Обход Doctrine2 ODM/MongoDB Object Graph в Symfony2 не может заполнить свойства в объекте 2-го уровня

Я конвертирую свое работающее в остальном приложение Symfony2 для использования MongoDB через Doctrine-ODM. У меня работает подавляющее большинство системы, но я не могу заставить работать часть ролей пользователей. Я могу войти в систему, но тогда к пользователю не привязаны роли.

Соответствующие классы документов представлены здесь со всем, кроме того, что имеет значение.

Пользователь

<?php

namespace XXXXX\UserBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\Common\Collections\ArrayCollection;
use XXXXX\UserBundle\Interfaces\UserInterface;

/**
 * 
 * @MongoDB\Document( collection="user")
 * 
 */
class User implements UserInterface {

    /**
     * @MongoDB\Id
     */
    protected $id;

    /**
     * @MongoDB\ReferenceMany(targetDocument="Group")
     */
    protected $groups;

    /**
     * Constructor
     */
    public function __construct() {
        $this->groups = new ArrayCollection();
        $this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
    }

    public function getRoles() {
        $array = array();
        //parse the roles down to an array
        foreach ($this->getGroups() as $group) {
            /* @var $group Group */
            foreach ($group->getRoles() as $role) {
                /* @var $role Role */
                if(!$role->getName())
                    throw new \Exception('Role must exist in group: '.$group->getName().' with ID: '.$group->getId().'.');
                $array[$role->getName()] = $role->getName();
            }
        }
        sort($array);
        return $array;
    }

    /**
     * Get groups
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getGroups() {
        return $this->groups;
    }

}

Группа

<?php

namespace XXXXX\UserBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use XXXXX\UserBundle\Interfaces\UserInterface;
use XXXXX\UserBundle\Interfaces\RoleInterface;
use XXXXX\UserBundle\Interfaces\GroupInterface;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @MongoDB\Document( collection="user_group" )
 */
class Group implements GroupInterface {

    /**
     * @MongoDB\Id
     */
    protected $id;

    /**
     * @MongoDB\String
     * @var string 
     */
    protected $name;

    /**
     * @MongoDB\ReferenceMany(targetDocument="User")
     */
    protected $users;

    /**
     * @MongoDB\ReferenceMany(targetDocument="Role", inversedBy="groups")
     */
    protected $roles;

    /**
     * Constructor
     */
    public function __construct() {
        $this->users = new ArrayCollection();
        $this->roles = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Get roles
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getRoles()
    {
        return $this->roles;
    }
}

Роль

<?php

namespace XXXXX\UserBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use XXXXX\UserBundle\Interfaces\UserInterface;
use XXXXX\UserBundle\Interfaces\GroupInterface;
use XXXXX\UserBundle\Interfaces\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @MongoDB\Document( collection="user_role")
 */
class Role implements RoleInterface {

    /**
     * @MongoDB\Id
     */
    protected $id;

    /**
     * @MongoDB\String
     * @var string 
     */
    protected $name;

    /**
     * @MongoDB\String
     * @var string 
     */
    protected $description;

    /** 
     * @MongoDB\ReferenceMany(targetDocument="Group", mappedBy="roles") 
     */
    protected $groups;

    /**
     * Set name
     *
     * @param string $name
     * @return RoleInterface
     */
    public function setName($name) {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName() {
        return $this->name;
    }

    public function getId() {
        return $this->id;
    }

    public function getDescription() {
        return $this->description;
    }

    public function setDescription($description) {
        $this->description = $description;
    }

}

Я использую фикстуры для загрузки данных в базу данных, и данные в MongoDB выглядят следующим образом. (Я удалил дополнительные элементы данных.)

Пользователь.

{ "_id" : ObjectId("5091a7241311fae01f00000d"), "groups" : [  DBRef("user_group", ObjectId("5091a7241311fae01f00000b")),      DBRef("user_group", ObjectId("5091a7241311fae01f00000c")) ] }

Группы, на которые ссылается Пользователь. (Это из запроса, который запускается Symfony2)

db.user_group.find({ "_id": { "$in": { "5091a7241311fae01f00000b":ObjectId("5091a7241311fae01f00000b"), "5091a7241311fae01f00000c": ObjectId("5091a7241311fae01f00000c") } } }).sort([ ]);

{ "_id" : ObjectId("5091a7241311fae01f00000b"), "name" : "Base.Users", "roles" : [ DBRef("user_role", ObjectId("5091a7241311fae01f000009")) ] }
{ "_id" : ObjectId("5091a7241311fae01f00000c"), "name" : "AdminPortal.Base", "roles" : [ DBRef("user_role", ObjectId("5091a7241311fae01f000009")),        DBRef("user_role", ObjectId("5091a7241311fae01f00000a")) ] }

И, наконец, роли, на которые ссылаются группы. (Также взято из точного запроса, выполняемого Symfony2)

db.user_role.find({ "_id": { "$in": { "5091a7241311fae01f000009": ObjectId("5091a7241311fae01f000009") } } }).sort([ ]);
{ "_id" : ObjectId("5091a7241311fae01f000009"), "name" : "ROLE_USER", "description" : "Role required for all system users." }

Далее вызывается исключение в функции getRoles() для пользователя и возвращается следующий текст.

Роль должна существовать в группе: Base.Users с идентификатором: 5091a7241311fae01f00000b.

Проблема в том, что роли запрашиваются из базы данных, но затем не заполняются в объект роли. Я могу убедиться, что они загружаются, так как, когда я комментирую исключение, оно запускается и пытается добавить правильное количество ролей в группу. Проблема в том, что свойство имени роли имеет значение NULL. Сам объект роли является сохраненным и загруженным объектом, как если бы я выполнял команду print_r($role);exit; непосредственно перед оператором if я получу чрезвычайно рекурсивный вывод, который демонстрируют объекты доктрины. Единственное, что не происходит, это то, что свойства «имя» (и другие) не загружаются из базы данных.

Любое понимание того, как я могу решить эту проблему, будет очень признательно. Спасибо.


person Wpigott    schedule 31.10.2012    source источник


Ответы (1)


Я смог определить обходной путь. По сути, использование удобных функций, таких как find, findBy, findOneBy и т. д., похоже, не настраивает объекты для обхода. Я смог получить правильный результат, изменив функцию загрузки, чтобы использовать построитель запросов вместо удобной функции «findOneBy».

Мой измененный запрос ниже. Надеюсь, это поможет кому-то в будущем.

/**
     * 
     * @param string $username
     * @return User|Null
     */
    public function findUserByUserName($username) {
        $qb = $this->createQueryBuilder();
        $qb->find($this->getClassName());
        $qb->field('username');
        $qb->equals($username);
        $query = $qb->getQuery();
        return $query->getSingleResult();
    }

Я полагаю, что это могло бы быть более кратким, но мне пришлось разбить его на части, чтобы отладить, и я живу своей жизнью. :)

person Wpigott    schedule 01.11.2012