Zend Framework - ORM отношения и оптимизация - PullRequest
3 голосов
/ 19 марта 2012

Я использую ZF в течение нескольких месяцев, и я действительно доволен им, однако я не совсем уверен, как работать с отношениями моделей и в то же время избегать множественных запросов к БД. У многих людей есть эта проблема, и никто, кажется, не может найти хорошее решение для нее. (и избегая использования стороннего ORM) Например, у меня есть список пользователей, и каждый пользователь принадлежит к группе. Мне нужен список пользователей, отображающих информацию о пользователе и имя группы (для таблиц: пользователи и группы. У пользователей есть внешний ключ для групп таблиц). Я имею: 2 класса отображения для обработки этих таблиц, UserMapper и GroupMapper. 2 модели классов пользователей и групп 2 класса источников данных, расширяющих Zend_DB_Table_Abstract

в маппере пользователя я могу сделать findParentRow, чтобы получить информацию о группе каждого пользователя, но проблема в том, что у меня есть дополнительный запрос для каждой строки, это не очень хорошо, я думаю, когда с объединением я могу сделать это только в один. Конечно, теперь мы должны отобразить этот результат на объект. так что в моем абстрактном классе Mapper я пытаюсь загрузить объединяющие таблицы для каждой родительской строки, используя псевдонимы столбцов (аналогично Yii, я думаю), поэтому я получаю в одном запросе объект-значение, подобный этому // Объект пользовательской модели

$userMapper= new UserMapper();
$users= $userMapper->fetchAll(); //Array of user objects
echo $user->id;
echo $user->getGroup()->name // $user->getParentModel('group')->name // this info is already in the object so no extra query is required.

Я думаю, вы поняли мою точку зрения ... Есть ли нативное решение, возможно, более академическое, чем мое, чтобы сделать это, не избегая множественных запросов? // Zend db table выполняет дополнительные запросы для получения метаданных, которые в порядке и могут быть кэшированы. Моя проблема в том, чтобы получить информацию о родительской строке ... как в yii .... что-то подобное $ userModel-> with ('group') -> fetchAll (); Спасибо.

Ответы [ 2 ]

2 голосов
/ 14 мая 2012

Я написал решение подклассами Zend_Db_Table_Rowset_Abstract и Zend_Db_Table_Row_Abstract. Я постараюсь кратко изложить это, и если это будет интересно кому-либо, я могу расширить его.

Я создал абстрактный класс модели - My_Db_Table_Row - который содержит массив (связанный с именем дочернего класса) наборов строк дочерних элементов.

Я создал абстрактный класс Rowset - My_Db_Table_Rowset -, который извлекает данные из запроса на основе имен столбцов и создает наборы строк, хранящиеся в My_Db_Table_Row_children.

Класс My_Db_Table_Rowset использует _dependantTables и _referenceMap из Zend_Db_Table_Abstract для создания дочерних экземпляров (из соединенных столбцов) и добавления их в соответствующий массив в _children их родительского экземпляра (созданного из 'primary столбцы таблицы).

Доступ к ребенку осуществляется следующим образом: $car->getDrivers();

public function getDrivers() {
    // allow for lazy loading
    if (!isset($this->_children['My_Model_Driver'])) {
        $this->_children['My_Model_Driver'] = My_Model_Driver::fetch........;
    }
    return $this->_children('My_Model_Driver');
}

Первоначально я закодировал это для 2 уровней, родительского и дочернего, но я нахожусь в процессе расширения этого для обработки большего количества уровней, например прародитель-родитель-ребенок.

2 голосов
/ 20 марта 2012

Разработайте свой картограф для работы с Zend_Db_Select.Это должно обеспечить необходимую вам гибкость.Присоединение таблицы групп зависит от параметра, предоставленного методам сопоставления, в этом примере объект группы является критическим параметром.

class Model_User {
    //other fields id, username etc.
    //...

    /**
    * @var Model_Group
    */
    protected $_group;

    public function getGroup() {
        return $this->_group;
    }

    public function setGroup(Model_Group $group) {
        $this->_group = $group;
    }

}

class Model_Mapper_User {

    /**
    * User db select object, joins with group table if group model provided
    * @param Model_Group $group
    * @return Zend_Db_Select
    */
    public function getQuery(Model_Group $group = NULL) {
        $userTable = $this->getDbTable('user'); //mapper is provided with the user table
        $userTableName = $userTable->info(Zend_Db_Table::NAME); //needed for aliasing
        $adapter = $userTable->getAdapter();

        $select = $adapter->select()->from(array('u' => $userTableName));

        if (NULL !== $group) {
            //group model provided, include group in query
            $groupTable = $this->getDbTable('group');
            $groupTableName = $groupTable->info(Zend_Db_Table::NAME);
            $select->joinLeft(array('g' => $groupTableName), 
                                'g.group_id = u.user_group_id');
        }

        return $select;
    }

    /**
    * Returns an array of users (user group optional)
    * @param Model_User $user
    * @param Model_Group $group
    * @return array
    */
    public function fetchAll(Model_User $user, Model_Group $group = NULL) {
        $select = $this->getQuery();
        $adapter = $select->getAdapter();
        $rows = $adapter->fetchAll($select);

        $users = array();

        if (NULL === $group) {
            foreach ($rows as $row) {
                $users[] = $this->_populateUser($row, clone $user);
            }
        } else {
            foreach ($rows as $row) {
                $newUser = $this->_populateUser($row, clone $user);
                $newGroup = $this->_populateGroup($row, clone $group);

                //marrying user and group
                $newUser->setGroup($newGroup);

                $users[] = $newUser;
            }
        }

        return $users;
    }

    /**
    * Populating user object with data
    */
    protected function _populateUser($row, Model_User $user) {
        //setting fields like id, username etc
        $user->setId($row['user_id']);
        return $user;
    }

    /**
    * Populating group object with data
    */
    protected function _populateGroup($row, Model_Group $group) {
        //setting fields like id, name etc
        $group->setId($row['group_id']);
        $group->setName($row['group_name']);
        return $group;
    }

    /**
    * This method also fits nicely
    * @param int $id
    * @param Model_User $user
    * @param Model_Group $group 
    */
    public function fetchById($id, Model_User $user, Model_Group $group = NULL) {
        $select = $this->getQuery($group)->where('user_id = ?', $id);
        $adapter = $select->getAdapter();
        $row = $adapter->fetchRow($select);

        $this->_populateUser($row, $user);
        if (NULL !== $group) {
            $this->_populateGroup($row, $group);
            $user->setGroup($group);
        }

        return $user;
    }

}

использование сценариев

/**
 * This method needs users with their group names 
 */
public function indexAction() {
    $userFactory = new Model_Factory_User();
    $groupFactory = new Model_Factory_Group();
    $userMapper = $userFactory->createMapper();
    $users = $userMapper->fetchAll($userFactory->createUser(), 
                                        $groupFactory->createGroup());
}

/**
 * This method needs no user group
 */
public function otherAction() {
    $userFactory = new Model_Factory_User();
    $userMapper = $userFactory->createMapper();
    $users = $userMapper->fetchAll($userFactory->createUser());
}

Приветствия

...