Question

I've started working with Symfony2 and MongoDB (Doctrine ODM) and am having difficulty getting the unique validator constraint to work on multiple fields (one field references another MongoDB document with DBRef). In my validation.yml file, I have:

Acme\SomeBundle\Document\ArticlePosition:
    constraints:
        - Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique:
            fields: [position, section]

The "position" field is an integer and "section" is a referenceOne field which points to an entity in another bundle.

When I submit a form for this I see the following queries in the profiler:

db.article_position.find({ "position": 1, "section": "51ff78494fae886b1f7c0f1d" });
db.article_position.insert({ "000000005dc659f30000000082e5d25d": { "_id":ObjectId("5203d1804fae880e801fd12d"), "position": 1, "section": { "$ref": "section", "$id": ObjectId("51ff78494fae886b1f7c0f1d"), "$db": "my_db" } } });

Symfony/Doctrine looks like they are trying to do the right thing. The first find() looks for a matching document with both the position and section field, but it's missing the DBRef fields ($ref, $id, $db) and always returns an empty set.

The find() query should be like this:

db.article_position.find({ "position": 1, "section": { "$ref": "section", "$id": ObjectId("51ff78494fae886b1f7c0f1d"), "$db": "my_db" }});

My doctrine YAML file looks like:

Acme\SomeBundle\Document\ArticlePosition
    type: document
    collection: article_position
    referenceOne:
        section:
            targetDocument: Acme\SomeOtherBundle\Document\Section
    fields:
        id:
            type: id
            id: true
        position:
            type: int

The section document is located in a separate bundle from the ArticlePosition document.

Was it helpful?

Solution

This is more of a workaround than a solution.

First, in your controller, you have to manually link section to ArticlePosition before you invoke $form->isValid().

$entity = new ArticlePosition();
$entity->setSection($section); 
...
$form->handleRequest($request);
if ($form->isValid()) {
    ...
}

Second, you have to specify a custom repository method for the Unique constraint.

# validation.yml
Acme\DefaultBundle\Document\ArticlePosition:
    constraints:
        - Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique:
            fields: [section, position]
            repositoryMethod: findUniqueBy

and in your ArticlePositionRepository

public function findUniqueBy($criteria)
{
    $section = $criteria['section'];
    $position = $criteria['position'];

    return $this->findBy(array('section.id' => $section, 'position' => $position));
}

The key is here is to add .id for reference fields in findBy for Mongodb to correctly query the result.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top