【问题标题】:How to Establish Multiple Table Inheritance in the Domain using Zend Framework?Zend框架如何在域中建立多表继承?
【发布时间】:2010-09-27 09:36:07
【问题描述】:

我有一个数据库结构,它有一个 Person 表,其中包含诸如姓名、电子邮件、company_id、personType 等字段。因为不是所有的人都必须是系统用户的,所以我有一个单独的表用户,它为系统中的用户定义了用户名和密码。

我有以下代码来为 Person 表定义表数据网关:

class Model_Table_Person extends Zend_Db_Table_Abstract
{
    protected $_name = 'person';
    protected $_primary = 'person_id';

    protected $_referenceMap = array(
        'Company' =>    array(
            'columns' => 'company_id',
            'refTableClass' => 'Company',
            'refColumns' => 'id'
        ),
        'Store' =>  array(
            'columns' => 'store_id',
            'refTableClass' => 'Store',
            'refColumns' => 'id'
        )
    );

    public function findByPersonType(string $personType)
    {
        $where = $this->getAdapter()->quoteInto('personType = ?', $personType);
        return $this->fetchAll($where);
    }
}

这段代码定义了 Person 的域对象:

class Model_Person
{
    protected static $_gateway;

    protected $_person;

    public static function init()
    {
        if(self::$_gateway == null)
        {
            self::$_gateway = new Model_Table_Person();
        }
    }

    public static function get(string $searchString, string $searchType = 'id') 
    {
        self::init();

        switch($searchString)
        {
            case 'id':
                $row = self::$_gateway->find($id)->current();
                break;
        }

        return self::factory($row);
    }

    public static function getCollection(string $searchString, string $searchType = null)
    {
        self::init();

        switch($searchType)
        {
            case 'userType':
                $row = self::$_gateway->findByPersonType($searchString);
                break;
            default:
                $personRowset = self::$_gateway->fetchAll();
                break;
        }

        $personArray = array ();

        foreach ($personRowset as $person)
        {
            $personArray[] = self::factory($person);
        }

        return $personArray;
    }

    public function getCompany()
    {
        return $this->_person->findParentRow('Company');
    }

    public function getStore()
    {
        return $this->_person->findParentRow('Store');
    }

    protected static function factory(Zend_Db_Table_Row $row) 
    {
        $class = 'Model_Person_' . ucfirst($row->personType);
        return new $class($row);
    }

    // protected constructor can only be called from this class, e.g. factory()
    protected function __construct(Zend_Db_Table_Row $personRow)
    {
        $this->_person = $personRow;
    }
}

最后,我有另一个用户表数据网关:

class Model_Table_User extends Zend_Db_Table_Abstract
{
    protected $_name = 'user';
    protected $_primary = 'person_id';

    public function findByUserName()
    {

    }
}

还有一个像这样扩展 Model_Person 表的基本类:

class Model_User extends Model_Person
{       
    public function login()
    {

    }

    public function setPassword()
    {

    }   
}

如何正确扩展“Model_User”类(它为除一个以外的所有其他类型的用户提供基本类型)以使用映射到一个表的“Model_Person”类函数,同时映射实际的“Model_User”函​​数要使用第二张桌子吗?

【问题讨论】:

    标签: zend-framework orm multiple-inheritance


    【解决方案1】:

    这是 PHP(5.3.0 之前的版本)的一个巨大弱点——它缺乏对 late static binding 的支持。

    也就是说,当一个静态方法(例如get())调用另一个静态方法(例如init())时,它总是使用该类中定义的init() 方法。如果子类定义了替代方法init() 并调用get(),期望它调用init() 的覆盖版本,则不会发生这种情况。

    class A
    {
      static $var = null;
      static function init() { self::$var = 1234; }
      static function get() { self::init(); }
    }
    
    class B extends A
    {
      static function init() { self::$var = 5678; }
    }
    
    B::get();
    print B::$var . "\n"; 
    

    这将打印“1234”,而您可能希望它打印“5678”。就好像A::get() 不知道它是B 类的一部分。解决方法是您必须将get() 方法的实现复制到子类中,即使它与超类没有什么不同。 这很不令人满意

    PHP 5.3.0 尝试解决此问题,但您必须在 get() 中对其进行稍微不同的编码:

    function get() {
      static::init();
    }
    

    PHP 5.3.0 目前仍处于 alpha 版本。


    有几种可能的解决方法:

    • 不要将Person 子类化为User,而是将登录名和密码属性添加到Person 类。如果这些属性为 NULL,那么它是一个非用户的人,函数 login()setPassword() 应该注意这一点并抛出异常或返回 false 或其他东西。

    • 对每个子类型使用不同的 get() 方法:getUser()getPerson() 等。每一个都将初始化各自的 Table 对象。

    【讨论】:

    • 你会设计不同的 User 和 Person 类之间的关系吗?我想尝试这种扩展 Model_Person 类的方法,然后为 User 对象实现第二个 $_gateway 对象,但它似乎并没有很好地结合在一起。
    • 我想我已经决定我需要使用 User 和 Person 表的 $_referenceMap 来定义 User 表中数据的使用,而不是尝试创建某种多网关继承?这或多或少听起来正确吗?
    • 是的,我感觉 PHP 语言目前不支持您尝试执行的操作。毕竟你可能需要一个工厂类。
    猜你喜欢
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 2012-02-28
    • 1970-01-01
    相关资源
    最近更新 更多