On 3/20/10 2:18 PM, chrisk wrote:
### Inject services in each controller
Just to exaggerate: If we pass everything as parameters, our
controllers can be plain php functions again!
I think it's good to pass the really dynamic parameters (from the
route) as method parameters (no need to access the $request var as in
symfony 1.x), but things like parameters/services, which are somewhat
static at runtime, should be properties of the controller.
My point is that if you need to pass too many arguments to an action, it
probably means that your controller is trying to do too many things. So,
I'm quite comfortable with that problem, as it will remember you it's
not a good idea to inject so many things.
So Nicolas has also shown a lot of examples to pass the services in an
array with their names as keys. I think this is just a lightweight
version of the service container, because the container supports array
access you could pass it instead of the array in production env. I'll
come back to this later on.
How I see it there are two main problems: declaring dependencies on
services/parameters and accessing them in an unverbose/short way.
To declare the dependencies I think the injection into constructor
approach is the cleanest way, but it requires boilerplate code. So
here are some of my ideas how to circumvent the the boiler plate code
or at least the need to write it by hand:
#1. Solution:
Use code generation to create the boilerplate code (specify the
service names when calling generate:module). I think the worst
solution, some problems I see:
- how to add additional dependencies later on,
- manage regeneration,
- developer has to use CLI to create new controller,
- ...
I agree it's not a good idea at all ;)
#2. Solution:
Use annotations. The protected properties can be tagged with
annotations so it is clear what has to be injected and the variable
name can be different from the service name. The problem I see:
- php developers aren't used to annotations
- it isn't a native language feature
There are some libraries to support annotations (http://
code.google.com/p/addendum/ , lime2 also uses annotations)
Besides the problems you have already pointed, it will be slow or means
we need to generate the "real" controller class in the cache. Not what
we want.
#3. Solution:
Lightweight service container: You can change the contract of the
controller constructor to: pass an array/ArrayAccess object, which can
be used to access the services/parameters. So you can pass an array in
your tests and a service container at runtime.
At runtime:
$controller = new ArticleController($container);
In your tests:
$controller = new ArticleController(array(
'user' => new UserMock(),
));
The service container can maintain service references until you really
access a service. This solves the problem that only the services you
need are created.
Getting a service is just an array access.
$this->services['user']->setAttribute(...);
That's exactly what we already have right now. The Container class
already implements ArrayAccess. So, replace "services" with "container"
and that how it already work in PR1.
#4. Solution:
Use the dependency injection component to configure the controller. So
the controller becomes a service itself. The problem might be that the
configuration is split
over multiple files so it isn't obvious what is injected into the
controller. Maybe it also requires boilerplate code, because I don't
know atm if the di component supports direct property injection
(sorry).
Not really possible. The container can only create "global" objects...
or you need to create the configuration for every controller class,
which seems unpractical. I don't want to create an XML/YAML file for
each controller.
All of these solutions will make the service accessible as properties
of the controller or through an array.
One last concern: the solutions #2, #4 and your proposal "Inject
services as protected properties" will make testing harder, because
you have to create and use the "injector"/"service container" to setup
the controller.
I hope this post has some value for the discussion and I didn't
oversee something important.
Thanks for your feedback.
Fabien
Christian Kerl
--
If you want to report a vulnerability issue on symfony, please send it to
security at symfony-project.com
You received this message because you are subscribed to the Google
Groups "symfony developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/symfony-devs?hl=en
To unsubscribe from this group, send email to symfony-devs+unsubscribegooglegroups.com or
reply to this email with the words "REMOVE ME" as the subject.