ramblings on PHP, SQL, the web, politics, ultimate frisbee and what else is on in my life
back

Symfony2 stuff

Since about 4 weeks I have really started using Symfony2, in development for a work project no less. Kinda crazy seeing its still in pre-alpha phase, but I think its a great platform today and I know its going to be the best soon aka once we have a stable release. But in these 4 weeks quite a few things have popped up that I like to see addressed. Most things aren't really about writing code, but figuring out how things should be. The kind of stuff that is hard to fix on your own. At the same time there are not yet that many people to collaborate with, so I think I will have to accept that not all things will get an answer right here, right now. Also a lot of it is pondering best practices, aka documentation. To keep an overview I figured I should make a little list, since right now I just have a ton of flagged emails. Also I might entice some people to follow up on stuff on my list at the same time.

1. Making 3rd party controllers truly reusable

This is what I last blogged about. Since then a couple of things have been fixed and I think we are starting to figure out a good solution for the last. The main issue I see left is that a direct mapping of a service name in a controller to a single service doesn't quite do the trick. For example if a controller is supposed to generate output for a specific format I need to potentially replace the default "templating" and "response" services. But if that some controller is supposed to handle multiple output formats things will get tricky. I either have to create a "templating" and "response" service implementation that can do them all, or I need to have a meta service that then makes instances of the right one dynamically. It gets messy and the risk is great that everybody will come up with their own approach. The current idea to solve this is by making it possible to switch the actual service for the DIC to load based on a "context" which can be defined inside the route (and I guess also the constructor of a controller).

2. Flash message handling

Here I am still fairly lost what the best approach would be. Basically I don't really like that flash messages seem to be set inside the controller. Also if they are set there, I think they should not really contain normal text, but more a "key". But I guess this is the same for all translations. The good news is that this is supported by the Symfony2 translation system, aka the keys used in the translation system do not need to represent a "real" language translation. That being said flash messages may at times also need parameters, which makes it a bit tricky to separate the setting of the flash message and the actual use of the flash message inside a template. Finally right now it seems many Bundle's include outputting flash messages inside specific templates, but I actually think that in many cases you would want to output flash messages in a fixed location inside the layout template.

3. Easy DIC customization of 3rd party Bundles

Another thing I am still fuzzy on. I noticed that the DoctrineBundle does a lot of work inside the Extension class to setup the DIC configuration. This makes it quite tedious to extend. For example I was pondering adding a "beginTransaction()" call after creating the DBAL connection inside my functional tests, so that I would not have to clean the database after each test. But the way things are now I cannot do this in XML or YAML. I actually have to extend the Extension class itself, which doesn't seem right.

4. Issues with setting GET parameters in functional tests as well as forward() calls

I tried debugging this issue with MacGDBp.app, but it doesn't allow inspection of nested objects so I never got anywhere. The issue is that when I do something like the following the GET parameter gets parsed but lost somewhere along the lines:


<?php
$client = $this->createClient(array('environment' =>   'test'));
$client->request('GET', '/foo?ding=dong');
$this->assertContains('dong, $client->getResponse()->getContent());
?>

Similary the following doesn't work either:


<?php
$query = array('ding' => 'dong');
$response = $this->controller_resolver->forward('fooController', array(), $query);
?>

In either case the GET parameter never becomes accessible inside the called controller.

5. Form validation issues

I haven't tried to dive into the source code here. But using the UserForm bundled with DoctrineUserBundle we get some weird issues in the validation. First up if we just submit the form without entering anything. We get the same validation error messages multiple times on the email. Exactly as often as we have validation rules. Furthermore we never get any validation errors on the password field.


<?php
abstract class User
{
    /**
     * @validation:Validation({
     *      @validation:Email(),
     *      @validation:NotBlank(),
     *      @validation:MaxLength(limit=255)
     * })
     * @var string
     */
    protected $email;

    /**
     * @validation:Validation({
     *      @validation:NotBlank(),
     *      @validation:MinLength(limit=2),
     *      @validation:MaxLength(limit=255)
     * })
     * @var string
     */
    protected $password;}
?>

The issue can be seen in this screenshot.

6. Aligning the handling for Bundle configuration

The Symfony2 DIC system already supports parameters, which is a create way to make default service configurable. However the syntax is a bit verbose. Since in order to enable a Bundle it needs to be added to the config it has become a best practice to provide short hand config options for most of the key parameters used in the Bundle. However Bundles with a lot of parameters tend not to cover all of them, which means you end up having to code up configuration options differently for the same Bundle. Jordi cooked up a patch to make it easier to support essentially all configuration options with little code, which has since been applied to DoctrineUserBundle. However there remains one big question, how to handle null values. If null values are ignored as the previously linked patch defined, then it is impossible to override a default value for a parameter with null. Right now I cannot think of a use case for this anyway, but who knows? The upside of ignoring null values is that one can easily list all possible options without overriding.