2008-12-17 40 views
2

我有一個數據庫結構有一個Person表,其中包含諸如名稱,電子郵件,company_id,personType等字段。因爲不是所有的人都必須是系統用戶的,所以我有一個單獨的表用戶爲系統中的用戶定義了用戶名和密碼。如何使用Zend Framework在域中建立多個表繼承?

我有以下代碼來定義表數據網關爲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); 
    } 
} 

而這個代碼定義爲個人域對象:

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」函​​數映射爲使用第二個表?

回答

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版本目前。


有幾個可能的解決方法:

  • 不要繼承PersonUser,而是添加用戶名和密碼屬性的Person類。如果這些屬性是NULL,那麼它是非用戶的人,功能login()setPassword()應該注意這一點,並拋出一個異常或返回false或其他東西。

  • 使用每亞型不同get()方法:getUser()getPerson()等。每個這些將初始化它自己相應的表對象。

+0

你會設計User和Person類之間的關係嗎?我想要嘗試擴展Model_Person類的這種方法,然後爲User對象實現第二個$ _gateway對象,但它似乎並沒有很好地結合在一起。 – 2008-12-17 19:41:59