2012-03-19 18 views
3

私は数ヶ月間ZFを使用していましたが、私は本当に満足していますが、モデル関係をどのように扱うかについては完全にはわかりません。データベース。多くの人々がこの問題を抱えており、誰もそれに対して良い解決策を見つけることはできないようです。 (そして第三者のORMの使用を避ける)たとえば、私はユーザのリストを持ち、各ユーザはグループに属しています。ユーザー情報とグループ名を表示するユーザーのリストが必要です(テーブル:ユーザーとグループ、ユーザーにはテーブルグループの外部キーがあります)。 私は持っている: これらのテーブル、UserMapperとGroupMapperを扱う2つのマッパークラス。私は、各ユーザーのグループ情報を取得するために、Zend_Db_Table_Row_AbstractはfindParentRowを行うことができ、ユーザマッパーで取得Zend_Db_Table_AbstractZend Framework - ORMの関係と最適化

を拡張しますが、問題は、私は行ごとに余分なクエリを持っている 2モデル・クラスのユーザーとグループ 2データソースクラス、これは良いことではありません。私が参加すれば、私は1つしかできません。もちろん、その結果をオブジェクトにマップする必要があります。私の抽象的な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テーブルは、メタデータを取得するために追加のクエリを実行します。私の問題は親行の情報を得るためです... yii ....のようなものです。$ userModel-> with( 'group') - > fetchAll(); ありがとうございます。

+1

私は同じ問題で苦労しています。私は、Zend_Db_TableがTableDataGateway(TDG)の実装であるということがコアの問題だと思います。これは、リンクされたテーブルを扱うのに十分な柔軟性を備えていますが、結合を使用するカスタムクエリがなければ、特定したように複数のクエリが終了します。正確には、TDGと私の現実のニーズとの間のこの不一致は、しばしば第三者のORMのDoctrineのようなものに向かって私を押しつけてしまいます。 –

+0

まあまあ、Doctrineは私が普段使っているプロジェクトにとっては大きすぎます。だから私はいつでも可能な限りZendクラスに頼り、それを簡単に保つようにしています。 ZF2のZend_dbと関連するクラスの計画は何か分かりませんが、私はいくつかの改善ができることを願っています... ZF2はこの夏/秋にリリースされるはずです – FranStrentz

+0

ZF2 'Zend \ Db \ Table' APIはおそらく機能的にはZF1 'Zend_Db_Table'と同じでしょう。結局のところ、どちらもTDGの実装です。悲しいことに、ZF2がこの基本的なTDG /マッパー/結合/ユースケースの緊張を解決すると期待するのはおそらく妥当ではありません。 –

答えて

2

Zend_Db_Selectで作業するマッパーを開発してください。それはあなたが必要とする柔軟性を可能にするはずです。グループテーブルが結合されるかどうかは、マッパーメソッドに提供されるパラメータに依存します。この例では、groupオブジェクトは重要なパラメータです。

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

乾杯

+0

こんにちは、お返事ありがとうございます。私はあなたが描いているような何かをやっていると思う。私のマッパーは抽象クラスから継承されています。そのクラスには抽象クラスのすべてをフェッチするなどの一般的なメソッドがあります。私はzend dbテーブル抽象を拡張するデータテーブルソースの名前を渡します。 _referenceMap info。これとモデルクラスの名前をマップするつもりです。エイリアシングを使って1つの結合でマッピングを行うことができます。それは私の目的(カスタムとシンプルなCMS)のために正常に動作します... – FranStrentz

+0

...しかし、私はそれがフレームワークに追加されている可能性がある場合、私は自分自身に尋ねることのようなものを書いていたとき。 (オブジェクトを関連テーブルにマッピングする)しかし、私はZFの哲学の一部でもあると思います。 "モデル/マッパー"はあなたの仕事です; – FranStrentz

+0

誰かがすべてのモデルの$ _referenceMapによって与えられた抽象クラスを書くので、ゼント! – Mauro

2

私はZend_Db_Table_Rowset_AbstractZend_Db_Table_Row_Abstractをサブクラス化ソリューションを書かれています。私はそれを簡単に要約しようとします、そして、もしそれが誰にでも興味があれば、私はそれを拡張することができます。

子供の行セットの配列(子クラス名をキーとする)を含む抽象モデルクラスMy_Db_Table_Rowを作成しました。

私は、列名に基づいてクエリからデータを抽出し、My_Db_Table_Row_childrenに格納された行セットを作成する抽象的なRowsetクラス(My_Db_Table_Rowset)を作成しました。

My_Db_Table_Rowsetクラスは、(結合列から)子インスタンスを作成し、( '主テーブルの列から作成された)親インスタンスの_children内の適切な配列に追加しZend_Db_Table_Abstractから_dependantTables_referenceMapを使用しています。次のように子供にアクセス

が行われます:$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つのレベルのためにこれをコード化された親と子が、私はより多くのレベルを処理するために、これを拡張する過程で午前祖父母 - 親 - 子。

関連する問題