Как спроектировать объекты слоя домена для представления нескольких объектов и одного объекта в Zend Framework? - PullRequest
6 голосов
/ 17 декабря 2008

Я работаю над созданием слоя домена в Zend Framework, который отделен от слоя доступа к данным. Уровень доступа к данным состоит из двух основных объектов: шлюза табличных данных и шлюза данных строк. Согласно ответу Билла Карвина на этот предыдущий вопрос Теперь у меня есть следующий код для моего объекта Person объекта:

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 в таблице и возврата объекта использования соответствующего типа (администратор, покупатель и т. Д.) Для использования. По сути, я представляю что-то вроде следующего:

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

Это хороший / плохой способ справиться с этой конкретной проблемой? Какие улучшения или корректировки я должен внести в общий дизайн?

Заранее спасибо за ваши комментарии и критику.

1 Ответ

9 голосов
/ 17 декабря 2008

Я имел в виду, что вы будете использовать класс Domain Model, чтобы полностью скрыть тот факт, что вы используете таблицу базы данных для сохранения. Таким образом, передача объекта Table или Row должна быть полностью закрыта:

<?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 класс? "

Не думаю, что это необходимо.

"Есть ли конкретная причина, по которой вы переименовал метод поиска, чтобы получить в модель класса? "

Я назвал метод get(), чтобы отличаться от find(). Парадигма «getter» связана с интерфейсами OO, в то время как «finders» традиционно связаны с базой данных. Мы пытаемся разработать модель предметной области так, чтобы она притворялась, что в ней нет базы данных.

"А вы бы продолжали использовать та же логика для реализации конкретного getBy и методы getCollectionBy? "

Я бы не стал создавать универсальный метод getBy(), потому что заманчиво заставить его принять универсальное выражение SQL, а затем передать его дословно объектам доступа к данным. Это связывает использование нашей доменной модели с базовым представлением базы данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...