2

I'm creating a bundle with relationship associations. In order to keep things abstract, I'd like to use Doctrine's brand new ResolveTargetEntities listener.

The thing is that I would like the setup of the listener to be automated, so future developers using my bundle won't need to configure the listener themselves.

In my bundle, there's a config parameter called data_class, which I would like to use to setup the ResolveTargetEntities listener:

# app/config/config.yml
my_bundle:
    City:
        data_class: Acme\DemoBundle\Entity\City

How can I setup a service, or a config file within my bundle to configure the listener using this parameter? Something like this:

resolve_target_entities:
    Dev\MyBundle\Model\City: %my_bundle.City.data_class%

EDIT:

The above configuration example is provided to show what should be accomplished by doctrine, but the object of this question is to find a way to setup the ResolveTargetEntities listener automatically, using a service, a dependency injection container, or any other way that requires the end user to provide only one parameter under the my_bundle namespace: data_class

bob dope
  • 479
  • 1
  • 6
  • 16
  • Have you tried this: `resolve_target_entities: Dev\MyBundle\Model\City: "%my_bundle.City.data_class%"`? – Mick Jan 20 '13 at 16:58
  • Thank you for your comment. Yes, I tried and got an error message. I would also prefer a solution that doesn't involve writing the configuration manually in the app/config/config.yml. Maybe a service, or using the dependency injection? – bob dope Jan 20 '13 at 21:55

3 Answers3

4

You can use your Bundle Extension class in DependancyInjection folder for that. There is a option to add custom configuration to another bundles configuration (http://symfony.com/doc/current/cookbook/bundles/prepend_extension.html). My code that does the same is below.

<?php

namespace Zveen\CmsBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
 * This is the class that loads and manages your bundle configuration
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
 */
class ZveenCmsExtension extends Extension implements PrependExtensionInterface
{
    /**
     * {@inheritDoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $container->setParameter('zveen.cmsbundle.tenant.class', $config['tenant']['class']);
        $container->setParameter('zveen.cmsbundle.tenant.dql', $config['tenant']['class']);

        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
    }

    /**
     * Allow an extension to prepend the extension configurations.
     *
     * @param ContainerBuilder $container
     */
    public function prepend(ContainerBuilder $container)
    {
        // get all Bundles
        $bundles = $container->getParameter('kernel.bundles');
        if (isset($bundles['DoctrineBundle'])) {
            // Get configuration of our own bundle
            $configs = $container->getExtensionConfig($this->getAlias());
            $config = $this->processConfiguration(new Configuration(), $configs);

            // Prepare for insertion
            $forInsertion = array(
                'orm' => array(
                    'resolve_target_entities' => array(
                        'Zveen\CmsBundle\Entity\TenantInterface' => $config['tenant']['class']
                    )
                )
            );
            foreach ($container->getExtensions() as $name => $extension) {
                switch ($name) {
                    case 'doctrine':
                        $container->prependExtensionConfig($name, $forInsertion);
                        break;
                }
            }
        }
    }
}
zveljkovic
  • 444
  • 4
  • 16
1

See https://github.com/doctrine/doctrine2/blob/master/docs/en/cookbook/resolve-target-entity-listener.rst

Next, we need to configure the listener. Add this to the area you set up Doctrine. You must set this up in the way outlined below, otherwise you can not be guaranteed that the targetEntity resolution will occur reliably: $evm = new \Doctrine\Common\EventManager;

$rtel = new \Doctrine\ORM\Tools\ResolveTargetEntityListener;
$rtel->addResolveTargetEntity('Acme\\InvoiceModule\\Model\\InvoiceSubjectInterface',
    'Acme\\CustomerModule\\Entity\\Customer', array());

// Add the ResolveTargetEntityListener
$evm->addEventSubscriber($rtel);

$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $evm);
Alex Lisovoy
  • 5,767
  • 3
  • 27
  • 28
  • Thank you for your reply. It looks like you understood exactly what I need. However, I don't understand where I should use this code. Inside a controller? Create a service? A listener? Any help much appreciated. – bob dope Mar 14 '13 at 15:24
  • You have to use a Symfony compiler pass (see [this issue comment](https://github.com/doctrine/DoctrineBundle/issues/185#issuecomment-17760795)). – stollr Feb 26 '14 at 14:12
0

Try writing

my_bundle.City.data_class: Acme\DemoBundle\Entity\City

in the parameters.yml file, it worked to me.

  • Thank you for your reply. Yes, that would work, but I'm trying to set up the listener automatically, using the parameter from my example. The idea is that the developer will only have to provide my data_class parameter, and the bundle will setup the doctrine ResolveTargetEntities listener automatically. A service, or maybe a dependency injection might do it, but I don't know how. I guess my question was unclear... – bob dope Jan 21 '13 at 13:34
  • I'm validating this answer to thank you for your time, but this question remains unanswered to me. – bob dope Jan 23 '13 at 11:54