Çoklu Nesneler ve Temsil Domain Katman nesneleri Tasarım Nasıl

1 Cevap php

Ben veri erişim katmanı ayrı Zend Framework bir etki katmanı oluşturmaya çalışıyorum. Veri Erişim Katmanı iki ana nesneler, bir Tablo Veri Ağ Geçidi ve Satır Veri Gateway oluşmaktadır. Bill Karwin en cevapta başına this earlier question Şimdi benim alanı Person nesnesi için aşağıdaki kodu var:

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)
    {

    }
}

Bununla birlikte, bu, sadece tek bir satır ile çalışır. Ben de tüm tabloyu temsil edebilir ve (muhtemelen) Kişinin tablosundaki tüm yineleme ve kullanımı için kişinin uygun tip (yönetici, alıcı, vb) nesne döndürmek için kullanılabilecek bir etki alanı nesnesi oluşturmak gerekir. Temelde, ben aşağıdaki gibi bir şey öngörülüyor:

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

Bu belirli bir sorunu ele almak iyi / kötü bir yoldur mi? Ne iyileştirmeler ve ayarlamalar ben genel tasarımı yapmak gerekir?

Görüş ve eleştiriler için şimdiden teşekkür ederiz.

1 Cevap

Ben tamamen Eğer sebat için bir veritabanı tablosu kullanıyorsanız gerçeği gizlemek için Alan Modeli sınıfını kullanmak istiyorsunuz aklınızda vardı. Yani Tablo nesnesi geçen veya bir satır nesne tamamen kapakların altında olmalıdır:

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

"I thought static methods were bad which is why I was trying to create the table level methods as instance methods."

I static her zaman kötü, ya da tekil her zaman kötü, ya goto her zaman kötü olduğunu, ya da ne olduğuna dair herhangi bir battaniye deyimi içine almayın. Böyle kesin bir beyanda İnsanlar sorunları basite arıyoruz. Uygun dil araçlarını kullanın ve onlar sizin için iyi olacak.

İşte o başka şeyler yapmak zor iken daha kolay bazı şeyleri yapmak için yapar, bir dil yapısı seçtiğinizde bir takas sık sık var, dedi. İnsanlar genelde static zor birim test kodu yazmak için, ve aynı zamanda PHP statik ve subclassing ilgili bazı can sıkıcı eksiklikler vardır hale gelin. Bu kodda Fakat gördüğünüz gibi avantajları da vardır. Sen avantajlar vaka bazında bir durumda, dezavantajları daha ağır olup olmadığını kendiniz için hakim var.

"Would Zend Framework support a Finder class?"

Bunun gerekli olduğunu sanmıyorum.

"Is there a particular reason that you renamed the find method to be get in the model class?"

Sadece find() farklı olması için yöntem get() adlandırılır. "Ölçme" geleneksel veritabanı malzeme ile ilişkili iken "alıcı" paradigma, OO arayüzleri ile ilişkilidir. Biz dahil hiçbir veri tabanı yok taklit Domain Model tasarımı çalışıyoruz.

"And would you use continue to use the same logic to implement specific getBy and getCollectionBy methods?"

Ben bunu genel bir SQL ifadesi kabul ettirmek için cazip, çünkü genel bir getBy() yöntem oluşturarak karşı, ve sonra birebir veri erişim nesneleri onu geçerdi. Bu çiftler temel veritabanı temsile Domain Modelin kullanımı.