This tutorial has a new version, check it out!


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.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

For 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 --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()
->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
... 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
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
# default configuration for services in *this* file
... 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!

Leave a comment!

  • 2020-05-08 Gaetano Sottile

    ok, now I understand better. Inside the function execute of my articlestatscommand I inject ArticleRepository and I call my Articlerepository method .
    This is my function inside ArticleRepository:

    public function getHeartNumberBySlug($slug) {
    $article = $this->findOneBy(['slug' => $slug]);
    return 'No article found';
    return $article->getHeartCount();

    Thanks for your help.

  • 2020-05-08 Diego Aguiar

    That's not bad but I have a couple of tips :)

    1) Since Symfony4 you can inject Repositories, you don't have to get them through the EntityManager (Although you still can)
    2) You need to check that the $article was found, in other words, it's not null because you are fetching by slug field, it may not exist


  • 2020-05-07 Diego Aguiar

    Hey Gaetano Sottile

    You can create an EntityRepository that will encapsulate the query logic for fetching the total hearts. Then in a controller you can just inject that repository and use it. Or, if you want to have a layer between your repositories and controllers, then you can create a service class that will call the repository for you


  • 2020-05-07 Gaetano Sottile

    Hello again :),
    what do yo think about this way?
    And then I inject this service in ArticleStatsCommand.

    Thanks a lot for your advice.

    namespace App\Service;

    use App\Entity\Article;
    use Doctrine\ORM\EntityManagerInterface;

    class HeartHelper
    * @var EntityManagerInterface
    private $entityManager;

    * HeartHelper constructor.
    * @param EntityManagerInterface $entityManager
    public function __construct(EntityManagerInterface $entityManager)
    $this->entityManager = $entityManager;

    public function getHeartNumber(string $slug) {
    $article = $this->entityManager->getRepository(Article::class)->findOneBy(['slug' => $slug]);
    return $article->getHeartCount();

  • 2020-05-07 Gaetano Sottile


    before starting the Forms course I would like to understand how to get hearts with the best practise 'Getting Services from the Service Container'.
    I suppose that I have to create a service in directory service and then using EntityManagerInterface to get hearts number. Is this the right way?
    Thanks for your help.

  • 2019-03-15 Vladimir Sadicov

    Hey stereomaik

    Thanks for the good words! I'm appreciate that you liked CRUD generator.

    BTW I always wondered if someone use it :p


  • 2019-03-15 Victor Bocharsky

    Hey stereomaik ,

    I think it's just more matter of habit, if you get used to something, other workflows may seem weird at the first sight, though I have never used CakePHP so it's difficult to compare for me :) Anyway, Symfony is getting much more thin with the new Symfony Flex, that's a crazy cool. ;)


  • 2019-03-14 stereomaik

    CRUD generator IS one of the CakePHP's amazing superpowers Symfony lacked. To be completely honest, it is still difficult to say goodbye to CakePHP, as it is soooooo intuitive thanks to the convention over configuration approach, like not having to call neither the entity manager nor the template but still having them was amazing.

    Having said that, Symfony feels much less like a great toy but more like a mature tool which makes it a go-to choice as the projects become more advanced. In short, I absolutely love Symfony, but leaving CakePHP does feel a lot like an actual break-up. And getting options such as CRUD generator just makes the transition easier. So while it is not the deal-breaker, it helps to get in Symfony what I had in Cake (aside from the Symfony-specific features like autowiring which is CRAZY in a good way).

    Also, a shout out to Vladimir - you are the man!

  • 2019-03-14 Victor Bocharsky

    Hey stereomaik ,

    Yay, our friend Vladimir contributed that!

    But did you wait only for CRUD generator so far before saying goodbye to CakePHP? It looks like the most wanted feature for you :p


  • 2019-03-13 stereomaik

    As I am watching it, the maker can now create the entire CRUD for Doctrine Entity. Time to say goodbye to CakePHP.

  • 2019-03-11 Victor Bocharsky

    Hey Mika,

    Yes, Ryan just missed it. We totally should install Maker for dev only... and we've already fixed it in scripts and added a note in the video.


  • 2019-03-09 Mike

    Wouldn't it make sense to install maker bundle via --dev flag? Because we only need to create files with make: in dev env?

  • 2018-05-31 Victor Bocharsky

    Yeah, probably so. Not sure what can you do then, probably that PowerShell ISE has some kind of configuration where this can be fixed, do not know :/

  • 2018-05-30 Raymond Dube

    I'm honestly not sure if this is a problem wiht MakerBundle, or with PowerShell ISE. I'm more inclined to blame ISE as it is working fine in a standalone PowerShell window

  • 2018-05-30 Victor Bocharsky

    Hey Raymond,

    Thanks for this notice. I personally haven't heard about this problem before. It makes sense to upgrade to the latest version of MakerBundle. If you still have this issue, feel free to open a bug in its repo with detailed steps to reproduce.


  • 2018-05-29 Raymond Dube

    A quick note for those who may be using Windows10 PowerShell ISE.

    For whatver reason, it appears, at least on my system, that while in the ISE,the make:command doesn't execute properly and leaves you hanging at the "Choose a command name (e.g. app:some-thing):" prompt without allowing you to enter the command name.

    The good news, if you use the standalone PowerShell, this is not an issue.