2008-12-17 15 views
6

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. De acuerdo con la respuesta de Bill Karwin a this earlier question ahora tengo el siguiente código para mi persona objeto de dominio:¿Cómo diseñar objetos de capa de dominio para representar objetos múltiples y un solo objeto en Zend Framework?

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 sólo 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, me 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; 
     } 
    } 
} 

es que esto es así bueno/malo para 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.

Respuesta

9

Tenía en mente que utilizaría la clase de Modelo de dominio para ocultar por completo el hecho de que está utilizando una tabla de base de datos para la persistencia. Por lo que pasa un objeto de tabla o un objeto de fila debe estar completamente bajo las sábanas:

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

"Creo que los métodos estáticos eran malos razón por la cual yo estaba tratando de crear los métodos a nivel de tabla como ejemplo métodos "

Yo no creo en ninguna declaración general que static siempre es malo, o hijos únicos son siempre malas, o goto siempre es 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 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 static por lo que es difícil escribir código de prueba de la unidad, y también PHP tiene algunas deficiencias molestas relacionadas con estática y subclases. 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.

"Would Zend Framework support a Finder class?"

No creo que sea necesario.

"¿Hay alguna razón en particular que cambió el nombre del método find a ser ponerse en la clase del modelo?"

He llamado el método get() para que sea 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 usaría seguir utilizando la misma lógica para implementar getBy y métodos getCollectionBy específico?"

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

+0

Por cierto, utilicé esto como un ejercicio para aprender a codificar PHP en el nuevo NetBeans 6.5. ¡Oscila! –

+0

Dos preguntas: 1) Pensé que los métodos estáticos eran malos, por eso intentaba crear los métodos de tabla como métodos de instancia. ¿Zend Framework admitiría una clase Finder? –

+0

2) ¿Existe alguna razón particular por la que haya cambiado el nombre del método de búsqueda para obtener en la clase de modelo? ¿Y utilizarías continuar usando la misma lógica para implementar métodos específicos getBy y getCollectionBy? –

Cuestiones relacionadas