2

in my project i need to share objects between orm and odm. I have an entity "Variation" and a document "Tracking". One variation can hold many trackingevents. I tried to solve it through doctrine extension references using the stofdoctrineextensionbundle for symfony 2.3 but whatever i do it wont work. Maybe someone of you have an idea.

Tracking Document: ( watch for $variation )

namespace Anchorbrands\Bundle\LandingpageBundle\Document;

use Anchorbrands\Bundle\LandingpageBundle\AnchorbrandsLandingpageBundle;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;


/**
 * @ODM\Document(collection="landingpage_tracking")
 */
class Tracking {

    /**
     * @Gedmo\ReferenceOne(type="entity", class="Anchorbrands\Bundle\LandingpageBundle\Entity\Variation", inversedBy="trackingEvents", identifier="variationId")
     */
    protected $variation;

    protected $variationId;

    public function setVariationId($variationId)
    {
        $this->variationId = $variationId;
    }

    public function getVariationId()
    {
        return $this->variationId;
    }

Variation Entity ( watch out for $trackingEvents )

/**
 * Variation
 *
 * @ORM\Table(name="landingpage_variation")
 * @ORM\Entity
 */
class Variation
{

/**
 * @Gedmo\ReferenceMany(type="document", class="Anchorbrands\Bundle\LandingpageBundle\Document\Tracking", mappedBy="variation")
 */
protected $trackingEvents;


public function getTrackingEvents()
{
    return $this->trackingEvents;
}

public function setTrackingEvents(Collection $trackingEvents)
{
    $this->trackingEvents = $trackingEvents;
}
Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
user2485214
  • 227
  • 1
  • 6
  • 13

3 Answers3

1

Workaround to the circular referencing problem (unless you can solve it using DI) @see stof's bundle

<?php

namespace ACME\CoreBundle\Listener;

use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class ReferencesListener
 *
 * @package ACME\CoreBundle\Listener
 */
class ReferencesListener extends \Gedmo\References\ReferencesListener
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;
    /**
     * @var array
     */
    protected $managers
        = [
            'document' => 'doctrine.odm.mongodb.document_manager',
            'entity'   => 'doctrine.orm.default_entity_manager'
        ];

    /**
     * @param ContainerInterface $container
     * @param array              $managers
     */
    public function __construct(ContainerInterface $container, array $managers = array())
    {
        $this->container = $container;
        parent::__construct($managers);
    }

    /**
     * @param $type
     *
     * @return object
     */
    public function getManager($type)
    {
        return $this->container->get($this->managers[$type]);
    }
} 

Listener defination

acme.listener.reference:
       class: ACME\CoreBundle\Listener\ReferencesListener
       arguments: ["@service_container"]
       tags:
           - { name: doctrine.event_subscriber, connection: default }
Ahmed Habashy
  • 108
  • 1
  • 7
0

When using doctrine extension's references you need to make sure you have registered the subscriber with doctrine. Otherwise the references won't work.

In symfony2 you can register doctrine listeners/subscribers using container tags:

config.yml

services:
    gedmo_reference_listener:          # choose whatever name you like
        class: Gedmo\References\ReferencesListener
        arguments: 
            - { entity: @doctrine.orm.entity_manager, document: @doctrine.odm.mongodb.document_manager }
        tags:
            - { name: doctrine.event_subscriber, connection: default }

This is what StofDoctrineExtensionsBundle usually does in the bundle's compilerpass. It just simplifies the process of registering the services using a bit of configuration.

But as you can see here ... @stof didn't yet add the reference listener to the configuration options.

There is already an open pull request but @stof doesn't want to add it until the implementation has been refactored. Meanwhile use my solution above :-)

Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
  • Hi, thanks for your reply. Your solution is not working cause it seems that i need to pass an index through the service container. Do you have any idea? Notice: Undefined index: document in /vagrant/www/vendor/gedmo/doctrine-extensions/lib/Gedmo/References/ReferencesListener.php line 122 – user2485214 Jun 25 '13 at 21:53
  • updated my answer you have to inject an array of object-managers ( entity-manager, document-manager, ... ) into the constructor of the listener – Nicolai Fröhlich Jun 26 '13 at 08:21
  • just ran into another exception: ServiceCircularReferenceException: Circular reference detected for service "doctrine.orm.default_entity_manager", path: "doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> gedmo_reference_listener". i quiet new to symfony but i beginn to understand the fundermentals of the container – user2485214 Jun 26 '13 at 08:28
  • for me it seems like i try to inject a class which needs another object for which the instance is needed.. so i end in a loop – user2485214 Jun 26 '13 at 08:31
  • looks like the managers passed to the constructor has to be an associative array "type" -> manager ... https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/References/ReferencesListener.php#L120 ... maybe we need a service factory here ... investigating – Nicolai Fröhlich Jun 26 '13 at 08:45
  • okay seems like we need an array { document: `@document_manager` , entity: `@entity_manager` } ... the original error thrown at line 122 indicates that type can be 'document'. updated my answer. does it work now or circular reference again? – Nicolai Fröhlich Jun 26 '13 at 08:50
  • yes.. i end up into another circular reference ServiceCircularReferenceException: Circular reference detected for service "doctrine.orm.default_entity_manager", path: "http_kernel -> debug.event_dispatcher -> profiler -> security.context -> security.authentication.manager -> fos_user.user_provider.username -> fos_user.user_manager -> doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> gedmo_reference_listener". – user2485214 Jun 26 '13 at 09:11
  • trying to solve the puzzle using a callable ... updating when i found success – Nicolai Fröhlich Jun 26 '13 at 09:16
  • had you had time to dig into it? – user2485214 Jun 28 '13 at 07:56
  • Didn't forget you, but i have to work today and i'll come back to you afterwards okay? :) – Nicolai Fröhlich Jun 28 '13 at 09:55
  • ah there was something - I'm back in the game ... :D There seems to be a working example in PR https://github.com/l3pp4rd/DoctrineExtensions/pull/625/files by OpenSky. Did you already have a look at that one? – Nicolai Fröhlich Jul 08 '13 at 14:28
  • It would be nice to post the important parts of the PR code into this question and accept it as an answer @nifr . Thanks in advance! – webDEVILopers Sep 10 '14 at 07:50
  • @webDEVILopers: I haven't asked this question ... so I can't accept an answer. Yet my answer solves the issue. Feel free to propose an edit including the parts of the PR that you think might help others in the future. – Nicolai Fröhlich Sep 10 '14 at 08:43
  • Sorry, missed the original author @nifr. Unfortunately the PR at https://github.com/l3pp4rd/DoctrineExtensions/issues/625 is gone. I am trying to create a working example with the SonataAdminBundle and see if the solution relates to this question. – webDEVILopers Sep 10 '14 at 08:48
  • I tried your solution @nifr but ran into the same error as user2485214 did and mentioned above: ServiceCircularReferenceException: Circular reference detected for service "doctrine.orm.default_entity_manager", path: "doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> gedmo_reference_listener". Too bad the PR with the obvious solution is gone. Am I still missing something to make your solution work? – webDEVILopers Sep 10 '14 at 11:44
  • I think the issue is also discussed here: https://github.com/Atlantic18/DoctrineExtensions/issues/821 – webDEVILopers Sep 10 '14 at 11:55
0

Maybe try from :

services:
    # reference behavior doctrine < mongodb
    gedmo.listener.reference:
        class: Gedmo\References\ReferencesListener
        tags:
            - { name: doctrine_mongodb.odm.event_subscriber }
        calls:
            - [ setAnnotationReader, [ "@annotation_reader" ] ]
            - [ registerManager, [ 'entity', "@doctrine.orm.default_entity_manager" ] ]

    # reference behavior doctrine > mongodb
    gedmo.listener.reference:
        class: Gedmo\References\ReferencesListener
        tags:
            - { name: doctrine.event_subscriber, connection: default }

        calls:
            - [ setAnnotationReader, [ "@annotation_reader" ] ]
            - [ registerManager, [ 'document', "@doctrine_mongodb.odm.document_manager" ] ]

They both work for me, but alone...

If you put them both like this only the second is taken

Azr
  • 1,083
  • 1
  • 13
  • 26
  • You're actively overwriting the first service by providing the SAME service-name (`gedmo.listener.reference`) with both subscribers. Change one of the service's names and both subscribers will be active. – Nicolai Fröhlich Sep 10 '14 at 08:49
  • When trying to set individual service names like gedmo.listener.reference_one and ..reference_two I get this error: ServiceCircularReferenceException: Circular reference detected for service "doctrine_mongodb.odm.default_document_manager", path: "doctrine_mongodb.odm.default_document_manager -> doctrine_mongodb.odm.default_connection -> doctrine_mongodb.odm.event_manager -> gedmo.listener.reference_orm -> doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> gedmo.listener.reference_odm". – webDEVILopers Sep 10 '14 at 11:38