Sorry if this has already come up earlier in the thread, but I just realized I
sometimes have multiple routes that point to the same symfony 1 action. Will
this be possible Symfony 2, or is it required that route and action parameters
match exactly?
For example, I might have two distinct routes, homepage and category, that both
point to an action that lists blog articles. I would assume I could direct each
of these routes to this Symfony 2 action:
public function listArticles($category = null)
{
}
Will it be possible to point a route that doesn't have a category parameter at
this action?
Thanks,
Kris
--
Kris Wallsmith | Release Manager
[email protected]
Portland, Oregon USA
http://twitter.com/kriswallsmith
On Mar 30, 2010, at 1:24 AM, Fabien Potencier wrote:
> Hi all,
>
> Last week, I took the time to play with the implementation of the main
> approaches discussed in the controllers RFC. I also wrote some unit tests to
> see how it feels. During this journey, I discovered that writing a RFC
> without any implementation is quite difficult (my apologizes for this). But I
> learned a lot, and discovered that some approaches look rather impractical in
> real-world scenarios.
>
> This email is an attempt to explain my findings and my concerns about some
> approaches and why they are not as good as they seem to be in the RFC. If you
> don't want to read the whole email, which is quite long, let me give you the
> main conclusions right away:
>
> * For the common cases, the controller needs the Container object (if not,
> you loose a lot of shortcuts provided by the Controller base class, or you
> are forced to inject a lot of services you don't need because they are used
> by the parent class methods);
>
> * Approach 1 (yes, the one currently implemented) is the best implementation
> (simple, fast, easy);
>
> * If you like to have the Request object in the controller signatures instead
> of just the routing variables, then Approach 1, where we change the
> controller method arguments to just the Request objet, is also a working
> approach (see my previous email to understand why I think it is a less
> attractive approach);
>
> * Other approaches are not exciting anymore as the Container should be
> injected at some point. So, injecting services in the controller constructor
> or methods is just a convenient shortcut, nothing more.
>
> Now, for the longer story.
>
> My initial point of view was to be able to test a controller as any other
> method; just by calling it and checking the result. That's possible for
> simple controllers like the following one:
>
> public function showAction($name)
> {
> return new Response('Hello '.$name);
> }
>
> If you like to have the Request object injected, here is the equivalent:
>
> public function showAction(Request $request)
> {
> return new Response('Hello '.$request->getPathParameter('name'));
> }
>
> With such a controller, writing a unit test is straightforward:
>
> class HelloControllerTest extends \PHPUnit_Framework_TestCase
> {
> public function testShowAction()
> {
> $container = new Container();
> $controller = new HelloController($container);
>
> $response = $controller->indexAction('Fabien');
>
> $this->assertRegexp('/Hello/', $response->getContent());
> }
> }
>
> The controller only relies on the request, and as such, if you use some
> approaches where you inject services manually, it will still be easy (or even
> easier to test as we remove the need for the container):
>
> class HelloControllerTest extends \PHPUnit_Framework_TestCase
> {
> public function testShowAction()
> {
> $request = new Request();
> $request->setPathParameters(array('name' => 'Fabien'));
>
> $container = new Container();
> $controller = new HelloController($container);
>
> $controller = new HelloController($container);
>
> $response = $controller->indexAction($request);
>
> $this->assertRegexp('/Hello/', $response->getContent());
> }
> }
>
> Also, if you need a database connection to do your job, it's still easy
> enough:
>
> public function showAction(Request $request, DatabaseConnection $conn)
> {
> // do something with the $conn
>
> return new Response('Hello '.$request->getPathParameter('name'));
> }
>
> In such cases, testing is also still easy:
>
> class HelloControllerTest extends \PHPUnit_Framework_TestCase
> {
> public function testShowAction()
> {
> $request = new Request();
> $request->setPathParameters(array('name' => 'Fabien'));
> $conn = new DatabaseConnection(...);
>
> $controller = new HelloController();
>
> $response = $controller->indexAction($request, $conn);
>
> $this->assertRegexp('/Hello/', $response->getContent());
> }
> }
>
> But easiness stops here. As soon as you write "richer" controllers, problems
> comes very fast. The main problem is with "hidden" dependencies. Consider the
> following example:
>
> public function indexAction()
> {
> return $this->render('BlogBundle:Post:index');
> }
>
> Behind the scene, the `render()` method needs the `templating` service; no
> big deal. And if you want to forward to another action, you need the
> `controller_loader` service. That's easy enough, even if it feels a bit magic
> as the end user controller does not really use the service directly:
>
> public function __construct($templating)
> {
> $this->templating = $templating;
> }
>
> public function indexAction()
> {
> return $this->render('BlogBundle:Post:index');
> }
>
> But when it comes to testing, things are much more complex. Because the
> templating needs a loader, helpers, and some more services. So, re-creating
> the dependency graph (with mock objects or not) is a more difficult. At this
> point, you will probably just use the container in your test to create the
> dependencies automatically (with a special configuration for the test
> environment of course).
>
> For this reason, and after having played with all approaches and their
> corresponding unit tests, I think that a controller needs the full container
> object. With this in mind, testing becomes easy again no matter what:
>
> public function setUp()
> {
> $kernel = new \BlogKernel('dev', true);
> $kernel->boot();
>
> $this->container = $kernel->getContainer();
> }
>
> public function testIndexAction()
> {
> $controller = new PostController($this->container);
> $response = $controller->indexAction();
>
> $this->assertRegexp('/Hello/', $response->getContent());
> }
>
> Of course, the boilerplate code can be abstracted in a sub-class of the
> PHPUnit Test Case class.
>
> That works for most controllers. And if you want to do "functional" tests,
> it's as easy as unit tests, as you can just ask the request handler to handle
> the request for you.
>
> public function setUp()
> {
> $this->kernel = new \BlogKernel('dev', true);
> $this->kernel->boot();
> }
>
> public function testIndexAction()
> {
> $request = new Request($get, $post, $...);
> $response = $this->kernel->handle($request);
>
> $this->assertRegexp('/Archives/', $response->getContent());
> }
>
> As before, we will provide a sub-class of Test Case to abstract the
> boilerplate code.
>
> Sorry for the very long post but the controller implementation is at the
> heart of an MVC framework and as such the final decision about which approach
> to use should be taken carefully.
>
> As always all comments are very welcome.
>
> Fabien
>
> --
> Fabien Potencier
> Sensio CEO - symfony lead developer
> sensiolabs.com | symfony-project.org | fabien.potencier.org
> Tél: +33 1 40 99 80 80
>
> --
> 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.
--
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.