Archives


Master Symfony2 fundamentals

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Discover the SensioLabs Support

Access to the SensioLabs Competency Center for an exclusive and tailor-made support on Symfony
sensiolabs.com

Fabien Potencier
Symfony2: Annotations get better
by Fabien Potencier – May 23, 2011 – 15 comments

Later today, I will release Symfony2 beta2. But first, I wanted to talk about a big change that landed into master yesterday. As you might know, Symfony2 uses annotations for Doctrine mapping information and validation configuration. Of course, it is entirely optional, and the same can be done with XML, YAML, or even PHP. But using annotations is convenient and allows you to define everything in the same file.

Symfony Standard Edition provides an even better support for annotations via two additional bundles: SensioFrameworkExtraBundle and JMSSecurityExtraBundle. They allow you to use annotations for controller configuration (routing, cache, security, template, ...).

To avoid ambiguities when different libraries/bundles define new annotations, you were required to use a configurable "prefix":

/**
 * @orm:Entity
 */
class User
{
    /**
     * @orm:Column(type="string", nullable=false)
     * @assert:NotBlank
     */
    private $name;
}

But several problems arose quite fast:

  • If you have a look at the Doctrine documentation, you will see that @Column is used instead of @orm:Column. That's because the prefix is optional. So, the Doctrine documentation does not use one, but Symfony2 forces you to use orm. Note that it is configurable, so you might use any other prefix (@doctrine:Column).

  • The annotation library did not play well with autoloading.

  • SensioFrameworkExtraBundle and JMSSecurityExtraBundle shared the same extra prefix, but it was a hack and it was not really scalable.

Johannes worked hard in the last few weeks to find an elegant solution to this problem. As each annotation is defined as a class, instead of using only the short class name, we have decided to use the fully qualified class name. It removes the need for arbitrary prefixes defined as a global configuration, avoids any ambiguities between libraries, and gets rid of the autoloading issue altogether:

/**
 * @Doctrine\ORM\Mapping\Entity
 */
class User
{
    /**
     * @Doctrine\ORM\Mapping\Column(type="string", nullable=false)
     * @Symfony\Component\Validator\Constraints\NotBlank
     */
    private $name;
}

Of course, using the FQCN everywhere is quite verbose but fortunately, PHP already has a solution via the use statement:

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 */
class User
{
    /**
     * @ORM\Column(type="string", nullable=false)
     * @Assert\NotBlank
     */
    private $name;
}

Annotations now feel more "native". If you want to use annotations outside of a Symfony2 context, have a look at the Doctrine Common repository (version 3.0).

Comments RSS

  • gravatar
    #1 Lukas said on the 2011/05/23 at 08:10
    Just to make it clear, this means that Symfony2 stable will come with Doctrine Common 3.x which is scheduled to be released end of June.
  • gravatar
    #2 Volker said on the 2011/05/23 at 08:25
    It's a little more code to write (and to remember!) but I see that this is necessary in the "big picture". Thanks for your hard work, I really begin to enjoy Symfony2 and I'm looking forward for the final release.
  • gravatar
    #3 François Zaninotto said on the 2011/05/23 at 08:43
    It's both easy and configurable. Great job, Johannes!
  • gravatar
    #4 Andy said on the 2011/05/23 at 08:58
    Can't help but feel there is a Lot more typing in SF2...

    And still no default= option?!
  • gravatar
    #5 Kuba said on the 2011/05/23 at 09:13
    Someone pointed me out that special characters in tag names might be and issue for DocBlock parsers.

    Someone tried generating a documentation with such annotations included?
  • gravatar
    #6 beberlei said on the 2011/05/23 at 09:52
    We will port this back to Doctrine 2.1 aswell, we already have a working implementation that has this features and is backwards compatible (i.e. allows to set @alias: aswell).

    We havent discussed finally what features become deprecated and which will make the step to 3.0
  • gravatar
    #7 Marijn Huizendveld said on the 2011/05/23 at 10:14
    Totally awesome! Great work Johannes
  • gravatar
    #8 Jon Busby said on the 2011/05/23 at 10:24
    Looks great..

    Although I've saw its now called 'Symfony Standard Edition'.

    Please please please please please tell me that symfony isn't going to have a 'standard' and 'premium' edition...
  • gravatar
    #9 Mike van Riel said on the 2011/05/23 at 10:25
    The changes above can have influence on applications which parse DocBlocks as tag names are commonly defined as being alphanumeric.

    I'd expect that parsers can adapt (except for perhaps the older ones) but a detailed specification of the new format is necessary. I know I wouldn't mind adapting DocBlox but I'd need the spec.

    The format above also conflicts with efforts in Internals where a different format is proposed for a similar functionality. Perhaps you and Guillhermo can work together to come to a single standard?
  • gravatar
    #10 Javier said on the 2011/05/23 at 10:31
    I really like this and It improves the understanding of what is going on under the hood. Great job!
  • gravatar
    #11 Johannes said on the 2011/05/23 at 10:44
    @Mike, Guilherme was also involved in the process of updating Doctrine Common to this new approach. We basically follow the EBNF that is detailed in Guilherme's first RFC with the exception that we do not use "<>" but "@" to mark annotations (https://wiki.php.net/rfc/annotations).
  • gravatar
    #12 Mike van Riel said on the 2011/05/23 at 10:55
    @Johannes: Guillhermo has written a new RFC (https://wiki.php.net/rfc/annotations-in-docblock) which differs from the format presented above.

    For one it does not mention the use of non-alphanumeric character as tag names.

    And additionally it present that content in the 'description' section of the tag; whilst the above code shows no space between the @tagname and the (content). This does not help when generating documentation as a tag is no longer an identifier but now has contextual meaning and thus countless variations.
  • gravatar
    #13 Lukas said on the 2011/05/23 at 11:29
    @Jon Busby: there will not be a "premium" edition in case you are worried about a close source commercial edition. The purpose of the editions is to convey the idea that you can have many versions of the framework.

    For example there could be a "Rest Server Edition" or a "CMF Edition" that come preconfigured with relevant Bundles, libs and settings.
  • gravatar
    #14 Anthony Servedio said on the 2011/05/23 at 15:06
    Namespaced annotations,
    Less wtf's..

    Awesome idea =)
  • gravatar
    #15 Christian Kaps said on the 2011/05/26 at 09:55
    Very nice feature. It would be cool if the reflection API supports a ReflectionNamespace class, to query this use statements.

    Is there anyone with C and PHP internal skills, who can implement this missing feature, so that it can be merged into PHP5.4!?