3

私は数か月間 ZF を使用しており、非常に満足していますが、モデルの関係を操作し、同時にデータベースへの複数のクエリを回避する方法については完全にはわかりません。多くの人がこの問題を抱えていますが、誰もそれに対する良い解決策を見つけていないようです. (およびサードパーティの ORM の使用を避ける) たとえば、ユーザーのリストがあり、各ユーザーはグループに属しています。ユーザー情報とグループ名を表示するユーザーのリストが必要です(テーブル:ユーザーとグループ。ユーザーはテーブルグループへの外部キーを持っています)。これらのテーブルを処理するための 2 つのマッパー クラス、UserMapper と GroupMapper があります。2 つのモデル クラス ユーザーとグループ Zend_DB_Table_Abstract を拡張する 2 つのデータ ソース クラス

ユーザーマッパーでは、各ユーザーのグループ情報を取得するためにfindParentRowを実行できますが、問題は、各行に余分なクエリがあることです。これは、結合を使用すると1つだけで実行できると思います。もちろん、その結果をオブジェクトにマップする必要があります。したがって、私の抽象Mapperクラスでは、列のエイリアスを使用して各親行の結合テーブルを積極的にロードしようとします(Yiiと同様..私は思う)ので、1つのクエリでこのような値オブジェクトを取得します//ユーザーモデルオブジェクト

$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 テーブルは追加のクエリを実行して、正常でキャッシュ可能なメタデータを取得します。私の問題は、親行情報を取得することです...yiiのように....そのようなもの $userModel->with('group')->fetchAll(); ありがとうございました。

4

2 に答える 2

2

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、および_referenceMapfromを使用して(結合された列から)子インスタンスを作成し、それらを親インスタンス(「プライマリテーブル」列から作成)Zend_Db_Table_Abstract内の適切な配列に追加します。_children

子へのアクセスは次のように行われます。$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つのレベルにコーディングしましたが、祖父母-親-子など、より多くのレベルを処理するようにこれを拡張する過程にあります。

于 2012-05-14T15:17:19.263 に答える
2

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());
}

乾杯

于 2012-03-20T15:26:25.930 に答える