Domanda

I am attempting to integrate PHPCR-ODM with an existing Symfony project, and am having trouble getting it to (presumably) detect my mapped Document class. Specifically, I get an error like this when attempting to persist a Document of my class MyDocument:

[Doctrine\Common\Persistence\Mapping\MappingException]                                                                            
The class 'Example\Common\ORM\Document\MyDocument' was not found in the chain configured namespaces Doctrine\ODM\PHPCR\Document

My class is in a potentially strange namespace because this project uses Doctrine ORM as well, and thus far I've just added a new space for mapped Documents off of that, but I can't imagine the choice of namespace name affects the functionality.

Per the docs, I have added to my app/autoload.php:

 AnnotationRegistry::registerFile(__DIR__.'/../vendor/doctrine/phpcr-odm/lib/Doctrine/ODM/PHPCR/Mapping/Annotations/DoctrineAnnotations.php');

My app/config/config.yml includes the following (with parameters set in parameters.yml):

 doctrine_phpcr:
     session:
         backend:
             type: jackrabbit
             url: %jackrabbit_url%
         workspace: %jackrabbit_workspace%
         username: %jackrabbit_user%
         password: %jackrabbit_password%
     odm:
         auto_mapping: true

My document class lives in src/Example/Common/ORM/Document/MyDocument.php and looks like:

<?php

namespace Example\Common\ORM\Document;

use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM;

/**
 * @PHPCRODM\Document
 */
class MyDocument
{
  /**
   * @PHPCRODM\Id
   */
  private $id;

  /**
   * @PHPCRODM\ParentDocument
   */
  private $parent;

  /**
   * @PHPCRODM\Nodename
   */
  private $name;

  // .. etc

Finally, the code I am using to test the integration is inside a simple console command, and looks like:

use Example\Common\ORM\Document\MyDocument;

// ...

$documentManager = $this->container->get('doctrine_phpcr.odm.default_document_manager');

$document = new MyDocument();
$document->setParent($documentManager->find(null, '/'));
$document->setName('ExampleName');

$documentManager->persist($document);
$documentManager->flush();

I have verified that my MyDocument class is being correctly loaded, but it seems that the annotations are not being processed in a way that is making the DocumentManager aware that it is a mapped Document class.

My guess is that I have overlooked some simple configuration step, but from looking repeatedly and thoroughly at the docs for PHPCR, PHPCR-ODM, and even Symfony CMF, I can't seem to find anything. Most of the examples out there involve using PHPCR via Symfony CMF, and I wasn't able to find many (any?) real world examples of PHPCR-ODM being integrated in a regular Symfony project.


edit: The Eventual Solution

I followed the advice that @WouterJ gave below and it fixed my problem, and I further followed his suggestion of adding a compiler pass to my Symfony bundle to make this work with a non-standard namespace (i.e., something other than YourBundle\Document). In my case, this is going into a library that will be re-used elsewhere rather than a bundle, so it was appropriate.

To do this, I added a method to the src/Example/Bundle/ExampleBundle/ExampleBundle.php file like so:

<?php

namespace Example\Bundle\ExampleBundle;

use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class ExampleBundle extends Bundle
{
  public function build(ContainerBuilder $container)
  {
    parent::build($container);

    $mappedDirectories = array(
      realpath(__DIR__ . '/../../Common/ODM/Document')
    );

    $mappedNamespaces = array(
        'Example\Common\ODM\Document'
    );

    $phpcrCompilerClass = 'Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass';
    if (class_exists($phpcrCompilerClass)) {
        $container->addCompilerPass(
            DoctrinePhpcrMappingsPass::createAnnotationMappingDriver(
              $mappedNamespaces,
              $mappedDirectories
        ));
    }
  }
}

That code allows any mapped document classes to be placed in the Example\Common\ODM\Document namespace and it will pick them up. This example uses annotations but the same pattern can be used for XML or YAML mappings (see the Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass class for method signatures).

I found that I also needed to define the doctrine_phpcr.odm.metadata.annotation_reader service for this to work, which I did in app/config.yml:

services:
    doctrine_phpcr.odm.metadata.annotation_reader:
        class: Doctrine\Common\Annotations\AnnotationReader

There may be a better way to do that, but that was enough to make it work for me.

È stato utile?

Soluzione

The document should be placed in the Document namespace of the bundle, not the ORM\Document namespace.

If you really want to put it in the ORM\Document namespace (which is very strange, because we are talking about an ODM not an ORM), you can use the doctrine mapping compiler pass: http://symfony.com/doc/current/cookbook/doctrine/mapping_model_classes.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top