Creando objetos Yii FormModel (CFormModel) dinámicamente

Estoy trabajando en una aplicación que implica generar formularios con un alto nivel de abstracción (es una aplicación CMS). Quiero crear dinámicamente objetos CFormModel y establecer los campos de formulario sobre la marcha. Creo que puedo hacer esto extendiendo CFormModel y luego creando dinámicamente las propiedades de clase que representan los campos de formulario ("atributos" en la jerga de Yii).

Para ilustrar, en lugar de especificar un formulario de inicio de sesión en la siguiente clase (definida en un archivo):

// From: http://www.yiiframework.com/doc/guide/1.1/en/form.model
class LoginForm extends CFormModel
{
    public $username;
    public $password;
    public $rememberMe=false;

    private $_identity;

    public function rules()
    {
        return array(
            array('username, password', 'required'),
            array('rememberMe', 'boolean'),
            array('password', 'authenticate'), // assume function authenticate defined elsewhere
        );
    }
}

Quiero hacerlo de la siguiente manera:

class MyFormModel extends CFormModel {

    protected $_rules = array();

    public function __construct($attributes=array(), $rules=array()) {

        foreach ($attributes as $i => $attr) {
            $this->{$attr} = ???; // <<== This is the key here
        }

        // pass in array of rules as described in Yii doc for CFormModel
        $this->_rules = $rules;
    }

    public function rules() {
        return $_rules;
    }
}

E invóquelo cuando sea necesario de la siguiente manera:

$myModelObj = new MyFormModel($attr, $rules);

donde:

$attr = array(
            'username',
            'rememberMe',
            'password',
        );
$rules = array(
            array('username, password', 'required'),
            array('rememberMe', 'boolean'),
            array('password', 'authenticate'), // assume function authenticate defined elsewhere
        );

Tenga en cuenta lo que estoy tratando de lograr, no hay "LoginClass" escrito en ningún archivo, se crea sobre la marcha en el código.

Esto me permitiría crear formularios (en vistas) haciendo cosas como esta:

// based on http://www.yiiframework.com/doc/guide/1.1/en/form.view
<?php echo $wForm->textField($myModelObj,'username'); ?>

etc.

Intenté esto, y la línea $this->{$attr} está fallando con:

Property "MyFormModel.username" is not defined.

En realidad, el código para esa línea es solo:

$this->{$attr};

Él ??? indica que no estoy realmente seguro de qué asignar a esto. En los ejemplos de documentos de Yii, simplemente definen los campos como variables de clase pública.

¿Debería usar métodos mágicos?

¿Es posible lo que estoy tratando de hacer aquí?

preguntado el 04 de julio de 12 a las 00:07

1 Respuestas

Como probablemente sepas, Yii usa sobrecarga de programación orientada a objetos para resolver sus propiedades similares a AR.

Lo que debe hacer aquí es similar a lo que Yii hace internamente.

Defina una propiedad codificada para almacenar todas sus propiedades personalizadas como una matriz: $_data

y estos datos serán una matriz y contendrán todos los atributos que agregó en tiempo de ejecución. Es posible que deba desafiar la validación sobrescribiendo los métodos mágicos (establecedores, captadores, isset) como lo hace Yii, para resolver primero los nombres de propiedad DESDE su $_data titular de la propiedad

Algún tipo de código que encontrará en CAActiveRecord busca todos esos __XXX como métodos.

Si duplica el manejo de la propiedad AR en su clase personalizada, todo esto se ejecutará a su nivel y volverá a Yii cuando sus métodos mágicos no lo resuelvan.

También buscaría en Comportamientos, ya que puede delegar muchas funciones comunes a una clase de comportamiento.

Uso del comportamiento de los componentes

Un componente es compatible con Mixin patrón y se puede adjuntar con uno o varios comportamientos. Un comportamiento es un objeto cuyos métodos pueden ser "heredados" por su componente adjunto mediante la recopilación de funciones en lugar de la especialización (es decir, la herencia de clase normal). Un componente se puede adjuntar con varios comportamientos y así lograr una 'herencia múltiple'.

Las clases de comportamiento deben implementar el IBehavior interfaz. La mayoría de los comportamientos pueden extenderse desde CBehavior clase base. Si un comportamiento necesita estar asociado a un modelo, también puede extenderse desde CModelBehaviorCModelBehavior or CActiveRecordBehavior que implementa características adicionales específicas para los modelos.

Para usar un comportamiento, primero debe adjuntarse a un componente llamando al comportamiento attach() método. Entonces podemos llamar a un método de comportamiento a través del componente:

// $name uniquely identifies the behavior in the component
$component->attachBehavior($name,$behavior);
// test() is a method of $behavior
$component->test();

Se puede acceder a un comportamiento adjunto como una propiedad normal del componente. Por ejemplo, si un comportamiento llamado árbol se adjunta a un componente, podemos obtener la referencia a este objeto de comportamiento usando:

$behavior=$component->tree;
// equivalent to the following:
// $behavior=$component->asa('tree');

Un comportamiento se puede deshabilitar temporalmente para que sus métodos no estén disponibles a través del componente. Por ejemplo,

$component->disableBehavior($name);
// the following statement will throw an exception
$component->test();
$component->enableBehavior($name);
// it works now
$component->test();

Es posible que dos comportamientos adjuntos al mismo componente tengan métodos del mismo nombre. En este caso, prevalecerá el método del primer comportamiento adjunto.

Cuando se usa junto con Eventos, los comportamientos son aún más poderosos. Un comportamiento, cuando se adjunta a un componente, puede adjuntar algunos de sus métodos a algunos eventos del componente. Al hacerlo, el comportamiento tiene la oportunidad de observar o cambiar el flujo de ejecución normal del componente.

También se puede acceder a las propiedades de un comportamiento a través del componente al que está adjunto. Las propiedades incluyen tanto las variables miembro públicas como las propiedades definidas mediante captadores y / o definidores del comportamiento. Por ejemplo, si un comportamiento tiene una propiedad llamada xyz y el comportamiento está asociado a un componente $ a. Entonces podemos usar la expresión $a->xyz para acceder a la propiedad del comportamiento.

Más lectura:
http://www.yiiframework.com/wiki/44/behaviors-events
http://www.ramirezcobos.com/2010/11/19/how-to-create-a-yii-behavior/

Respondido 04 Jul 12, 07:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.