Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • SensioLabs Professional services to help you with Symfony
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Cookbook
  4. Doctrine
  5. How to Provide Model Classes for several Doctrine Implementations
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

How to Provide Model Classes for several Doctrine Implementations

Edit this page

Warning: You are browsing the documentation for Symfony 2.4, which is no longer maintained.

Read the updated version of this page for Symfony 6.2 (the current stable version).

How to Provide Model Classes for several Doctrine Implementations

When building a bundle that could be used not only with Doctrine ORM but also the CouchDB ODM, MongoDB ODM or PHPCR ODM, you should still only write one model class. The Doctrine bundles provide a compiler pass to register the mappings for your model classes.

Note

For non-reusable bundles, the easiest option is to put your model classes in the default locations: Entity for the Doctrine ORM or Document for one of the ODMs. For reusable bundles, rather than duplicate model classes just to get the auto mapping, use the compiler pass.

2.3

The base mapping compiler pass was introduced in Symfony 2.3. The Doctrine bundles support it from DoctrineBundle >= 1.2.1, MongoDBBundle >= 3.0.0, PHPCRBundle >= 1.0.0-alpha2 and the (unversioned) CouchDBBundle supports the compiler pass since the CouchDB Mapping Compiler Pass pull request was merged.

If you want your bundle to support older versions of Symfony and Doctrine, you can provide a copy of the compiler pass in your bundle. See for example the FOSUserBundle mapping configuration addRegisterMappingsPass.

In your bundle class, write the following code to register the compiler pass. This one is written for the FOSUserBundle, so parts of it will need to be adapted for your case:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass;
use Doctrine\Bundle\CouchDBBundle\DependencyInjection\Compiler\DoctrineCouchDBMappingsPass;
use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass;

class FOSUserBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        // ...

        $modelDir = realpath(__DIR__.'/Resources/config/doctrine/model');
        $mappings = array(
            $modelDir => 'FOS\UserBundle\Model',
        );

        $ormCompilerClass = 'Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass';
        if (class_exists($ormCompilerClass)) {
            $container->addCompilerPass(
                DoctrineOrmMappingsPass::createXmlMappingDriver(
                    $mappings,
                    array('fos_user.model_manager_name'),
                    'fos_user.backend_type_orm'
            ));
        }

        $mongoCompilerClass = 'Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass';
        if (class_exists($mongoCompilerClass)) {
            $container->addCompilerPass(
                DoctrineMongoDBMappingsPass::createXmlMappingDriver(
                    $mappings,
                    array('fos_user.model_manager_name'),
                    'fos_user.backend_type_mongodb'
            ));
        }

        $couchCompilerClass = 'Doctrine\Bundle\CouchDBBundle\DependencyInjection\Compiler\DoctrineCouchDBMappingsPass';
        if (class_exists($couchCompilerClass)) {
            $container->addCompilerPass(
                DoctrineCouchDBMappingsPass::createXmlMappingDriver(
                    $mappings,
                    array('fos_user.model_manager_name'),
                    'fos_user.backend_type_couchdb'
            ));
        }

        $phpcrCompilerClass = 'Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass';
        if (class_exists($phpcrCompilerClass)) {
            $container->addCompilerPass(
                DoctrinePhpcrMappingsPass::createXmlMappingDriver(
                    $mappings,
                    array('fos_user.model_manager_name'),
                    'fos_user.backend_type_phpcr'
            ));
        }
    }
}

Note the class_exists check. This is crucial, as you do not want your bundle to have a hard dependency on all Doctrine bundles but let the user decide which to use.

The compiler pass provides factory methods for all drivers provided by Doctrine: Annotations, XML, Yaml, PHP and StaticPHP. The arguments are:

  • a map/hash of absolute directory path to namespace;
  • an array of container parameters that your bundle uses to specify the name of the Doctrine manager that it is using. In the above example, the FOSUserBundle stores the manager name that's being used under the fos_user.model_manager_name parameter. The compiler pass will append the parameter Doctrine is using to specify the name of the default manager. The first parameter found is used and the mappings are registered with that manager;
  • an optional container parameter name that will be used by the compiler pass to determine if this Doctrine type is used at all. This is relevant if your user has more than one type of Doctrine bundle installed, but your bundle is only used with one type of Doctrine.

Note

The factory method is using the SymfonyFileLocator of Doctrine, meaning it will only see XML and YML mapping files if they do not contain the full namespace as the filename. This is by design: the SymfonyFileLocator simplifies things by assuming the files are just the "short" version of the class as their filename (e.g. BlogPost.orm.xml)

If you also need to map a base class, you can register a compiler pass with the DefaultFileLocator like this. This code is simply taken from the DoctrineOrmMappingsPass and adapted to use the DefaultFileLocator instead of the SymfonyFileLocator:

1
2
3
4
5
6
7
8
9
10
11
12
13
private function buildMappingCompilerPass()
{
    $arguments = array(array(realpath(__DIR__ . '/Resources/config/doctrine-base')), '.orm.xml');
    $locator = new Definition('Doctrine\Common\Persistence\Mapping\Driver\DefaultFileLocator', $arguments);
    $driver = new Definition('Doctrine\ORM\Mapping\Driver\XmlDriver', array($locator));

    return new DoctrineOrmMappingsPass(
        $driver,
        array('Full\Namespace'),
        array('your_bundle.manager_name'),
        'your_bundle.orm_enabled'
    );
}

Now place your mapping file into /Resources/config/doctrine-base with the fully qualified class name, separated by . instead of \, for example Other.Namespace.Model.Name.orm.xml. You may not mix the two as otherwise the SymfonyFileLocator will get confused.

Adjust accordingly for the other Doctrine implementations.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:
    Become certified from home

    Become certified from home

    Check Code Performance in Dev, Test, Staging & Production

    Check Code Performance in Dev, Test, Staging & Production

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Hubert Moutot, a Symfony contributor

    Thanks Hubert Moutot (@youbs) for being a Symfony contributor

    1 commit • 25 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony

    Search by Algolia