<[email protected]> wrote:
> This RFC discusses the possible enhancements to the current controller
> implementation in Symfony 2. Feel free to give your opinion.

Okay, that's my first contribution to this mailing list. So this post
might not be the right point to start, but I'll risk it.
How I build up my post: first I'd like to comment Fabien's and
Nicolas' ideas and at the end state my own ideas.

First of all I agree with the points you, Fabien, made up about
verbosity and testability in "How does controllers work in PR1? ".

>### Inject the needed services in the constructor
....
>Problem: The constructor need all services needed by all methods, which is
> not a good idea (we will create too many services most of the time)

You'll have the same problem when using the "Inject services as
protected properties" approach. Furthermore I think service creation
shouldn't be a very expensive task.

>  $this->__user__->setAttribute(...); // <-- __x__ convention could be
> replaced, of course

> protected $__requirements__ = array('user', 'doctrineManager');
>

The usage of special variables with __X__ looks like a lot of magic
and isn't Symfony 2 about leaving the magic behind?!
But I agree that the controller should explicitly declare its
dependencies (see details at the end).

> > ### Inject services as protected properties
> ...
> Nightmares expected, don't do this.

I definitely agree! Don't do it.

> ### 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.

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,
- ...

#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)

#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(...);

#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).

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.

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.

Reply via email to