2009-03-02 16 views
9

Soy relativamente nuevo en programación orientada a objetos. Entiendo bastante bien los conceptos, pero, en términos prácticos, estoy teniendo dificultades para encontrar información sobre cómo usar mejor los Modelos en mis aplicaciones de Zend Framework.Zend Framework: uso de modelos y vistas, mejores prácticas

Específicamente, tengo un modelo (que no extiende nada) que no utiliza una tabla de base de datos. Utiliza getters y setters para acceder a sus miembros protegidos. Me encuentro luchando con la mejor manera de mostrar este modelo en la vista. No quiero que la lógica de mis plantillas de vista, pero me encuentro en la siguiente situación:

En mi controlador:

$object = new Object(); 
$object->setName('Foo Bar'); 
$this->view->object = $object; 

En mi plantilla de vista:

<h2><?= $this->object->getName() ?></h2> 

I don' Realmente me gusta llamar funciones en mis plantillas de vista, pero no conozco una mejor manera de hacerlo. No quiero que los miembros de mi modelo a ser pública, pero básicamente quiero lograr los mismos resultados:

<h2><?= $this->object->name ?></h2> 

Yo no quiero que mi controlador para hacer todo el trabajo de tener que saber todo sobre el modelo:

$object = new Object(); 
$object->setName('Foo Bar'); 
$this->view->object = $object; 
$this->view->object->name = $object->getName(); 

¿Cuál es la mejor práctica de usar modelos en Zend Framework? ¿Alguien puede recomendar algún tutorial que me ayude a entender este dilema de Modelo/Vista en Zend Framework?

Respuesta

4

Una posibilidad es utilizar los métodos mágicos __set y __get en PHP.Los uso como tal dentro de mi clase abstracta del modelo:

abstract class Model_Abstract 
{ 
    protected $_data; 

    // Private Data Members assigned to protected $_data 
    public function __construct($data = null) 
    { 
     // Makes it so that I can pass in an associative array as well as 
     // an StdObject. 
     if(!is_object($data)) { 
      $data = (object) $data; 
     } 

     $this->_data = $data; 

    } 

    public function __get($key) 
    { 
     if (method_exists($this, '_get' . ucfirst($key))) { 
      $method = '_get' . ucfirst($key); 
      return $this->$method();    
     } 
     else { 
      return $this->_data->$key; 
     } 
    } 

    public function __set($key, $val) 
    { 
     if (method_exists($this, '_set' . ucfirst($key))) { 
      $method = '_set' . ucfirst($key); 
      return $this->$method($val);    
     } 
     else { 
      $this->_data->$key = $val; 
      return $this->_data->$key; 
     } 
    } 
} 


class Model_User extends Model_Abstract 
{ 
    //Example overriding method for the property firstName in the $_data collection. 
    protected function _getFirstName() 
    { 
     // Do some special processing and then output the first name. 
    } 
} 

Esto hace que sea para que pueda especificar captadores y definidores de las propiedades según sea necesario, pero lo hace de modo que usted no tiene que definir funciones de caldera para cada propiedad , solo aquellos en los que desea hacer algún tipo de procesamiento antes de devolver el valor. Por ejemplo, uso la funcionalidad en varios lugares para cambiar las fechas conformes con ISO (como las almacenadas en MySQL) en un formato más compacto y legible para los usuarios.

En cuanto a lo que debe colocar en su controlador, le recomendaría que consulte this post para obtener información específica sobre qué manejo colocar dentro de su controlador.

Algunos sienten que preferirían tener un ayudante que automáticamente carga modelos en la vista y bordea el controlador por completo. Personalmente, diría que dentro del contexto de Zend Framework y PHP tiene mucho sentido pasar modelos a la vista desde el controlador porque el estado de los modelos en la vista depende con frecuencia de lo que proviene de la solicitud (que definitivamente debería manejarse). en el controlador).

Actualización: De acuerdo con las críticas en los comentarios, una cosa que me gustaría señalar es que su capa de acceso a la base de datos y el dominio (o modelo) de capa son en realidad dos cosas diferentes, aunque con el Active Record que se mezclan . Hace un tiempo pedí this question y recibí algunos comentarios útiles sobre este asunto. Independientemente de lo que decida hacer con el modelo, querrá proporcionar una API consistente para todos los objetos de dominio, independientemente de dónde provengan los datos para el modelo.

Supongo que uno de los beneficios que ofrece la respuesta de Saem es que ofrece la capacidad de mapear directamente propiedades/valores de retorno de función de uno o más objetos de dominio al objeto de vista. En teoría, el uso dentro de la vista, entonces se ve así:

// Mapped from Model_User::_data->last_name and Model_User::_data->first_name 
$this->name 
+1

Esta es una manera pobre de hacer las cosas. No solo le da acceso arbitrario a todas las propiedades, ya sean las que deben ser (un) serializadas a/desde un formulario o no, sino que también sobrecarga el modelo con el concepto de mapeo, que es lo que realmente se solicitó. – Saem

+0

Poner la lógica de formulario en el modelo mezcla la vista y el modelo, que también es de mala calidad. Y como ya he mencionado, anular el comportamiento predeterminado es muy simple y evita la necesidad de crear captadores y ejecutores de texto estándar estúpidos. –

+0

Y si observas la clase Zend_Db_Table_Row, verás que Zend en realidad usa un principio similar para exponer los campos y sus valores de las tablas. –

3

Si solo otros desarrolladores van a trabajar con las plantillas, recomendaría simplemente pasar los modelos. Aquí hay un enlace a una publicación de Jeff Atwood en MVC Understanding Model-View-Controller

3

Esto no está especialmente orientado al framework Zend, pero el problema es bastante general, en mi opinión.

Parece que está en el camino correcto, en lugar de cablear el modelo a la vista, dentro del controlador. Prefiere tener ese resumen, especialmente importante si está mapeando una tonelada de modelos, o mapeando el mismo modelo una y otra vez.

Algo simple sería escribir un montón de funciones de mapeo, lo cual estaría bien si lo único que se evita es mapear lo mismo una y otra vez.

Si desea una solución más general, que también aborde evitar escribir el código de la placa de la caldera, y mantener las cosas más SECAS, sugiero crear una clase de correlacionador.

Podría crear un ViewModelMapper, que tomaría un modelo o algunos modelos y los mapearía a la vista.

class ViewModelMapper 
{ 
    public function __construct($view) 
    { 
     //set the properties 
    } 

    public function addModel($model, $overrideViewProperty = null) 
    { 
     //add the model to the list of models to map, use the view's property 
     // name to figure out what to map it to? Allow for an override just in case. 
    } 

    public function getMappedView() 
    { 
     //take the view, map all the models 
    } 
} 

A continuación, podría ejemplo esta en el controlador, y la configuración de las asignaciones, por lo que el controlador controla el mapeo todavía, pero toda la placa de la caldera y la lógica de codificación está centralizada, para todos los mapas de controlador, a excepción de las raras excepciones .

+0

Proporcione un ejemplo relevante que use esta clase de Mapper. En este momento, todo lo que veo es una forma de hacer que agregar Modelos a la Vista sea más complejo. –

1

Para una buena lectura de la arquitectura del modelo, read this post. No habla específicamente sobre la vista, pero definitivamente vale la pena leerla.

Terminé agregando una función getViewClass() a mis modelos. El controlador llama a esta función para obtener las variables protegidas a las que de otra manera no tendría acceso, y la vista no tiene que preocuparse de llamar a ningún getter.

//controller 
$object = new Object(); 
$object->setName('Foo Bar'); 
$this->view->object = $object->getViewClass(); 

//view template 
<h2><?= $this->object->name ?></h2> 

No sé si hay una mejor manera de hacer el trabajo en el Zend Framework, pero esto es una solución.

Cuestiones relacionadas