Zend中的多个表基于快速入门指南示例

时间:2011-08-15 18:53:00

标签: php zend-framework zend-db-table

我是Zend的新手,并且一直在尝试使用Data Mappers Zend Quick Start Guide's example并扩展Zend_Db_Table_Abstract。我想我已经掌握了一般概念,但我现在想知道,我将如何修改指南的示例代码以允许多个表格。

以下是我目前有兴趣修改的代码部分:

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

这是在数据映射器模式中实现多个表的正确方法,还是以不同方式执行?感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

假设您要从相关表中返回数据,您应该add queries with joins to one Zend_Db_Table或使用Zend_Db_Table_Relationships来获取关联数据。使用联接的好处是,在使用关系时,您只会对多个查询执行一次查询。缺点是连接表不会返回Zend_Db_Table_Row个对象(iirc),但是因为你要将它们映射到你的Domain对象上,所以这不是一个问题。

在结构上,你可以像我在How to change Zend_Db_Table name within a Model to insert in multiple tables中建议的那样做。无论您是创建网关网关还是直接在DataMapper中聚合表网关,都取决于您。按你认为合适的方式撰写。

答案 1 :(得分: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;
    }
}

这是我实施的地图制作者之一:

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