MakerBundle
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeFor our last trick, I want to introduce a bundle that's going to make our life awesome. And, for the first time, we are going to hook into Symfony.
Installing Maker Bundle
First, find your terminal, and install that bundle:
composer require "maker:^1.35" --dev
Yep! That's a Flex alias for symfony/maker-bundle
. And, in this case, "make" means - "make your life easier by generating code".
We know that the main purpose of a bundle is to give us services. And, that's true in this case too... but the purpose of these services isn't for us to use them directly, like in our controller. Nope, the purpose of these services is that they give us new bin/console
commands:
php bin/console
Nice! About 10 new commands, capable of generating all kinds of things. And, more make commands are still being added.
Generating a new Command
So... let's try one! Let's use the MakerBundle to create our very own, custom bin/console
command. Use:
php bin/console make:command
This will ask us for a command name - how about article:stats
- we'll create a command that will return some stats about an article. And... it's done! We now have a shiny new src/Command/ArticleStatsCommand.php
file. Open it!
// ... lines 1 - 2 | |
namespace App\Command; | |
use Symfony\Component\Console\Command\Command; | |
use Symfony\Component\Console\Input\InputArgument; | |
use Symfony\Component\Console\Input\InputInterface; | |
use Symfony\Component\Console\Input\InputOption; | |
use Symfony\Component\Console\Output\OutputInterface; | |
use Symfony\Component\Console\Style\SymfonyStyle; | |
class ArticleStatsCommand extends Command | |
{ | |
protected static $defaultName = 'article:stats'; | |
protected function configure() | |
{ | |
$this | |
->setDescription('Add a short description for your command') | |
->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description') | |
->addOption('option1', null, InputOption::VALUE_NONE, 'Option description') | |
; | |
} | |
protected function execute(InputInterface $input, OutputInterface $output) | |
{ | |
$io = new SymfonyStyle($input, $output); | |
$argument = $input->getArgument('arg1'); | |
if ($input->getOption('option1')) { | |
// ... | |
} | |
$io->success('You have a new command! Now make it your own! Pass --help to see your options.'); | |
} | |
} |
Hey! It even added some example code to get us started! Run:
php bin/console
And on top... yes! Symfony already sees our new article:stats
command. Sweet! Um... so... let's try it!
php bin/console article:stats
It doesn't do much... yet - but it's already working.
Service autoconfigure
But... how does Symfony already know about this new command? I mean, is it scanning all of our files looking for command classes? Actually, no! And that's a good thing - that would be super slow!
Here's the answer. Remember: all of our classes in src/
are loaded as services:
// ... lines 1 - 5 | |
services: | |
// ... lines 7 - 22 | |
# makes classes in src/ available to be used as services | |
# this creates a service per class whose id is the fully-qualified class name | |
App\: | |
resource: '../src/*' | |
exclude: '../src/{Entity,Migrations,Tests}' | |
// ... lines 28 - 37 |
Notice that our new class extends Symfony's base Command
class:
// ... lines 1 - 4 | |
use Symfony\Component\Console\Command\Command; | |
// ... lines 6 - 11 | |
class ArticleStatsCommand extends Command | |
// ... lines 13 - 35 | |
} |
When the service was registered, Symfony noticed this and made sure that it included it as a command. This nice feature has a name - autoconfigure
. It's not too important, but just like autowiring, this is activated thanks to a little bit of config in our services.yaml
file:
// ... lines 1 - 5 | |
services: | |
# default configuration for services in *this* file | |
_defaults: | |
// ... line 9 | |
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. | |
// ... lines 11 - 37 |
It's just another way that you can avoid configuration, and keep working!
Next, let's have fun and make our command much more awesome!
Getting this error:
"Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires symfony/maker-bundle ^1.43 -> satisfiable by symfony/maker-bundle[v1.43.0].
- symfony/maker-bundle v1.43.0 requires symfony/config ^5.4.7|^6.0 -> found symfony/config[v5.4.7, v5.4.8, v5.4.9, v6.0.0, ..., v6.1.0] but the package is fixed to v4.4.41 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
You can also try re-running composer require with an explicit version constraint, e.g. "composer require symfony/maker-bundle:*" to figure out if any version is installable, or "composer require symfony/maker-bundle:^2.1" if you know which you need.
Installation failed, reverting ./composer.json and ./composer.lock to their original content."