Yii2 framework backup
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

13 KiB

Comportamientos

Comportamientos son instancias de yii\base\Behavior o sus clases "hija". Comportamientos, también conocido como mixins, te permiten mejorar la funcionalidad de un yii\base\Component existente sin necesidad de modificar su herencia de clases. Cuando un comportamiento se une a un componente, "inyectará" sus métodos y propiedades dentro del componente, y podrás acceder a esos métodos y propiedades como si hubieran estado definidos por la clase de componente. Además, un comportamiento puede responder a eventos disparados por el componente de modo que se pueda personalizar o adaptar a la ejecución normal del código del componente.

Usando comportamientos

Para poder utilizar un comportamiento, primero tienes que unirlo a un yii\base\Component. Describiremos cómo puedes vincular un comportamiento en la próxima sub-sección.

Una vez que el comportamiento ha sido vinculado a un componente, su uso es sencillo.

Puedes usar a una variable pública o a una propiedad definida por un getter y/o un setter del comportamiento a través del componente con el que se ha vinculado, como por ejemplo,

// "prop1" es una propiedad definida en la clase comportamiento
echo $component->prop1;
$component->prop1 = $value;

También puedes llamar métodos públicos del comportamiento de una forma similar,

// bar() es un método público definido dentro de la clase comportamiento
$component->bar();

Como puedes ver, aunque $component no tiene definida prop1 y bar(), pueden ser usadas como si fueran parte definida del componente.

Si dos comportamientos definen la misma propiedad o método y ambos están vinculados con el mismo componente, el comportamiento que ha sido vinculado primero tendrá preferencia cuando se esté accediendo a la propiedad o método.

Un comportamiento puede estar asociado con un nombre cuando se une a un componente. Si este es el caso, es posible acceder al objeto de comportamiento mediante el nombre, como se muestra a continuación,

$behavior = $component->getBehavior('myBehavior');

También puedes acceder a todos los comportamientos vinculados al componente:

$behaviors = $component->getBehaviors();

Vinculando Comportamientos

Puedes vincular un comportamiento a un yii\base\Component ya sea estática o dinámicamente. La primera forma es la más comúnmente utilizada en la práctica.

Para unir un comportamiento estáticamente, reemplaza el método yii\base\Component::behaviors() de la clase componente que se está conectando. Por ejemplo,

namespace app\models;

use yii\db\ActiveRecord;
use app\components\MyBehavior;

class User extends ActiveRecord
{
    public function behaviors()
    {
        return [
            // comportamiento anónimo, sólo el nombre de la clase del comportamiento
            MyBehavior::className(),

            // comportamiento nombrado, sólo el nombre de la clase del comportamiento
            'myBehavior2' => MyBehavior::className(),

            // comportamiento anónimo, matriz de configuración
            [
                'class' => MyBehavior::className(),
                'prop1' => 'value1',
                'prop2' => 'value2',
            ],

            // comportamiento nombrado, matriz de configuración
            'myBehavior4' => [
                'class' => MyBehavior::className(),
                'prop1' => 'value1',
                'prop2' => 'value2',
            ]
        ];
    }
}

El método yii\base\Component::behaviors() tiene que devolver la lista de los comportamientos configuraciones. Cada configuración de un comportamiento puede ser el nombre de la clase o una matriz de configuración.

Puedes asociciar un nombre a un comportamiento especificándolo en la clave de la matriz correspondiente a la configuración del comportamiento. En este caso, el comportamiento puede ser llamado un comportamiento nombrado (named behavior). En el ejemplo anterior, hay dos tipos de comportamientos nombrados: myBehavior2 y myBehavior4. Si un comportamiento no está asociado con un nombre, se le llama comportamiento anónimo (anonymous behavior).

Para vincular un comportamiento dinámicamente, llama al método yii\base\Component::attachBehavior() desde el componente al que se le va a unir el comportamiento. Por ejemplo,

use app\components\MyBehavior;

// vincular un objeto comportamiento "behavior"
$component->attachBehavior('myBehavior1', new MyBehavior);

// vincular una clase comportamiento
$component->attachBehavior('myBehavior2', MyBehavior::className());

// asociar una matriz de configuración
$component->attachBehavior('myBehavior3', [
    'class' => MyBehavior::className(),
    'prop1' => 'value1',
    'prop2' => 'value2',
]);

You may attach multiple behaviors at once by using the yii\base\Component::attachBehaviors() method. For example,

$component->attachBehaviors([
    'myBehavior1' => new MyBehavior,  // a named behavior
    MyBehavior::className(),          // an anonymous behavior
]);

También puedes asociar comportamientos a traves de configuraciones compor el siguiente ejemplo. Para más detalles, por favor visita la sección Configuraciones.

[
    'as myBehavior2' => MyBehavior::className(),

    'as myBehavior3' => [
        'class' => MyBehavior::className(),
        'prop1' => 'value1',
        'prop2' => 'value2',
    ],
]

Desasociar Comportamientos

Para desasociar un comportamiento, puedes llamar el método yii\base\Component::detachBehavior() con el nombre con el que se le asoció:

$component->detachBehavior('myBehavior1');

También puedes desvincular todos los comportamientos:

$component->detachBehaviors();

Definiendo Comportamientos

Para definir un comportamiento, crea una clase extendendiéndola de yii\base\Behavior o una de sus clases "hija". Por ejemplo,

namespace app\components;

use yii\base\Model;
use yii\base\Behavior;

class MyBehavior extends Behavior
{
    public $prop1;

    private $_prop2;

    public function getProp2()
    {
        return $this->_prop2;
    }

    public function setProp2($value)
    {
        $this->_prop2 = $value;
    }

    public function foo()
    {
        // ...
    }
}

El código anterior define la clase del comportamiento app\components\MyBehavior que provee dos propiedades prop1 y prop2, y un método foo() al componente con el que está asociado.

The above code defines the behavior class app\components\MyBehavior which will provide two properties prop1 and prop2, and one method foo() to the component it is attached to. Fíjese que la propiedad prop2 esta definida a través del getter getProp2() y el setter setProp2(). Esto es debido a que yii\base\Object es una clase "ancestro" (o padre) de yii\base\Behavior, la cual soporta la definición de propiedades por getters/setters.

En un comportamiento, puedes acceder al componente al que está vinculado a través de la propiedad yii\base\Behavior::owner.

Si un omportamiento necesita responder a los eventos que han sido disparados desde el componente al qu están asociados, debería sobreescribir el método yii\base\Behavior::events(). Por ejemplo,

namespace app\components;

use yii\db\ActiveRecord;
use yii\base\Behavior;

class MyBehavior extends Behavior
{
    // ...

    public function events()
    {
        return [
            ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
        ];
    }

    public function beforeValidate($event)
    {
        // ...
    }
}

El método yii\base\Behavior::events() tiene que devolver un listado de eventos y sus correspondientes controladores (handlers). El código anterior declara el evento yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE con su controlador beforeValidate(). Cuando se especifica un controlador de evento, pudes utilizar uno de los siguientes formatos:

  • una cadena que se refiere al nombre de un método de la clase comportamiento, como el ejemplo anterior;
  • una matriz con un objeto o nombre de la clase, y el nombre de un método, por ejemplo, [$object, 'nombreMétodo'];
  • una función anónima.

El formato de un controlador de eventos tendría que ser como se describe a continuación, donde $event se refiere al parámetro evento. Por favor, visita la sección Eventos para obtener más información acerca de eventos.

function ($event) {
}

Utilizando TimestampBehavior

Para terminar, vamos a echar un vistazo a yii\behaviors\TimestampBehavior - un comportamiento que soporta de forma automática la actualización de atributos timestamp (sellos de tiempo) de un yii\db\ActiveRecord (Active Record) cuando éste está siendo guardado.

Primero, vincula este comportamiento a la clase yii\db\ActiveRecord que desees utilizar.

namespace app\models\User;

use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;

class User extends ActiveRecord
{
    // ...

    public function behaviors()
    {
        return [
            [
                'class' => TimestampBehavior::className(),
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
                    ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
                ],
            ],
        ];
    }
}

La configuración del comportamiento anterior especifica que

  • cuando el registro está siendo insertado, el comportamiento debe asignar el sello de tiempo actual a los atributos created_at y updated_at;
  • cuando el registro está siendo actualizado, el comportamiento debe asignar el sello de tiempo actual al atributo `updated_at.

Ahora si tienes un objeto User e intentas guardarlo, descubrirás que sus campos created_at y updated_at están automáticamente actualizados con el sello de tiempo actual:

$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at;  // muestra el sello tiempo actual (timestamp)

El comportamiento yii\behaviors\TimestampBehavior también ofrece un método muy útil llamado yii\behaviors\TimestampBehavior::touch(), que asigna el sello de tiempo actual a un atributo especificado y lo guarda automáticamente en la base de datos:

$user->touch('login_time');

Comparación con Traits

Mientras que los comportamientos son similares a traits en cuanto que ambos "inyectan" sus métodos y propiedades a la clase primaria, son diferentes en muchos aspectos. Tal y como se describe abajo, los dos tienen sus ventajas y desventajas. Son much mejor descritos como complementos y no como reemplazos entre sí.

Las Ventajas de los Comportamientos

Las clases de comportamientos (Behaviors), como todas las clases, soportan herencias. Traits, por otro lado, pueden ser considerados como un copia-y-pega de PHP. Los Traits no soportan la herencia de clases.

Los comportamientos pueden ser asociados y desasociados a un componente dinámicamente sin necesidad de que la clase del componente sea modificada. Para usar un trait, debes modificar la clase que la usa.

Los comportamientos son configurables mientras que los traits no.

Los comportamientos pueden personalizar la ejecución de un componente al responder a sus eventos.

Cuando hay un conflicto de nombre entre los diferentes comportamientos vinculados a un mismo componente, el conflicto es automáticamente resuelto respetando al que ha sido asociado primero. El conflicto de nombres en traits requiere que manualmente sean resueltos cambiando el nombre de las propiedades o métodos afectados.

Las Ventajas de los Traits

Los Traits son mucho más eficientes que los comportamientos debido a que los últimos son objetos que consumen tiempo y memoria.

Los IDEs (Programas de desarrollo) trabajan mucho mejor con traits ya que forman parte del lenguaje PHP.