2011-08-15 18 views
2

私はZendには新しく、Zend Quick Start Guide's exampleのデータマッパーを使用し、Zend_Db_Table_Abstractを拡張しようとしています。私は一般的な概念を把握していると思いますが、私は現在、複数のテーブルを使用できるようにガイドのサンプルコードを変更する方法について不思議です。ここでクイックスタートガイドに基づくZend内の複数のテーブルの例

は、私は現在、修正に興味を持ってコードの一部です:

protected $_dbTable; 

public function setDbTable($dbTable) 
{ 
    if (is_string($dbTable)) { 
     $dbTable = new $dbTable(); 
    } 
    if (!$dbTable instanceof Zend_Db_Table_Abstract) { 
     throw new Exception('Invalid table data gateway provided'); 
    } 
    $this->_dbTable = $dbTable; 
    return $this; 
} 

public function getDbTable() 
{ 
    if (null === $this->_dbTable) { 
     $this->setDbTable('Application_Model_DbTable_Guestbook'); 
    } 
    return $this->_dbTable; 
} 

私はこれにそれを変更しました:

protected $_dbTables; 

public function setDbTable($dbTable, $tableName) 
{ 
    if (is_string($dbTable)) { 
     $dbTable = new $dbTable(); 
    } 
    if (!$dbTable instanceof Zend_Db_Table_Abstract) { 
     throw new Exception('Invalid table data gateway provided'); 
    } 
    $this->_dbTables[$tableName] = $dbTable; 
    return $this; 
} 

public function getDbTables() 
{ 
    if (null === $this->_dbTables) { 
     $this->setDbTable('Application_Model_DbTable_Courses', 'courses'); 
     $this->setDbTable('Application_Model_DbTable_CourseTimes', 'course_times'); 
    } 
    return $this->_dbTables; 
} 

が、これは複数のテーブルを実装については移動するための正しい方法ですデータマッパーのパターン内にあるか、別の方法でそれを行いますか?事前にあなたの助けをありがとう!

+0

私のここでのロジックは、MVCパターンの無知に起因するわずかな欠陥であることがわかりました。この質問の私の提案された解決策は、実際にはマッパーごとに1つのテーブルしか存在しないので、良いものではありません。複数の同時挿入が必要な場合は、コントローラから呼び出すか、別のモデルを使用して呼び出す必要があります。 – Dan

答えて

1

関連するテーブルからデータを返すと仮定すると、add queries with joins to one Zend_Db_Tableか、Zend_Db_Table_Relationshipsを使用して関連データを取得する必要があります。結合を使用する利点は、リレーションシップを使用するときに多くのクエリに対して1つのクエリしか実行しないことです。欠点は、結合されたテーブルはZend_Db_Table_Rowオブジェクト(iirc)を返しませんが、あなたがドメインオブジェクトにそれらをマップすることになるので、それほど大きな問題ではありません。

構造的には、How to change Zend_Db_Table name within a Model to insert in multiple tablesで提案したようにすることができます。ゲートウェイのゲートウェイを作成するか、単にDataMapperにテーブルゲートウェイを集約するかは、あなた次第です。あなたが合っていると思うようにそれらを構成してください。

+0

ありがとう、私はSELECT文ではなくINSERTについて考えていました。はい、それは2つの関連するテーブルです。私はあなたがこれについて提案した方法のいずれかを使用することができるとは思わない? Zend_Db_Table_Relationshipsのドキュメントでは、「カスケードINSERTはサポートされていません。ある操作で親テーブルに行を挿入し、別の操作で依存テーブルに行を挿入する必要があります。 – Dan

+0

私の答えを確認してくださいあなたの考えを教えてください。 –

+0

@Gordonあなたの受け入れられた答え[ここ](http://stackoverflow.com/questions/2436461/how-to-change-zend-db-table-name-within-a-model-to-insert-in-multipleテーブルごとに1つずつ、Zend_Db_Table_Abstractという2つのインスタンスを作成することを提案しました。実際にどこから私の最初のアイデアを得たのですか?これは、データマッパーが使用されていないか、このメソッドをもはや推奨していないためですか? – Dan

1

私はそれが最善の方法だかどうかわからないんだけど、これは私の抽象マッパーです:

<?php 
abstract class Zf_Model_DbTable_Mapper 
{ 
    protected $_db; 
    protected $_dbTable = null; 

    protected $_systemLogger = null; 
    protected $_userLogger = null; 

    public function __construct() 
    { 
     $this->_systemLogger = Zend_Registry::get('systemLogger'); 
     $this->_userLogger = Zend_Registry::get('userLogger'); 

     // Set the adapter 
     if(null !== $this->_dbTable) 
     { 
      $tableName = $this->_dbTable; 
      $this->_db = $this->$tableName->getAdapter(); 
     } 
    } 

    public function __get($value) 
    { 
     if(isset($this->$value)) 
     { 
      return $this->$value; 
     } 

     $dbTable = 'Model_DbTable_' . $value; 
     $mapper = 'Model_' . $value; 

     if(class_exists($dbTable)) 
     { 
      return new $dbTable; 
     } 
     elseif(class_exists($mapper)) 
     { 
      return new $mapper; 
     } 
     else 
     { 
      throw new Exception("The property, DbTable or Mapper \"$value\" doesn't exists");  
     } 
    } 

    public function __set($key,$value) 
    { 
     $this->$key = $value; 
    } 

    public function getById($id) 
    { 
     $resource = $this->getDefaultResource(); 

     $id = (int)$id; 
     $row = $resource->fetchRow('id =' . $id); 

     if (!$row) { 
      throw new Exception("Count not find row $id"); 
     } 

     return $row;  
    } 

    public function getAll() 
    { 
     $resource = $this->getDefaultResource(); 

     return $resource->fetchAll()->toArray();  
    } 

    public function save(Zf_Model $Model) 
    { 
     $dbTable = $this->getDefaultResource(); 
     $data = $Model->toArray(); 

     if(false === $data) return false; 

     if(false === $Model->isNew()) 
     { 
       if(1 == $dbTable->update($data, 'id =' . (int)$Model->getId())) 
       { 
        return $Model; 
       } 
     } 
     else 
     {  
      $id = $dbTable->insert($data); 

      if($id) 
      { 
       $Model->setId($id); 
       return $Model; 
      } 
     } 

     return false; 
    } 

    public function remove($id) 
    { 
     return $this->getDefaultResource()->delete('id =' . (int) $id); 
    } 

    protected function getDefaultResource() 
    { 
     if(empty($this->_dbTable)) 
     { 
      throw new Exception('The $_dbTable property was not set.'); 
     } 

     $classname = 'Model_DbTable_' . $this->_dbTable; 
     if(!class_exists($classname)) 
     { 
      throw new Exception("The Model_DbTable_\"$classname\" class was not found."); 
     } 


     return new $classname; 
    } 

    protected function getDefaultModel() 
    { 
     return current($this->_models); 
    } 

    protected function getResources() 
    { 
     return $this->_resources; 
    } 
} 

そして、これが私の実装マッパーのための1つである:

<?php 
class Model_TwitterPostsMapper extends Zf_Model_DbTable_Mapper 
{ 
    /* 
    * Data Source 
    * @var string Zend_Db_Table name 
    */ 
    protected $_dbTable = 'TwitterPosts'; 

    public function recordExists($Item) 
    { 
     $row = $this->TwitterPosts->fetchRow($this->TwitterPosts->select()->where('status_id =?', $Item->getSource()->getStatusId())); 
     if($row) 
     { 
      return $row->id; 
     } 

     return false; 
    } 

    public function getLastUpdate($options) 
    { 
     $select = $this->TwitterPosts->select() 
         ->setIntegrityCheck(false) 
         ->from(array('t' => 'twt_tweets'), 't.created_at') 
         ->join(array('u' => 'twt_users'), 't.user_id = u.id', '') 
         ->order('t.created_at DESC'); 

     if($options['user_id']) 
     { 
      $select->where("t.user_id = ?", $options['user_id']); 
     } 

     if($options['terms']) 
     { 
      if(is_array($options['terms'])) 
      { 
       $condition = ''; 
       foreach($options['terms'] as $i => $term) 
       { 
        $condition .= ($i > 0) ? ' OR ' : ''; 
        $condition .= $this->getAdapter()->quoteInto('content LIKE ?',"%$term%"); 
       } 

       if($condition) 
       { 
        $select->where($condition); 
       } 
      } 
     } 

     return $this->TwitterPosts->fetchRow($select)->created_at; 
    } 

    public function getSinceId($term = null) 
    { 
     $select = $this->TwitterPosts->select()->setIntegrityCheck(false) 
         ->from('twt_tweets_content', 'status_id') 
         ->where('MATCH(content) AGAINST(? IN BOOLEAN MODE)', "$term") 
         ->order('status_id ASC') 
         ->limit(1); 
     //echo $select; exit; 

     $tweet = $this->TwitterPosts->fetchRow($select); 

     if(null !== $tweet) return $tweet->status_id; 

     return 0; 
    } 

    public function getAllByStatusId($statuses_id) 
    { 
     $select = $this->TwitterPosts->select() 
         ->setIntegrityCheck(false) 
         ->from(array('t' => 'twt_tweets'), array('t.id', 't.user_id', 't.status_id','t.user_id')) 
         ->join(array('u' => 'twt_users'), 't.user_id = u.id', array('u.screen_name', 'u.profile_image')) 
         ->where('status_id IN(?)', $statuses_id); 

     $rows = $this->TwitterPosts->fetchAll($select); 

     $Posts = array(); 
     foreach($rows as $row) 
     { 
      // Here we populate the models only with the specific method return data 
      $data = $row->toArray(); 

      $Post = new Model_TwitterPost($data['id']); 
      $Post->populate($data); 

      $User = new Model_TwitterUser($data['user_id']); 
      $User->populate($data); 

      $Post->setUser($User); 
      $Posts[] = $Post; 
     } 

     return $Posts; 
    } 

    public function getAllSince($since_id) 
    { 
     $select = $this->TwitterPosts->select() 
         ->setIntegrityCheck(false) 
         ->from(array('t' => 'twt_tweets'), array('t.status_id','t.user_id')) 
         ->join(array('u' => 'twt_users'), 't.user_id = u.id', array('u.screen_name', 'u.profile_image')) 
         ->where('status_id > ?', $since_id) 
         ->order('t.datetime DESC'); 

     $rows = $this->TwitterPosts->fetchAll($select); 

     $Posts = array(); 
     foreach($rows as $row) 
     { 
      // Here we populate the models only with the specific method return data 
      // TODO: This is not a truly lazy instatiation, since there's no way to get the not setted properties 
      $data = $row->toArray(); 
      $Post = new Model_TwitterPost($data); 
      $User = new Model_TwitterUser($data); 
      $Post->setUser($User); 
      $Posts[] = $Post; 
     } 

     return $Posts; 
    } 

    public function getTotalRatedItems($options) 
    { 
     $options = $this->prepareOptions($options); 

     $select = $this->TwitterPosts->select() 
         ->setIntegrityCheck(false) 
         ->from(array('t' => 'twt_tweets'), array('COUNT(DISTINCT t.id) AS total','r.rate')) 
         ->join(array('u' => 'twt_users'), 't.user_id = u.id', '') 
         ->join(array('r' => 'twt_tweets_rate'), 't.id = r.tweet_id', array('r.rate')) 
         ->group('r.rate') 
         ->order('t.datetime DESC'); 

     $select = $this->prepareSelect($select, $options); 

     $rates = $this->TwitterPosts->fetchAll($select)->toArray(); 

     $itemsRated = array('Green' => 0, 'Yellow' => 0, 'Orange' => 0, 'Red' => 0, 'Gray' => 0); 
     foreach ($rates as $rate) 
     { 
      $itemsRated[$rate['rate']] = $rate['total']; 
     } 

     return $itemsRated; 
    } 

    public function getUsersActivity($options) 
    { 
     $options = $this->prepareOptions($options); 

     $select = $this->TwitterPosts->select() 
         ->setIntegrityCheck(false) 
         ->from(array('t' => 'twt_tweets'), array('COUNT(DISTINCT t.id) AS total','DATE(t.datetime) AS datetime')) 
         ->join(array('u' => 'twt_users'), 't.user_id = u.id', '') 
         ->joinLeft(array('r' => 'twt_tweets_rate'), 't.id = r.tweet_id', '') 
         ->group('t.user_id') 
         ->order('t.datetime DESC'); 

     $select = $this->prepareSelect($select, $options); 

     $activity = $this->TwitterPosts->fetchAll($select)->toArray(); 

     return $activity; 
    } 

    public static function prepareOptions($options) 
    { 
     if(!is_array($options)) 
     { 
      $options = array(); 
     } 

     date_default_timezone_set('America/Sao_Paulo'); 

     if(Zend_Date::isDate($options['start_date'])) 
     { 
      $date = new Zend_Date($options['start_date']); 
      $date->setTime('00:00:00'); 
      $date->setTimezone('UTC'); 

      $options['start_date'] = $date->toString('yyyy-MM-dd HH:mm:ss'); 
     } 

     if(Zend_Date::isDate($options['end_date'])) 
     { 
      $date = new Zend_Date($options['end_date']); 
      $date->setTime('23:59:59'); 
      $date->setTimezone('UTC'); 

      $options['end_date'] = $date->toString('yyyy-MM-dd HH:mm:ss'); 
     } 

     date_default_timezone_set('UTC'); 

     $options['mainTerms'] = array(); 
     if(!empty($options['terms']) && !is_array($options['terms'])) 
     { 
      $options['mainTerms'] = explode(' ', $options['terms']);  
     } 

     if(!is_array($options['terms'])) 
     { 
      $options['terms'] = array(); 
     } 

     if($options['group_id'] || $options['client_id']) 
     { 
      $TwitterSearches = new Model_DbTable_TwitterSearches(); 

      $options['terms'] = array_merge($TwitterSearches->getList($options),$options['terms']); 

      if(empty($options['terms'])) 
      { 
       $options['terms'] = array(); 
      } 
     } 

     return $options; 
    } 

    public static function prepareSelect($select, $options) 
    { 
     if($options['start_date']) 
     { 
      $select->where('t.datetime >= ?', $options['start_date']); 
     } 

     if($options['end_date']) 
     { 
      $select->where('t.datetime <= ?', $options['end_date']); 
     } 

     foreach($options['mainTerms'] as $mainTerm) 
     { 
      $select->where('t.content LIKE ?', "%$mainTerm%"); 
     } 

     if($options['user_id']) 
     { 
      $select->where("t.user_id = ?", $options['user_id']); 
     } 

     if($options['terms']) 
     { 
      $select->where('MATCH (t.content) AGASINT(?)', $options['terms']); 
     } 

     if($options['rate']) 
     { 
      if($options['rate'] == 'NotRated') 
      { 
       $select->where('r.rate IS NULL'); 
      } 
      else 
      { 
       $select->where('r.rate = ?', $options['rate']); 
      } 
     } 

     if($options['last_update']) 
     { 
      $select->where('t.created_at > ?', $options['last_update']); 
     } 

     if($options['max_datetime']) 
     { 
      $select->where('t.created_at < ?', $options['max_datetime']); 
     } 

     return $select; 
    } 
} 

モデル:

<?php 
class Model_TwitterPost extends Zf_Model 
{ 
    private $_name = 'twitter'; 

    protected $_properties = array(
     'id', 
     'status_id', 
     'user_id', 
     'content' 
    ); 

    protected $_User = null; 

    public function setUser(Zf_Model $User) 
    { 
     $this->_User = $User; 
    } 

    public function getUser() 
    { 
     return $this->_User; 
    } 

    public function getPermalink() 
    { 
     return 'http://twitter.com/' . $this->screen_name . '/' . $this->status_id; 
    } 

    public function hasTerm($term) 
    { 
     if(preg_match("/\b$term\b/i", $this->getContent())) 
     { 
      return true; 
     } 
     return false; 
    } 

    public function getEntityName() 
    { 
     return $this->_name; 
    } 

    public function getUserProfileLink() 
    { 
     return $this->getUser()->getProfileLink() . '/status/' . $this->getStatusId(); 
    } 
} 

抽象モデル(汎用オブジェクト):

<?php 
abstract class Zf_Model 
{ 
    protected $_properties = array(); 
    protected $_modified = array(); 
    protected $_data = array(); 

    protected $_new = true; 
    protected $_loaded = false; 

    public function __construct($id=false) 
    { 
     $id = (int)$id; 
     if(!empty($id)) 
     { 
      $this->_data['id'] = (int)$id; 
      $this->setNew(false); 
     } 
    } 

    public function populate($data) 
    { 
     if(is_array($data) && count($data)) 
     { 
      foreach($data as $k => $v) 
      { 
       if(in_array($k,$this->_properties)) 
       { 
        $this->_data[$k] = $v; 
       } 
      } 
     } 

     $this->setLoaded(true); 
    } 

    public function setNew($new=true) 
    { 
     $this->_new = (bool)$new; 
    } 

    public function isNew() 
    { 
     return $this->_new; 
    } 

    public function setLoaded($loaded = true) 
    { 
     $this->_loaded = (bool)$loaded; 
    } 

    public function isLoaded() 
    { 
     return $this->_loaded; 
    } 

    public function __call($methodName, $args) { 

     if(method_exists($this, $methodName)) 
     { 
      return $this->$methodName($args); 
     } 

     $property = $methodName; 
     if (preg_match('~^(set|get)(.*)$~', $methodName, $matches)) 
     { 
      $filter = new Zend_Filter_Word_CamelCaseToUnderscore(); 
      $property = strtolower($filter->filter($matches[2])); 

      if(in_array($property, $this->_properties)) 
      { 
       if('set' == $matches[1]) 
       { 
        $this->_data[$property] = $args[0]; 

        if(true === $this->isLoaded()) 
        { 
         $this->_modified[$property] = true; 
        } 

        return $this; 
       } 
       elseif('get' == $matches[1]) 
       { 
        if(array_key_exists($property, $this->_data)) 
        { 
         return $this->_data[$property]; 
        } 

        throw new Exception("The property $property or $methodName() method was not setted for " . get_class($this)); 
       } 
      } 
     } 

     throw new Exception("The property '$property' doesn't exists."); 
    } 

    public function __get($key) 
    { 
     if(isset($this->_data[$key])) 
     { 
      return $this->_data[$key]; 
     } 
     return $this->$key; 
    } 

    public function __set($key,$value) 
    { 
     if(array_key_exists($key,$this->_properties)) 
     { 
      $this->_data[$key] = $value; 
      return; 
     } 

     $this->$key = $value; 
    } 

    public function getId() 
    { 
     return (!$this->_data['id']) ? null : $this->_data['id']; 
    } 

    public function toArray() 
    { 
     // If it's a new object 
     if(true === $this->isNew()) 
     { 
      return $this->_data; 
     } 

     // Else, if it's existing object 
     $data = array(); 
     foreach($this->_modified as $k=>$v) 
     { 
      if($v) 
      { 
       $data[$k] = $this->_data[$k]; 
      } 
     } 

     if(count($data)) 
     { 
      return $data; 
     } 

     return false; 
    } 

    public function reload() 
    { 
     $this->_modified = array(); 
    } 
} 
関連する問題