I want you to know how to write a service and let the container handle it for you.
This post comes from a very cool evening with Jacopo Romei and David Funaro, two friends of mine, developers too.
A container?
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
application bundle, HelloBundle
, which exposes the route:
1
|
|
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:
1
|
|
Then we have to build an extension able to load the configuration for our service.
Inside src/Application/HelloBundle
we create a directory DependencyInjection
and create the HelloExtension
class:
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 serviceLoad
method
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:
1
|
|
Remember? If we wrote hello.obama
, we should have defined a obamaLoad
method
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 hello.xml
.
Then, it sets a parameter, for the service: it sets hello.service.mood
; true
if we have defined it in the configuration, false otherwise ( our situation ).
Ok, things will become clear watching at the hello.xml
, located in
src/Application/HelloBundle/Resources/config/hello.xml
:
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
%hello.service.mood%
.
Yes, that parameter comes from the HelloExtension
!
Remember?
1 2 3 |
|
So, here we are passing to the XML the parameter %hello.service.mood%
with
false
value.
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
src/Application/HelloBundle/Service/Hello.php
:
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
defined a __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:
1 2 |
|
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 HelloExtension
.
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 $mood
as 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.