tres servidor separacion programacion patron niveles multicapa codigo cliente capas arquitectura php zend-framework orm

php - servidor - patron n capas



¿Cómo diseñar objetos de capa de dominio para representar objetos múltiples y un solo objeto en Zend Framework? (1)

Estoy trabajando en la creación de una capa de dominio en Zend Framework que está separada de la capa de acceso a datos. La capa de acceso a datos se compone de dos objetos principales, una puerta de enlace de datos de tabla y una puerta de enlace de datos de fila. Según la respuesta de Bill Karwin a esta pregunta anterior , ahora tengo el siguiente código para mi objeto Person de dominio:

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

Sin embargo, esto solo funciona con una fila individual. También necesito crear un objeto de dominio que pueda representar toda la tabla y (presumiblemente) se puede usar para iterar a través de todas las personas en la tabla y devolver el tipo apropiado de objeto de persona (administrador, comprador, etc.) para su uso. Básicamente, imagino algo como lo siguiente:

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

¿Esta es una buena / mala forma de manejar este problema en particular? ¿Qué mejoras o ajustes debo hacer en el diseño general?

Gracias de antemano por sus comentarios y críticas.


Tenía en mente que usaría la clase del Modelo de dominio para ocultar por completo el hecho de que está usando una tabla de base de datos para la persistencia. Por lo tanto, pasar un objeto Table o un objeto Row debe estar completamente cubierto:

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

"Pensé que los métodos estáticos eran malos y es por eso que estaba tratando de crear los métodos a nivel de tabla como métodos de instancia".

No creo en ninguna afirmación general de que la static siempre sea mala, o que los singletons siempre sean malos, o que goto siempre sea malo, o lo que sea. Las personas que hacen declaraciones tan inequívocas buscan simplificar demasiado los problemas. Use las herramientas de idioma de manera adecuada y serán buenos para usted.

Dicho esto, a menudo hay una compensación cuando eliges una construcción de un idioma, hace que sea más fácil hacer algunas cosas mientras que es más difícil hacer otras cosas. La gente a menudo apunta a la static lo que dificulta escribir código de prueba unitario, y también PHP tiene algunas deficiencias molestas relacionadas con la estática y la subclasificación. Pero también hay ventajas, como vemos en este código. Tienes que juzgar por ti mismo si las ventajas superan las desventajas, caso por caso.

"¿Sería Zend Framework compatible con una clase de Finder?"

No creo que sea necesario.

"¿Hay alguna razón particular por la que haya cambiado el nombre del método de búsqueda para obtener en la clase de modelo?"

Llamé al método get() solo para ser distinto de find() . El paradigma "captador" se asocia con las interfaces OO, mientras que los "buscadores" se asocian tradicionalmente con las cosas de la base de datos. Estamos tratando de diseñar el Modelo de Dominio para pretender que no hay una base de datos involucrada.

"¿Y utilizarías continuar usando la misma lógica para implementar métodos específicos getBy y getCollectionBy?"

Me resistiría a crear un método getBy() genérico, porque es tentador hacer que acepte una expresión SQL genérica y luego pasarlo a los objetos de acceso a los datos al pie de la letra. Esto combina el uso de nuestro Modelo de Dominio con la representación de la base de datos subyacente.