gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
In the show controller, we're using two services: MarkdownParserInterface
- from a bundle we installed - and CacheInterface
from Symfony itself:
... lines 1 - 4 | |
use Knp\Bundle\MarkdownBundle\MarkdownParserInterface; | |
... lines 6 - 8 | |
use Symfony\Contracts\Cache\CacheInterface; | |
... lines 10 - 11 | |
class QuestionController extends AbstractController | |
{ | |
... lines 14 - 31 | |
public function show($slug, MarkdownParserInterface $markdownParser, CacheInterface $cache) | |
{ | |
... lines 34 - 49 | |
} | |
} |
And... this was pretty easy: add an argument with the right type-hint then... use the object!
But I'm starting to wonder how can I control the behavior of these services? Like, what if I want Symfony's cache service to store in Redis instead of on the filesystem? Or maybe there are some options that I can pass to the markdown parser service to control its features.
Let's dd($markdownParser)
- that's short for dump()
and die()
- to see what this object looks like:
... lines 1 - 11 | |
class QuestionController extends AbstractController | |
{ | |
... lines 14 - 31 | |
public function show($slug, MarkdownParserInterface $markdownParser, CacheInterface $cache) | |
{ | |
... lines 34 - 40 | |
$parsedQuestionText = $cache->get('markdown_'.md5($questionText), function() use ($questionText, $markdownParser) { | |
return $markdownParser->transformMarkdown($questionText); | |
}); | |
dd($markdownParser); | |
... lines 46 - 51 | |
} | |
} |
Move over and refresh. This is apparently an instance of some class called Max
. And... inside, there's a $features
property: it kind of looks like you can turn certain features on or off. Interesting.
If we did want to control one of these feature flags, we can't really do that right now. Why? Because we aren't responsible for creating this object: the bundle just gives it to us.
This is a super common problem: a bundle wants to give you a service... but you want some control over what options are passed to that object when it's instantiated. To handle this, each bundle allows you to pass configuration to it where you describe the different behavior that you want its services to have.
Let me show you exactly what I'm talking about. Open config/bundles.php
and copy the KnpMarkdownBundle
class name:
... lines 1 - 2 | |
return [ | |
... lines 4 - 11 | |
Knp\Bundle\MarkdownBundle\KnpMarkdownBundle::class => ['all' => true], | |
]; |
Now, close this file and find your terminal. We're going to run a special command that will tell us exactly what config we can pass to this bundle. Run:
php bin/console config:dump KnpMarkdownBundle
Boom! This dumps a bunch of example YAML that describes all the config that can be used to control the services in this bundle. Apparently, there's an option called parser which has an example value of markdown.parser.max
... whatever that means.
Go back to the bundle's documentation and search for parser
- better, search for parser:
. Here we go... it says that we can apparently set this parser
key to any of these 5 strings, which turn on or off different features. Copy the markdown.parser.light
value: let's see if we can change the config to this value.
Look back at the YAML example at the terminal. The way you configure a bundle is via YAML. Well, you can also use PHP or XML - but usually it's done via YAML. We just need a knp_markdown
key, a parser
key below that and service
below that. But what file should this live in?
Open up the config/packages/
directory. This is already full of files that are configuring other bundles. Create a file called knp_markdown.yaml
. Inside, say knp_markdown:
, enter, go in 4 spaces, then we need parser:
, go in 4 spaces again and set service
to markdown.parser.light
:
knp_markdown: | |
parser: | |
service: markdown.parser.light |
If you're wondering why I named this file knp_markdown.yaml
, I did that to match this first key. But actually... the filename doesn't matter! It's the knp_markdown
YAML key that tells Symfony to pass this config to that bundle. If we renamed this to i_love_harry_potter.yaml
, it would work exactly the same.
So... what did this change? Well, find your browser and refresh!
Ah! An error! That was a genuine Ryan typo... but I love it!
Unrecognized option
services
underknp_markdown.parser
. Did you meanservice
?
Why yes I did! Let me change that:
knp_markdown: | |
parser: | |
service: markdown.parser.light |
This is one of my favorite things about the bundle config system: it's validated. If you make a typo, it will tell you. That's awesome.
Refresh now. Woh! By changing that little config value, it changed the entire class of the service object!
The point is: bundles gives you services and every bundle gives you different configuration to help you control the behavior of those services. For example, find your terminal and run:
php bin/console config:dump FrameworkBundle
FrameworkBundle
is the main, core, Symfony bundle and it gives us the most foundational services, like the cache service. This dumps a huge list of config options: there's a lot here because this bundle provides many services.
Go Deeper!
You can also pass sub-level key, e.g. cache
as the second argument to reduce
the output:
php bin/console config:dump FrameworkBundle cache
Try it!
Of course, if you really needed to configure something, you'll probably Google and find the config you need. But how cool is it that you can run this command to see the full list of possible config? Let's try another one for TwigBundle, which we installed in the first course:
php bin/console config:dump TwigBundle
Hello Twig config! Apparently you can create a global Twig variable by adding a globals
key. Oh, and this command also works if you use the root key, like twig
, as the argument:
php bin/console config:dump twig
That's the exact same list.
Ok! We now know that every bundle gives us configuration that allows us to control its services.
But I'm curious about this service
config we used for knp_markdown
. The docs told us we could use this markdown.parser.light
value. But what is that string? Is it just some random string that the bundle decided to use for a "light" parser? Actually, that string has a bit more meaning. Let's talk about the massively important "service container" next.
Took a little while for this tip to work for me, I cleared the cache, and after it completed refreshed the page a number of times, but it still returned markdown.parser.max each time. When I calmed down and did nothing for moment (around 30 seconds or so) and then refreshed, it was using markdown.parser.light as expected. Thank you!
Hey Poputa,
Thanks for this tip! First of all, it depends in which Symfony env you're... in prod you have to clear the cache first to see any changes, but in dev it should not be necessary. Yeah, sometimes you have to do it in dev, especially when you use a virtual machine or Docker, I just noticed this a few times. So, in any weird situation it's always a good idea to try to clear the cache first. If it does not help - then look into it deeper.
Cheers!
Just incase anybody is as retarded as I am:
Running ./bin/console config:dump KnpMarkdownBundle
only dumps the <b>default</b> configuration for that service.
In the video, they validated that the config was updated to use markdown.parser.light
by adding dd($markdownParser)
and checking the browser to see which class is being used.
Edit: As Diego points out below, the two commands are:
symfony console debug:config KnpMarkdownBundle
(your current config)symfony console config:dump KnpMarkdownBundle
(the default config)
Hey Niclas H.
Lol - thank's for sharing it, you can also run bin/console dump:config
to check your current configuration
Cheers!
Why was this autowiring system invented?
We could just write use statement on top of the file and then inside of a method just instantiate manually an object we want and configure it how we want via arguments instead of config files?
I'm just wondering, because at first I didn't like this system, but I get used to it
Hey Phy!
Well, first of all, in Symfony services are created by Dependency Injection Container (DIC) that knows how to create them. And it create them only on request. I.e. if during the request the service was never been called from the container - it also was never created. Yes, you can instantiate services manually in your code, it would mean you need to pass all the required arguments there, including injection other services or passing some parameters... but why do it manually when DIC may do it for you? All you need to do - teach DIC how to create the service, and then in the code just call that service, that's it. Also, DIC controls that only one instance of the service is created during the request. It means that if you call the same service in a few separate spots of your code - you will get the exact same instance of the service in all those spots. Manually, it would be difficult for you to do this if you instantiate it manually, because sometimes it's difficult to pass the created instance to all the spots correctly without violation code quality.
I hope it clarify things for you now!
Cheers!
I am trying to create new bundle in symfony 5.3*. but i can't did it. because when i try to create a new bundle first of all i need generate:bundle command. but i could not find it inside bin/console.
bin/console generate:bundle command gave me this error
`There are no commands defined in the "generate" namespace.
You may be looking for a command provided by the "SensioGeneratorBundle" which is currently not installed. Try running "composer require sensio/generator-bundle `
".
then i try to install composer require sensio/generator-bundle. after this command it's gave me this error
`mono@mono:~/Projects/apptest$ composer require sensio/generator-bundle
Using version ^3.1 for sensio/generator-bundle
./composer.json has been updated
Running composer update sensio/generator-bundle
Loading composer repositories with package information
Restricting packages listed in "symfony/symfony" to "5.3.*"
Updating dependencies
Your requirements could not be resolved to an installable set of packages.
Problem 1
- sensio/generator-bundle[3.1.0, ..., v3.1.7] require symfony/framework-bundle ~2.7|~3.0 -> found symfony/framework-bundle[v2.7.0, ..., v2.8.52, v3.0.0, ..., v3.4.47] but it conflicts with your root composer.json require (5.3.*).
- Root composer.json requires sensio/generator-bundle ^3.1 -> satisfiable by sensio/generator-bundle[3.1.0, ..., v3.1.7].
Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
Installation failed, reverting ./composer.json and ./composer.lock to their original content.
`
so i can't find any right way to generate a new bundle. could you please give me any suggestion what can i do for create a new bundle in symfony 5.3* version. and also please tell me what wrong i am doing.
thank you
Hey Monoranjan,
Yes, unfortunately, there's no a command that would generate a bundle for you, today you're trying to create the bundle yourself. Just literally open any bundle you're using and steal some boilerplate code. The bundle's structure you can find here: https://symfony.com/doc/cur...
That sensio/generator-bundle is abandoned and does not maintain anymore, which means you can't use it for Symfony 4 / 5. Since Symfony 4 we get rid of splitting your project code into bundles, so only third-party bundles are left that are supposed to be reusable in more than one project and should be installed via Composer in vendor/ dir. So, in theory you need to create a new bundle very rare, that's why there's no generate command so far, and yes, it's kinda requires some experience to work with the bundles if you want to create a new one.
So, following our tutorial about creating reusable bundles: https://symfonycasts.com/sc... and the docs I linked above you should be able to create a bundle I think. If you get stuck somewhere on that tutorial - let us know in the comments below the video and we will try to help you.
I hope this helps!
Cheers!
What is the difference between ./bin/console config:dump [name]
and ./bin/console config:dump-reference [name]
? In the documents I see this alternative command popping up.
Edit: I just tested this command in my project, and it seems it is just an alias for the same thing.
Hey Robin,
Those are the exact same command :) Symfony console has a really cool feature when you can make sorter command names, so the original command name is "config:dump-reference", but you can make it shorter and type only "config:dump-ref", or even shorter like "config:dump", or go crazy and type: "conf:dump", or even "c:d" :)
So, literally, to call that "config:dump-reference" - you can just type "bin/console c:d" and if Symfony won't find more than one command that matches your short name - it will call it. But sometimes Symfony may find more than one command and then it will fail asking you to be more specific.
To be sure about the full command name that is called when you call a short version of it - you can add "--help" option, e.g. "bin/console config:dump --help" will show you that behind the scene it calls "config:dump-reference" command.
I hope this helps ;)
Cheers!
I have added the knp_markdown.yaml file within the config->packages directory and added the "service: markdown.parser.light" by following you. But It do nothing, even I do mistakes on "services" instead of "service".
Hey Md,
I see that clearing the cache helped you. I just curious if you use any virtualization tool like Docker, etc. Probably you loaded the website in prod mode instead? Are you sure you were in dev mode? Only in dev mode Symfony rebuilds the cache on every page reload, for prod you need to clear the cache to see changes.
Cheers!
Hey Md,
Yeah, then you have to clear the cache manually in prod to see changes. If you use Docker - even in dev mode it's always a good idea to clear the cache first to see if this helps, as filesystem is shared between your host machine and containers.
Cheers!
// composer.json
{
"require": {
"php": "^7.3.0 || ^8.0.0",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
"sensio/framework-extra-bundle": "^6.0", // v6.2.1
"sentry/sentry-symfony": "^4.0", // 4.0.3
"symfony/asset": "5.0.*", // v5.0.11
"symfony/console": "5.0.*", // v5.0.11
"symfony/debug-bundle": "5.0.*", // v5.0.11
"symfony/dotenv": "5.0.*", // v5.0.11
"symfony/flex": "^1.3.1", // v1.17.5
"symfony/framework-bundle": "5.0.*", // v5.0.11
"symfony/monolog-bundle": "^3.0", // v3.6.0
"symfony/profiler-pack": "*", // v1.0.5
"symfony/routing": "5.1.*", // v5.1.11
"symfony/twig-pack": "^1.0", // v1.0.1
"symfony/var-dumper": "5.0.*", // v5.0.11
"symfony/webpack-encore-bundle": "^1.7", // v1.8.0
"symfony/yaml": "5.0.*" // v5.0.11
},
"require-dev": {
"symfony/maker-bundle": "^1.15", // v1.23.0
"symfony/profiler-pack": "^1.0" // v1.0.5
}
}
I followed every single step and when I was die dumping the markdown object the parser was still set to max, I figured out it was a cache problem, so if you find yourself in the same spot with me run:
./bin/console cache:clear
and it should work