Creating a Reusable (& Amazing) Symfony Bundle

2:21:06

What you'll be learning

Want to share some code between projects, or maybe with the whole world? Let's do it! By creating a Symfony bundle! In this tutorial, we'll learn about bundles, their super-powers, how to add services & routes and the best-practices to create the best bundle possible:

  • Anatomy of a Bundle
  • Bundles vs Libraries
  • Building a bundle inside your app
  • DependencyExtensions to add Services
  • Complex Service configuration: Definitions & compiler passes
  • Allowing config via a Configuration class
  • Private services
  • Routing & other Configuration
  • Creating a Recipe
  • Registering your bundle with Packagist
  • Handling Releases
  • README!

Not only will you be able to create your own bundle, but we'll learn a lot along the way about how all bundles in the Symfony world work!


Your Guides

Ryan Weaver

Buy Access

Questions? Conversation?

  • 2020-04-28 Diego Aguiar

    Hey Mark Holstein

    Sorry for my late reply. The autoconfigure and autowiring functionality have to be enabled per "services configuration" file, in other words, if you have more than one services.xml in your app, then you will have to add the configuration code that enables those features.

    You can find this info in the Symfony docs, you only have to find the topic you want to learn about. Another good place is at the Symfony Slack channel

    BTW, when you want to check all the config options of a bundle, you can use the bin/console debug:config command

    Cheers!

  • 2020-04-24 Mark Holstein

    I'm not sure, but I think, my project is autoconfigured.
    I have this not disabled.
    Or must I set this in my service.xml?

    Where can I read all this things?

  • 2020-04-24 Diego Aguiar

    That line tells to the Symfony Container to register your command class as a command service with the name setup:couchbaseBucket. Usually, you don't have to do that if you have enabled "autoconfigure" for your project.

  • 2020-04-24 Mark Holstein

    Ok.
    But why I do need this line in my service.xml additional to my service config?

    <tag name="console.command" command="setup:couchbaseBucket"/>

    Without this line my command does not appear in my command list.
    I only did find this by try and error. Nothing documented. :(

  • 2020-04-23 Diego Aguiar

    Hey Mark Holstein

    We don't cover that topic but it should be easy to do so. You just need to create the command, give it a name, and then in your services configuration file, you have to enable the autoconfigure and autowiring functionality for you command

    Cheers!

  • 2020-04-23 Mark Holstein

    Hi!
    How can I add a symfony console command via a bundle?
    Is there a good tutorial somewhere?

  • 2019-12-18 Victor Bocharsky

    Hey Rafael!

    Glad you for it working! And thank you a lot for sharing your solution - this might be useful for other users!

    FYI, I just wrapped your code inside "code" tags with a special "pre" tags that makes code look better :) So basically, you need to use both "pre" and "code" tags to format blocks of code :)

    Cheers!

  • 2019-12-17 Rafael Gil

    Hi Victor,

    thank you so much for your help, I actually got it working and just for reference these are the values I used:


    public function registerBundles()
    {
    return [
    new MyBundle(),
    new MonologBundle(),
    new FrameworkBundle()
    ];
    }

    And then, for FrameworkBundle, the only service that complains is the uri_signer for the secrets and I solved that like so:


    public function registerContainerConfiguration(LoaderInterface $loader)
    {
    $loader->load(function (ContainerBuilder $container) {
    $container->register('myservice', MyService::class);
    $container->loadFromExtension('myservice', $this->myBundleParams);

    $container->register('uri_signer', UriSigner::class);
    $container->loadFromExtension('framework', ['secret' => 'myrandomsecret']);
    });
    }
  • 2019-12-16 Victor Bocharsky

    Hey Rafael,

    Ah, ok! So, yes, you can mock the validator in case you want to write a unit tests for some piece of your code. But in case you want to add an integration or functional test - you would need to register it. I suppose it should be done the same way as you did for monolog service? :) How did you register it? Just do the same steps for validator. But there's no validator bundle, the integration of Validator component into Symfony app is made by FrameworkBundle, see "validation" section: https://symfony.com/doc/cur... . So, it looks like you need to configure FrameworkBundle (in particular "validation" option of it) the same way you did it for MonologBundle.

    I hope this helps!

    Cheers!

  • 2019-12-13 Rafael Gil

    Hi Victor, thank you so much for getting back to me. Yes you are correct, my bundle has a service that has the validator passed as DI.
    I'm booting up the kernel, loading and registering my bundle and monolog, when I call one of my services that has monolog with DI it works because I'm registering monolog's bundle along with mine for this test, but now for the service that uses the validator I get null instead of ValidatorInterface.

    My function looks like this


    public function testServiceWiring()
    {
    $kernel = new MyBundleKTestingKernel();
    $kernel->boot();
    $container = $kernel->getContainer();

    $myservice = $container->get('myserviceid');
    }

    I'm guessing I have to load the validator service somehow, but not sure where and how so it works when my service gets loaded.

  • 2019-12-13 Victor Bocharsky

    Hey Rafael,

    Let me clarify, somehow in your test the validator object that's passed as a dependency in your service you're testing is equal to null instead of a real object? Am I correct? But how do you instantiate it? Are you trying to get it from the DI container? And why don't you want to create it manually?

    Cheers!

  • 2019-12-12 Rafael Gil

    Diego Aguiar so now I have a similar issue with unit testing, I have an integration test similar to the one described in chapter 11 and one of my services has ValidatorInterface as DI, it is installed but it's null in the constructor for the tests, I think I have to register the bundle so it becomes available, but I don't think it's related to any bundle. Do you have any idea how I can make it available on my test with DI?

  • 2019-12-11 Rafael Gil

    That worked! Thank you so much.

  • 2019-12-10 Diego Aguiar

    Hey Rafael Gil

    You have to inject the log service by ID but you should make it optional in case no logger is installed - https://github.com/symfony/...

    Sometimes people also like to log to a specific "channel" - it gives users more flexibility to handle your logs in a different way. That's done with a tag https://github.com/symfony/...

    Cheers!

  • 2019-12-09 Rafael Gil

    Hi Guys, great work with these videos, they are very helpful. I'm just seem to be stuck on logging. How do I make my reusable bundle to log to the main application log stream? Do I have to autowire monolog to my services?

  • 2019-09-09 Vladimir Sadicov

    Hey Fire01

    Thank you for your feedback! We are very happy that you like it! Stay on tune!

    Cheers!

  • 2019-09-08 Fire01

    This is great tutorial for reusable my code, thanks...

  • 2019-08-06 Victor Bocharsky

    Hey Virginie,

    No problem! Thank you for your feedback! Glad it was useful for you ;)

    Cheers!

  • 2019-08-06 Virginie Burlot

    Hi Victor,
    Yeah, I worked a lot with SF since this comment, and I must say, it was kinda stupid.
    Thank you for answering me at that dark time. I now understand what this course is about and its usefulness. :)

  • 2019-04-08 Steve Johnson

    Thanks! That worked perfect.

  • 2019-04-05 Vladimir Sadicov

    hey @Steve Johnson

    I think you should look at this link https://symfony.com/doc/cur... it will be better to use this method to modify twig configuration from your custom bundle!

    Cheers!

  • 2019-04-04 Steve Johnson

    What method should be used to load global twig variables from a 4.2 symfony bundle?

    I would like to add some twig globals to my bundle using src/Resources/config/twig.yaml.

    Here is what my twig.yml file looks like:

    twig:
    globals:
    my_name: 'Jane Doe'

    In my DependencyInjection Extension file I include:

    $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    $loader->load('services.yaml');
    $loader->load('twig.yaml');

    I get the following error:

    There is no extension able to load the configuration for "twig" (in src/DependencyInjection/../Resources/config/twig.yaml).
    Looked for namespace "twig", found none

    I try from my services.yaml file

    imports:
    - { resource: twig.yaml }

    services:...

    I get the same error.

    Thanks!

  • 2018-11-20 weaverryan

    Hey Vinoth Kumar S!

    Ah, an excellent topic! And one that has a very simple answer:

    1) Put you template files in a Resources/views directory in your bundle - e.g. Resources/views/admin/index.html.twig
    2) When rendering, refer to them with a special "@BundleName" syntax... where BundleName is the name of your bundle, but without the last word Bundle. For example, if you want to render the above template from your SymfonyCastsHelloWorldBundle, you would use:


    return $this->render('@SymfonyCastsHelloWorld/admin/index.html.twig');

    That will work, and you will be able to override any templates in your project by following the normal "override mechanism" - https://symfony.com/doc/cur...

    I hope that helps!

    Cheers!

  • 2018-11-19 Vinoth Kumar S

    Hi! This tutorial is awesome to quickly setting up a custom bundle. It will be more helpful if you explained something about twig file rendering from the custom bundle.

  • 2018-04-12 weaverryan

    Hey Rafael!

    Bah! Unfortunately, that's the one thing that I did *not* cover in this tutorial.... in part because it's super tricky to record properly. But if you have any questions, let us know. My advice is this: your bundle may NOT need a recipe at all - many do not. You only need a recipe if your bundle requires some configuration or other files (e.g. the Twig recipe creates a templates/ directory). A recipe is basically "automating" the README. So if your README says "Do X, then create file Y", these are great things for the recipe :). And mostly, recipes are quite simple: you include files that you would like copied into the user's project.

    Cheers!

  • 2018-04-07 Rafael

    Hey, Is it going to cover how to create and publish sf flex recipe for this custom bundle? it would be nice!

  • 2018-04-06 Victor Bocharsky

    Hi Virginie,

    Really? I could find this course by "Symfony Bundle" keyword, see https://knpuniversity.com/s... . I wonder what keywords you searched for. Well, yes, Symfony 4 is bundle-less, but it means you should avoid creating bundles in the src/ folder of your project, but third-party bundles are still valid. And this screencast is not about creating project bundles but third-party bundles. In shorts, you create a bundle only when you need to share some code between projects. And this course probably will be in the Symfony 4 track because, well, we're using Symfony components v4.0 in this course. But most of the information we show in this course is valid for Symfony 3 as well, of course, if we're talking about sharable third-party bundles.

    Cheers!

  • 2018-04-06 Virginie Burlot

    Hi !
    I see that this course is currently in progress, and I wonder, will it be implemented into the SF3 or 4 Track ? I know that there are no more bundle into SF4, so, does it concern SF3 exclusively ?
    Also, I must say that I can't find this course into your searching tool. I only found it while going through the "Courses updates" through my profile.