2008-12-17 68 views
6

我正在創建Zend Framework中與數據訪問層分離的領域層。數據訪問層由兩個主要對象組成,一個是表格數據網關和一個行數據網關。按照比爾Karwin的答覆this earlier question我現在有下面的代碼爲我的域Person對象:如何設計域層對象來表示Zend框架中的多個對象和單個對象?

class Model_Row_Person 
{ 
    protected $_gateway; 

    public function __construct(Zend_Db_Table_Row $gateway) 
    { 
     $this->_gateway = $gateway; 
    } 

    public function login($userName, $password) 
    { 

    } 

    public function setPassword($password) 
    { 

    } 
} 

然而,這僅與單獨的行工作。我還需要創建一個可以表示整個表的域對象,並且(大概)可以用來遍歷表中的所有Person,並返回適當類型的人(admin,buyer等)對象以供使用。基本上,我想像如下:

class Model_Table_Person implements SeekableIterator, Countable, ArrayAccess 
{ 
    protected $_gateway; 

    public function __construct(Model_DbTable_Person $gateway) 
    { 
     $this->_gateway = $gateway; 
    } 

    public function current() 
    { 
     $current = $this->_gateway->fetchRow($this->_pointer); 

     return $this->_getUser($current); 
    } 

    private function _getUser(Zend_Db_Table_Row $current) 
    { 
     switch($current->userType) 
     { 
      case 'admin': 
       return new Model_Row_Administrator($current); 
       break; 
      case 'associate': 
       return new Model_Row_Associate($current); 
       break; 
     } 
    } 
} 

這是處理這個特定問題的好/壞方法?我應該對整體設計進行哪些改進或調整?

在此先感謝您的意見和批評。

回答

9

我記住,您將使用Domain Model類來完全隱藏您正在使用數據庫表進行持久化的事實。因此,通過一個表對象或行對象應該是完全在幕後:

<?php 
require_once 'Zend/Loader.php'; 
Zend_Loader::registerAutoload(); 

$db = Zend_Db::factory('mysqli', array('dbname'=>'test', 
    'username'=>'root', 'password'=>'xxxx')); 
Zend_Db_Table_Abstract::setDefaultAdapter($db); 

class Table_Person extends Zend_Db_Table_Abstract 
{ 
    protected $_name = 'person'; 
} 

class Model_Person 
{ 
    /** @var Zend_Db_Table */ 
    protected static $table = null; 

    /** @var Zend_Db_Table_Row */ 
    protected $person; 

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

    protected static function factory(Zend_Db_Table_Row $personRow) { 
     $personClass = 'Model_Person_' . ucfirst($personRow->person_type); 
     return new $personClass($personRow); 
    } 

    public static function get($id) { 
     self::init(); 
     $personRow = self::$table->find($id)->current(); 
     return self::factory($personRow); 
    } 

    public static function getCollection() { 
     self::init(); 
     $personRowset = self::$table->fetchAll(); 
     $personArray = array(); 
     foreach ($personRowset as $person) { 
      $personArray[] = self::factory($person); 
     } 
     return $personArray; 
    } 

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

    public function login($password) { 
     if ($this->person->password_hash == 
      hash('sha256', $this->person->password_salt . $password)) { 
      return true; 
     } else { 
      return false; 
     } 

    } 

    public function setPassword($newPassword) { 
     $this->person->password_hash = hash('sha256', 
      $this->person->password_salt . $newPassword); 
     $this->person->save(); 
    } 
} 

class Model_Person_Admin extends Model_Person { } 
class Model_Person_Associate extends Model_Person { } 

$person = Model_Person::get(1); 
print "Got object of type ".get_class($person)."\n"; 
$person->setPassword('potrzebie'); 

$people = Model_Person::getCollection(); 
print "Got ".count($people)." people objects:\n"; 
foreach ($people as $i => $person) { 
    print "\t$i: ".get_class($person)."\n"; 
} 

「我認爲靜態方法是壞 這就是爲什麼我試圖創建 表級方法爲實例 方法「。

我不買任何毯子聲明static總是不好的,或者單身都是壞的,或goto總是不好的,或者你有什麼。做出如此明確陳述的人們希望將問題過分簡單化。適當地使用語言工具,他們會對你很好。

也就是說,當你選擇一種語言結構時,通常會進行權衡,這使得做一些事情變得更容易,而做其他事情變得更加困難。人們經常指出static使得編寫單元測試代碼變得困難,並且PHP也有一些與靜態和子類相關的惱人的缺陷。但是也有一些優點,就像我們在這段代碼中看到的那樣。您必須親自判斷這些優點是否超過了缺點,並且是逐個案例分析的。

「Zend Framework是否支持Finder 類?」

我不認爲這是必要的。

「有你 改名find方法將得到 模型類特殊的原因?」

我將方法get()命名爲與find()截然不同。 「getter」範例與OO接口相關聯,而「finders」傳統上與數據庫相關。我們試圖設計領域模型來假裝沒有涉及數據庫。

「你會用繼續使用 相同的邏輯來實現特定getBy 和getCollectionBy方法?」

我會抗拒創建一個通用的getBy()的方法,因爲這是很有誘惑力,使其接受一個通用的SQL表達式,然後把它傳遞給數據訪問對象一字不差。這將我們的領域模型的使用與底層數據庫表示相結合。

+0

順便說一句,我用這個練習來學習如何在新的NetBeans 6.5中編寫PHP代碼。它岩石! – 2008-12-17 01:34:39