Doctrine XML Mapping or Annotations?

Annotations are very popular in Symfony. They are easy to write and understand. And most IDE’s have great support for them. But its greatest strength is also its greatest weakness. Annotations are written in comment blocks.

This can become messy when you have a lot of configurations in your Entity. Another issue is that your annotations are coupled to your source code. Your database implementations details, or any other configurations are coupled to your domain object. This goes against the guidelines of clean code. Your domain object (Entity) should only have one reason to change.

So what can we do about it? Well we can use XML Mapping.

But first lets look at how we do it with Annotations, and then what the XML alternative is. Only when we compare and know the different solutions. Only then we can make the correct choice.

The annotation example

/**
 * Class User
 * @ORM\Entity
 * @ORM\Table(name="user")
 * @package App\Domain\Model\User
 */
class User
{
    /**
     * @ORM\Id
     * @ORM\Column(type="uuid")
     * @var Uuid
     */
    private $id;

    /**
     * @ORM\Embedded(class="EmailAddress")
     * @var EmailAddress
     */
    private $email;

    /**
     * @ORM\Embedded(class="Name")
     * @var Name
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     * @var string
     */
    private $password;

    /**
     * @ORM\Column(type="json_array")
     * @var array
     */
    private $roles;

    ...
}

You can see here. With only these few annotation its easy to write and understand. You don’t need to look in another file to see its database implementation details. This is easy and OK when your application stays small. But be aware that your mixing different reasons to change in one class.

The XML example

So how can we use XML mapping?

Well in config/doctrine.yaml you change your mappings:

mappings:
    Domain:
        is_bundle: false
        type: xml
        dir: '%kernel.project_dir%/config/mapping/orm'
        prefix: 'App\Domain\Model'
        alias: Domain\Model

You only need to change type and dir. With type we define that our mapping will be using xml. And with dir we define where doctrine can find those xml files. This  mapping is then used to create the meta data.

Then in the config/mapping/orm  directory (you might need to create it first) you add the file with the same name as your Entity.  And you use . for sub directories.

My Entity is in a User sub folder and called User. This means my file name is User.User.orm.xml.

The content of this XML is:

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                   https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
    <entity name="App\Domain\Model\User\User" table="user">
        <id name="id" column="id" type="uuid"/>
        <embedded name="email" class="EmailAddress"/>
        <embedded name="name" class="Name"/>
        <field name="password" type="string"/>
        <field name="roles" type="json_array"/>
    </entity>
</doctrine-mapping>

As you can see now the same database definition is placed in a seperate xml file. The configurations are kinda the same but with XML tags. You also have auto completion and suggestions in your EDI. The only extra work is creating a new file and learning the XML mapping (once).

You can find the documentation for XML Mapping here.

Conclusion

Don’t get me wrong. I love annotations. I love @Route in my controllers. But I’m not a big fan of annotations in Entities, but will use them when the project or team requires it. Use them when and where it makes sense. Be pragmatic about it, discuss it within your team.

Its very important to recognize there is an alternative to using annotations. If you have never worked with XML’s configurations for Doctrine. I recommend trying it out. Then decide on a project to project base to use annotations or XML.

For bigger projects its in my humble opinion a no brainer to use XML’s. But for smaller projects, the ease of use working with annotations is something we can’t ignore. As always, think before you code! And don’t just follow examples with annotations blindly.