diff --git a/docs/guide-es/README.md b/docs/guide-es/README.md index 1242fe4b55..a1a0428c40 100644 --- a/docs/guide-es/README.md +++ b/docs/guide-es/README.md @@ -62,7 +62,7 @@ Conceptos clave * [Componentes](concept-components.md) * [Propiedades](concept-properties.md) -* **TBD** [Eventos](concept-events.md) +* [Eventos](concept-events.md) * [Comportamientos (Behaviors)](concept-behaviors.md) * [Configuraciones](concept-configurations.md) * [Alias](concept-aliases.md) @@ -72,12 +72,16 @@ Conceptos clave Trabajar con bases de datos ------------------------------ +--------------------------- -* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y manipulación de esquemas -* **TBD** [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de abstracción -* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y definición de relaciones -* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en equipo +* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y + manipulación de esquemas +* **TBD** [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de + abstracción +* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y + definición de relaciones +* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en + equipo * **TBD** [Sphinx](db-sphinx.md) * **TBD** [Redis](db-redis.md) * **TBD** [MongoDB](db-mongodb.md) @@ -195,5 +199,4 @@ Clases auxiliares * **TBD** [ArrayHelper](helper-array.md) * **TBD** [Html](helper-html.md) * **TBD** [Url](helper-url.md) -* **TBD** [Security](helper-security.md) - +* **TBD** [Security](helper-security.md) \ No newline at end of file diff --git a/docs/guide-es/concept-events.md b/docs/guide-es/concept-events.md new file mode 100644 index 0000000000..b02ec8893f --- /dev/null +++ b/docs/guide-es/concept-events.md @@ -0,0 +1,291 @@ +Eventos +======= + +Los eventos permiten inyectar código dentro de otro código existente en ciertos puntos de ejecución. Se pueden adjuntar +código personalizado a un evento, cuando se lance (triggered), el código se ejecutará automáticamente. Por ejemplo, un +objeto `mailer` puede lanzar el evento `messageSent` cuando se envía un mensaje correctamente. Si se quiere rastrear +el correcto envío del mensaje, se puede, simplemente, añadir un código de seguimiento al evento `messageSent`. + +Yii introduce una clase base [[yii\base\Component]] para soportar eventos. Si una clase necesita lanzar un evento, +este debe extender a [[yii\base\Component]] o a una clase hija. + +Gestor de Eventos +----------------- + +Un gestor de eventos es una +[llamada de retorno PHP (PHP callback)](http://php.net/manual/es/language.types.callable.php) que se ejecuta cuando se +lanza el evento al que corresponde. Se puede usar cualquier llamada de retorno de las enumeradas a continuación: + +- una función de PHP global especificada como una cadena de texto (sin paréntesis), p. ej. `'trim'`; +- un método de objeto especificado como un array de un objeto y un nombre de método como una cadena de texto + (sin paréntesis), p. ej. `[$object, 'methodNAme']`; +- un método de clase estático especificado como un array de un nombre de clase y un método como una cadena de texto + (sin paréntesis), p. ej. `[$class, 'methodName']`; +- una función anónima, p. ej. `function ($event) { ... }`. + +La firma de un gestor de eventos es: + +```php +function ($event) { + // $event es un objeto de yii\base\Event o de una clase hija +} +``` + +Un gestor de eventos puede obtener la siguiente información acerca de un evento ya sucedido mediante el parámetro +`$event`: + +- [[yii\base\Event::name|event name]] +- [[yii\base\Event::sender|event sender]]: el objeto desde el que se ha ejecutado `trigger()` +- [[yii\base\Event::data|custom data]]: los datos que se proporcionan al adjuntar el gestor de eventos + (se explicará más adelante) + +Añadir Gestores de Eventos +-------------------------- + +Se puede añadir un gestor a un evento llamando al método [[yii\base\Component::on()]]. Por ejemplo: + +```php +$foo = new Foo; + +// este gestor es una función global +$foo->on(Foo::EVENT_HELLO, 'function_name'); + +// este gestor es un método de objeto +$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']); + +// este gestor es un método de clase estática +$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']); + +// este gestor es una función anónima +$foo->on(Foo::EVENT_HELLO, function ($event) { + // event handling logic +}); +``` + +También se pueden adjuntar gestores de eventos mediante [configuraciones](concept-configurations.md). Se pueden +encontrar más de talles en la sección [Configuraciones](concept-configurations.md#configuration-format). + +Cuando se adjunta un gestor de eventos, se pueden proporcionar datos adicionales como tercer parámetro de +[[yii\base\Component::on()]]. El gestor podrá acceder a los datos cuando se lance el evento y se ejecute el gestor. +Por ejemplo: + +```php +// El siguiente código muestra "abc" cuando se lanza el evento +// ya que $event->data contiene los datos enviados en el tercer parámetro de "on" +$foo->on(Foo::EVENT_HELLO, 'function_name', 'abc'); + +function function_name($event) { + echo $event->data; +} +``` + +Ordenación de Gestores de Eventos +--------------------------------- + +Se puede adjuntar uno o más gestores a un único evento. Cuando se lanza un evento, se ejecutarán los gestores adjuntos +en el orden que se hayan añadido al evento. Si un gestor necesita parar la invocación de los gestores que le siguen, +se puede establecer la propiedad [[yii\base\Event::handled]] del parámetro `$event` para que sea `true`: + +```php +$foo->on(Foo::EVENT_HELLO, function ($event) { + $event->handled = true; +}); +``` + +De forma predeterminada, cada nuevo gestor añadido se pone a la cola de la lista de gestores del evento. Por lo tanto, +el gestor se ejecutará en el último lugar cuando se lance el evento. Para insertar un nuevo gestor al principio de la +cola de gestores para que sea ejecutado primero, se debe llamar a [[yii\base\Component::on()]], pasando al cuarto +parámetro `$append` el valor `false`: + +```php +$foo->on(Foo::EVENT_HELLO, function ($event) { + // ... +}, $data, false); +``` + +Lanzamiento de Eventos +---------------------- + +Los eventos se lanzan llamando al método [[yii\base\Component::trigger()]]. El método requiere un *nombre de evento*, +y de forma opcional un objeto de evento que describa los parámetros que se enviarán a los gestores de eventos. Por +ejemplo: + +```php +namespace app\components; + +use yii\base\Component; +use yii\base\Event; + +class Foo extends Component +{ + const EVENT_HELLO = 'hello'; + + public function bar() + { + $this->trigger(self::EVENT_HELLO); + } +} +``` + +Con el código anterior, cada llamada a `bar()` lanzará un evento llamado `hello` + +> Consejo: Se recomienda usar las constantes de clase para representar nombres de eventos. En el anterior ejemplo, la + constante `EVENT_HELLO` representa el evento `hello`. Este enfoque proporciona tres beneficios. Primero, previene + errores tipográficos. Segundo, puede hacer que los IDEs reconozcan los eventos en las funciones de auto-completado. + Tercero, se puede ver que eventos soporta una clase simplemente revisando la declaración de constantes. + +A veces cuando se lanza un evento se puede querer pasar información adicional al gestor de eventos. Por ejemplo, un +`mailer` puede querer enviar la información del mensaje para que los gestores del evento `messageSent` para que los +gestores puedan saber las particularidades del mensaje enviado. Para hacerlo, se puede proporcionar un objeto de tipo +evento como segundo parámetro al método [[yii\base\Component::trigger()]]. El objeto de tipo evento debe ser una +instancia de la clase [[yii\base\Event]] o de sus hijas. Por ejemplo: + +```php +namespace app\components; + +use yii\base\Component; +use yii\base\Event; + +class MessageEvent extends Event +{ + public $message; +} + +class Mailer extends Component +{ + const EVENT_MESSAGE_SENT = 'messageSent'; + + public function send($message) + { + // ...enviando $message... + + $event = new MessageEvent; + $event->message = $message; + $this->trigger(self::EVENT_MESSAGE_SENT, $event); + } +} +``` + +Cuando se lanza el método [[yii\base\Component::trigger()]], se ejecutarán todos los gestores adjuntos al evento. + +Desadjuntar Gestores de Evento +------------------------------ + +Para desadjuntar un gestor de un evento, se puede ejecutar el método [[yii\base\Component::off()]]. Por ejemplo: + +```php +// el gestor es una función global +$foo->off(Foo::EVENT_HELLO, 'function_name'); + +// el gestor es un método de objeto +$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']); + +// el gestor es un método estático de clase +$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']); + +// el gestor es una función anónima +$foo->off(Foo::EVENT_HELLO, $anonymousFunction); +``` + +Tenga en cuenta que en general no se debe intentar desadjuntar las funciones anónimas a no ser que se almacene donde +se ha adjuntado al evento. En el anterior ejemplo, se asume que la función anónima se almacena como variable +`$anonymousFunction`. + +Para desadjuntar TODOS los gestores de un evento, se puede llamar [[yii\base\Component::off()]] sin el segundo +parámetro: + +```php +$foo->off(Foo::EVENT_HELLO); +``` + +Nivel de Clase (Class-Level) Gestores de Eventos +------------------------------------------------ + +En las subsecciones anteriores se ha descrito como adjuntar un gestor a un evento a *nivel de instancia*. A veces, se +puede querer que un gestor responda todos los eventos de *todos* las instancias de una clase en lugar de una instancia +especifica. En lugar de adjuntar un gestor de eventos a una instancia, se puede adjuntar un gestor a *nivel de clase* +llamando al método estático [[yii\base\Event::on()]]. + +Por ejemplo, un objeto de tipo [Active Record](db-active-record.md) lanzará un evento +[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] cada vez que inserte un nuevo registro en la base +de datos. Para poder registrar las inserciones efectuadas por *todos* los objetos +[Active Record](db-active-record.md), se puede usar el siguiente código: + +```php +use Yii; +use yii\base\Event; +use yii\db\ActiveRecord; + +Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { + Yii::trace(get_class($event->sender) . ' is inserted'); +}); +``` + +Se invocará al gestor de eventos cada vez que una instancia de [[yii\db\ActiveRecord|ActiveRecord]], o de uno de sus +clases hijas, lance un evento de tipo [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]]. Se puede +obtener el objeto que ha lanzado el evento mediante `$event->sender` en el gestor. + +Cuando un objeto lanza un evento, primero llamará los gestores a nivel de instancia, y a continuación los gestores a +nivel de clase. + +Se puede lanzar un evento de tipo *nivel de clase* llamando al método estático [[yii\base\Event::trigger()]]. Un +evento de nivel de clase no se asocia a un objeto en particular. Como resultado, esto provocará solamente la +invocación de los gestores de eventos a nivel de clase. + +```php +use yii\base\Event; + +Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) { + echo $event->sender; // displays "app\models\Foo" +}); + +Event::trigger(Foo::className(), Foo::EVENT_HELLO); +``` + +Tenga en cuenta que en este caso, el `$event->sender` hace referencia al nombre de la clase que lanza el evento en +lugar de a la instancia del objeto. + +> Nota: Debido a que los gestores a nivel de clase responderán a los eventos lanzados por cualquier instancia de la +clase, o cualquier clase hija, se debe usar con cuidado, especialmente en las clases de bajo nivel (low-level), tales +como [[yii\base\Object]]. + +Para desadjuntar un gestor de eventos a nivel de clase, se tiene que llamar a [[yii\base\Event::off()]]. Por ejemplo: + +```php +// desadjunta $handler +Event::off(Foo::className(), Foo::EVENT_HELLO, $handler); + +// desadjunta todos los gestores de Foo::EVENT_HELLO +Event::off(Foo::className(), Foo::EVENT_HELLO); +``` + +Eventos Globales +---------------- + +Yii soporta los llamados *eventos globales*, que en realidad es un truco basado en el gestor de eventos descrito +anteriormente. El evento global requiere un Singleton globalmente accesible, tal como la instancia de +[aplicación](structure-applications.md) en si misma. + +Para crear un evento global, un evento remitente (event sender) llama al método `trigger()` del Singleton para lanzar +el evento, en lugar de llamar al propio método `trigger()` del remitente. De forma similar, los gestores de eventos se +adjuntan al evento del Singleton. Por ejemplo: + +```php +use Yii; +use yii\base\Event; +use app\components\Foo; + +Yii::$app->on('bar', function ($event) { + echo get_class($event->sender); // muestra "app\components\Foo" +}); + +Yii::$app->trigger('bar', new Event(['sender' => new Foo])); +``` + +Un beneficio de usar eventos globales es que no se necesita un objeto cuando se adjuntan gestores a un evento para que +sean lanzados por el objeto. En su lugar, los gestores adjuntos y el lanzamiento de eventos se efectúan en el +Singleton (p. ej. la instancia de la aplicación). + +Sin embargo, debido a que los `namespaces` de los eventos globales son compartidos por todas partes, se les deben +asignar nombres bien pensados, como puede ser la introducción de algún `namespace` +(p. ej. "frontend.mail.sent", "backend.mail.sent").