Я работаю над созданием домена в Zend Framework, который отделен от уровня доступа к данным. Уровень доступа к данным состоит из двух основных объектов: шлюза данных данных и шлюза данных строк. Согласно ответу Билла Карвина на этот более ранний вопрос, у меня теперь есть следующий код для моего объекта Person 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) { } }
Однако это работает только с отдельной строкой. Мне также необходимо создать объект домена, который может представлять всю таблицу, и (предположительно) можно использовать для итерации по всему персонажу в таблице и возврата объекта соответствующего типа лица (администратора, покупателя и т. Д.) Для использования. В принципе, я представляю себе что-то вроде следующего:
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; } } }
Это хороший / плохой способ справиться с этой конкретной проблемой? Какие улучшения или корректировки я должен внести в общий дизайн?
Заранее благодарим за ваши комментарии и критику.
Я имел в виду, что вы бы использовали класс Domain Model, чтобы полностью скрыть тот факт, что вы используете таблицу базы данных для сохранения. Поэтому передача объекта таблицы или объекта 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, eg 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, в то время как «искатели» традиционно связаны с материалами базы данных. Мы пытаемся создать модель домена, чтобы притворяться, что в ней нет базы данных.
«И продолжаете ли вы использовать ту же логику для реализации конкретных методов getBy и getCollectionBy?»
Я бы сопротивлялся созданию общего getBy()
, потому что соблазн заставить его принять обобщенное выражение SQL, а затем передать его объектам доступа к данным дословно. Это связывает использование нашей модели домена с базовым представлением базы данных.