I want you to know how to write a service and let the container handle it for you.
Yes, a container: Symfony2 implements a dependency injection container able to load any service you need ( a service can be the DB connection, a Twitter WS, a mailer ) in the way you prefer.
Ever thought the
factories.yml of symfony 1.4 was evil? The DIC basically does
the same thing. But, the right way.
Why does a container is that great?
Because it lets you decide the behaviour of the framework.
Ever thought the
sfActions were crap and wanted to build your own C of the MVC
with symfony 1.4 in a simple way? A pain in the mess :)
With the DIC you are able to configure Symfony’s architecture.
Building your own service
I’ll show a really simple example.
To let the container manage your extension you simply need:
- a bundle
- an extension, able to load the cascading configuration of your service
- your service class(es)
If you are familiar with the Sf2 sandbox you know it comes bundled with a simple
HelloBundle, which exposes the route:
and renders a template saying
hello to the name:
We will add the mood of our application to that page ;–)
First of all we need to tell Sf2 that we want to enable our service:
Then we have to build an extension able to load the configuration for our service.
src/Application/HelloBundle we create a directory
and create the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
If you take a closer look to the
1 2 3 4 5 6 7 8 9
you’ll notice that it accepts, as parameters, the configuration ( yes, the YML
configuration, the one we left untouched with the
~ symbol ) and the container.
Why does our extension calls the
serviceLoad method? That comes from the YAML
configuration done before:
Remember? If we wrote
hello.obama, we should have defined a
in our extension.
Then it creates an
XMLFileLoader and loads the configuration of our services,
which lies in the
Resources/config folder, an XML file called
Then, it sets a parameter, for the service: it sets
if we have defined it in the configuration, false otherwise ( our situation ).
Ok, things will become clear watching at the
hello.xml, located in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
As you see, it defines a service (
hello_service ), which istantiates the class
%hello.service.class%, a parameter defined some lines above, with the argument
Yes, that parameter comes from the
1 2 3
So, here we are passing to the XML the parameter
Ok, we are close to the end, what’s missing there? Oh, our service!
In the XML we stated that the class of the
hello_service service should be
Application\HelloBundle\Service\Hello, so we only need to create it under
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
as you see, the mood is passed by the DIC in the constructor*, and we have
__toString returning 2 different strings based on the value of the mood.
Ok, we’re done.
Open the dummy front controller bundled with the sandbox and pass a second argument to the template:
1 2 3 4 5 6 7 8
then edit the twig template:
File /src/source/downloads/code/[src/Application/HelloBundle/Resource/views/Hello/index.twig] could not be found
So, let’s see it in action:
Now we can edit the service configuration:
and see what happens:
“Oh shit”… A bit lost? Here’s a recap!
Ok, let’s try to explain things again!
In the configuration of you application (
app/config/config_dev.yml ) you add
to your application a new service (
hello.service ), with no parameters.
Then, when in the application you call the service
hello_service, the DIC
looks for an extension able to load the service, which is
It runs the method serviceLoad, which looks to an XML describing the service
passing it the parameters you defined in the YAML configuration ( none ).
Then the DIC instantiate the service class with the parameters mapped in the XML
$mood = false ).
The second time, we have defined
true, so the container instantiates
the class with a really simple:
1 2 3
the result is that you get an instance of your service configured as you want.