@@ -12,7 +12,7 @@ Registra el [[yii\base\Application::errorHandler|error handler]].
Inicializa las propiedades de aplicación usando la configuración de la aplicación dada.
Llama a [[yii\base\Application::init()|init()]] que a su vez llama a [[yii\base\Application::bootstrap()|bootstrap()]] para ejecutar componentes de bootstrapping.
Incluye el archivo de manifiesto de extensiones ‘vendor/yiisoft/extensions.php’
Crea y ejecuta [compoentenes de bootstrap](structure-extensions.md#bootstrapping-classes) declarados por las extensiones.
Crea y ejecuta [componentes de bootstrap](structure-extensions.md#bootstrapping-classes) declarados por las extensiones.
Crea y ejecuta [componentes de aplicación](structure-application-components.md) y/o [módulos](structure-modules.md) que se declaran en la [propiedad bootstrap](structure-applications.md#bootstrap) de la aplicación.
Debido a que el trabajo de bootstrapping se tiene que ejecutar antes de gestionar *todas* las peticiones, es muy importante mantener este proceso ligero y optimizado lo máximo que sea posible.
Yii incluye un [[yii\web\ErrorHandler|error handler]] que permite una gestión de errores mucho más práctica que
...
...
@@ -87,7 +87,7 @@ personalizar la visualización de los errores.
### Uso de Acciones de Error <a name="using-error-actions"></a>
Una mejor manera de personalizar la visualizacion de errores es usar un [acción](structure-controllers.md) de error
Una mejor manera de personalizar la visualización de errores es usar un [acción](structure-controllers.md) de error
dedicada. Para hacerlo, primero se debe configurar la propiedad [[yii\web\ErrorHandler::errorAction|errorAction]] del
componente `errorHandler` como en el siguiente ejemplo:
...
...
@@ -127,7 +127,7 @@ class SiteController extends Controller
```
El código anterior define la acción `error` usando la clase [[yii\web\ErrorAction]] que renderiza un error usando la
la vista llamada `error`.
vista llamada `error`.
Además, usando [[yii\web\ErrorAction]], también se puede definir la acción `error` usando un método de acción como en
el siguiente ejemplo,
...
...
@@ -156,7 +156,11 @@ a las siguientes variables si se define el error como un [[yii\web\ErrorAction]]
### Personalizar el Formato de Respuesta de Error <a name="error-format"></a>
El gestor de errores muestra los errores de siguiente la configuración del formato de las
[respuestas](runtime-responses.md). Si el [[yii\web\Response::format response format]] es `html`, se usará la vista de error o excepción para mostrar los errores tal y como se ha descrito en la anterior subsección. Para otros tipos de formatos de respuesta, el gestor de errores asignara la representación del array de la excepción a la propiedad [[yii\web\Response::data]] que posteriormente podrá convertirse al formato deseado. Por ejemplo, si el formato de respuesta es `json`, obtendremos la siguiente respuesta:
[respuestas](runtime-responses.md). Si el [[yii\web\Response::format response format]] es `html`, se usará la vista de
error o excepción para mostrar los errores tal y como se ha descrito en la anterior subsección. Para otros tipos de
formatos de respuesta, el gestor de errores asignara la representación del array de la excepción a la propiedad
[[yii\web\Response::data]] que posteriormente podrá convertirse al formato deseado. Por ejemplo, si el formato de
respuesta es `json`, obtendremos la siguiente respuesta:
Se puede personalizar el formato de respuestas de error respondiendo al evento `beforeSend` del componente `response` en la configuración de la aplicación:
Se puede personalizar el formato de respuestas de error respondiendo al evento `beforeSend` del componente `response`
Cada vez que una aplicación Yii gestiona una petición, se somete a un flujo de trabajo similar.
1. Un usuario hace una petición al [script de entrada](structure-entry-scripts.md) ‘web/index.php’.
2. El script de entrada carga la [configuración](concept-configurations.md) y crea una instancia de la [aplicación](structure-applications.md) para gestionar la petición.
3. La aplicación resuelve la [ruta](runtime-routing.md) solicitada con la ayuda del componente [petición](runtime-requests.md) de la aplicación.
2. El script de entrada carga la [configuración](concept-configurations.md) y crea una instancia de la
[aplicación](structure-applications.md) para gestionar la petición.
3. La aplicación resuelve la [ruta](runtime-routing.md) solicitada con la ayuda del componente
[petición](runtime-requests.md) de la aplicación.
4. La aplicación crea una instancia del [controlador](structure-controllers.md) para gestionar la petición.
5. El controlador crea una instancia de la [acción](structure-controllers.md) y ejecuta los filtros para la acción.
Las peticiones(requests) hechas a una aplicación son representadas como objetos [[yii\web\Request]] que proporcionan información como parámetros de la petición, cabeceras HTTP, cookies, etc. Dada una petición, se puede acceder al objeto request correspondiente a través del [componente de aplicación](structure-application-components.md)`request` que, por defecto, es una instancia de [[yii\web\Request]]. En esta sección se describirá como hacer uso de este componente en las aplicaciones.
Las peticiones (requests) hechas a una aplicación son representadas como objetos [[yii\web\Request]] que proporcionan
información como parámetros de la petición, cabeceras HTTP, cookies, etc. Dada una petición, se puede acceder al
objeto request correspondiente a través del [componente de aplicación](structure-application-components.md)`request`
que, por defecto, es una instancia de [[yii\web\Request]]. En esta sección se describirá como hacer uso de este
componente en las aplicaciones.
## Parámetros de Request <a name="request-parameters"></a>
Para obtener los parámetros de la petición, se puede llamar a los métodos [[yii\web\Request::get()|get()]] y [[yii\web\Request::post()|post()]] del componente `request`. Estos devuelven los valores de `$_GET` y `$_POST`, respectivamente. Por ejemplo:
Para obtener los parámetros de la petición, se puede llamar a los métodos [[yii\web\Request::get()|get()]] y
[[yii\web\Request::post()|post()]] del componente `request`. Estos devuelven los valores de `$_GET` y `$_POST`,
>Info: En lugar de acceder directamente a `$_GET` y `$_POST` para obtener los parámetros de la petición, es recomendable que se obtengan mediante el componente `request` como en el ejemplo anterior. Esto facilitará la creación de tests ya que se puede simular una componente de request con datos de peticiones personalizados.
> Información: En lugar de acceder directamente a `$_GET` y `$_POST` para obtener los parámetros de la petición, es
recomendable que se obtengan mediante el componente `request` como en el ejemplo anterior. Esto facilitará la
creación de tests ya que se puede simular una componente de request con datos de peticiones personalizados.
Cuando se implementan [APIs RESTful](rest-quick-start.md), a menudo se necesita obtener parámetros enviados desde el formulario a través de PUT, PATCH u otros [métodos de request](runtime-requests.md#request-methods). Se pueden obtener estos parámetros llamando a los métodos [[yii\web\Request::getBodyParam()]]. Por ejemplo:
Cuando se implementan [APIs RESTful](rest-quick-start.md), a menudo se necesita obtener parámetros enviados desde el
formulario a través de PUT, PATCH u otros [métodos de request](runtime-requests.md#request-methods). Se pueden obtener
estos parámetros llamando a los métodos [[yii\web\Request::getBodyParam()]]. Por ejemplo:
>Info: A diferencia de los parámetros `GET`, los parámetros enviados desde el formulario a través de `POST`, `PUT`, `PATCH`, etc. se envían en el cuerpo de la petición. El componente `request` convierte los parámetros cuando se acceda a él a través de los métodos descritos anteriormente. Se puede personalizar la manera en como los parámetros se convierten configurando la propiedad [[yii\web\Request::parsers]].
> Información: A diferencia de los parámetros `GET`, los parámetros enviados desde el formulario a través de `POST`,
`PUT`, `PATCH`, etc. se envían en el cuerpo de la petición. El componente `request` convierte los parámetros cuando
se acceda a él a través de los métodos descritos anteriormente. Se puede personalizar la manera en como los
parámetros se convierten configurando la propiedad [[yii\web\Request::parsers]].
## Métodos de Request <a name="request-methods"></a>
Se puede obtener el método HTTP usado por la petición actual a través de la expresión `Yii::$app->request->method`. Se proporcionan un conjunto de propiedades booleanas para comprobar si el método actual es de un cierto tipo. Por ejemplo:
Se puede obtener el método HTTP usado por la petición actual a través de la expresión `Yii::$app->request->method`. Se
proporcionan un conjunto de propiedades booleanas para comprobar si el método actual es de un cierto tipo. Por ejemplo:
```php
$request=Yii::$app->request;
...
...
@@ -61,21 +76,29 @@ if ($request->isPut) { // el método de la request es PUT }
El componente `request` proporciona muchas maneras de inspeccionar la URL solicitada actualmente.
Asumiendo que la URL que se está solicitando es `http://example.com/admin/index.php/product?id=100`, se pueden obtener varias partes de la URL explicadas en los siguientes puntos:
*[[yii\web\Request::url|url]]: devuelve `/admin/index.php/product?id=100`, que es la URL sin la parte de información del host.
*[[yii\web\Request::absoluteUrl|absoluteUrl]]: devuelve `http://example.com/admin/index.php/product?id=100`, que es la URL entera, incluyendo la parte de información del host.
*[[yii\web\Request::hostInfo|hostInfo]]: devuelve `http://example.com`, que es la parte de información del host dentro de la URL.
*[[yii\web\Request::pathInfo|pathInfo]]: devuelve `/product`, que es la parte posterior al script de entrada y anterior al interrogante (query string)
Asumiendo que la URL que se está solicitando es `http://example.com/admin/index.php/product?id=100`, se pueden obtener
varias partes de la URL explicadas en los siguientes puntos:
*[[yii\web\Request::url|url]]: devuelve `/admin/index.php/product?id=100`, que es la URL sin la parte de información
del host.
*[[yii\web\Request::absoluteUrl|absoluteUrl]]: devuelve `http://example.com/admin/index.php/product?id=100`, que es
la URL entera, incluyendo la parte de información del host.
*[[yii\web\Request::hostInfo|hostInfo]]: devuelve `http://example.com`, que es la parte de información del host
dentro de la URL.
*[[yii\web\Request::pathInfo|pathInfo]]: devuelve `/product`, que es la parte posterior al script de entrada y
anterior al interrogante (query string)
*[[yii\web\Request::queryString|queryString]]: devuelve `id=100`, que es la parte posterior al interrogante.
*[[yii\web\Request::baseUrl|baseUrl]]: devuelve `/admin`, que es la parte posterior a la información del host y anterior al nombre de script de entrada.
*[[yii\web\Request::scriptUrl|scriptUrl]]: devuelve `/admin/index.php`, que es la URL sin la información del la ruta ni la query string.
*[[yii\web\Request::baseUrl|baseUrl]]: devuelve `/admin`, que es la parte posterior a la información del host y
anterior al nombre de script de entrada.
*[[yii\web\Request::scriptUrl|scriptUrl]]: devuelve `/admin/index.php`, que es la URL sin la información del la ruta
ni la query string.
*[[yii\web\Request::serverName|serverName]]: devuelve `example.com`, que es el nombre del host dentro de la URL.
*[[yii\web\Request::serverPort|serverPort]]: devuelve 80, que es el puerto que usa el servidor web.
## Cabeceras HTTP <a name="http-headers"></a>
Se pueden obtener la información de las cabeceras HTTP a través de [[yii\web\HeaderCollection|header collection]] devueltas por la propiedad [[yii\web\Request::headers]]. Por ejemplo:
Se pueden obtener la información de las cabeceras HTTP a través de [[yii\web\HeaderCollection|header collection]]
devueltas por la propiedad [[yii\web\Request::headers]]. Por ejemplo:
```php
// $headers es un objeto de yii\web\HeaderCollection
if($headers->has('User-Agent')){// la cabecera contiene un User-Agent }
```
El componente `request` también proporciona soporte para acceder rápidamente a las cabeceras usadas más comúnmente, incluyendo:
El componente `request` también proporciona soporte para acceder rápidamente a las cabeceras usadas más comúnmente,
incluyendo:
*[[yii\web\Request::userAgent|userAgent]]: devuelve el valor de la cabecera `User-Agen`.
*[[yii\web\Request::contentType|contentType]]: devuelve el valor de la cabecera `Content-Type` que indica el tipo MIME de los datos del cuerpo de la petición.
*[[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: devuelve los tipos de contenido MIME aceptado por los usuarios, ordenados por puntuación de calidad. Los que tienen mejor puntuación, se devolverán primero.
*[[yii\web\Request::acceptableLanguages|acceptableLanguages]]: devuelve los idiomas aceptados por el usuario. Los idiomas devueltos son ordenados según su orden de preferencia. El primer elemento representa el idioma preferido.
Si la aplicación soporta múltiples idiomas y se quiere mostrar las páginas en el idioma preferido por el usuario, se puede usar el método de negociación de idioma [[yii\web\Request::getPreferredLanguage()]]. Este método obtiene una lista de idiomas soportados por la aplicación, comparados con [[yii\web\Request::acceptableLanguages|acceptableLanguages]], y devuelve el idioma más apropiado.
>Consejo: También se puede usar el filtro [[yii\filters\ContentNegotiator|ContentNegotiator]] para determinar diatónicamente el content type y el idioma que debe usarse en la respuesta. El filtro implementa la negociación de contenido en la parte superior de las propiedades y métodos descritos anteriormente.
*[[yii\web\Request::contentType|contentType]]: devuelve el valor de la cabecera `Content-Type` que indica el tipo
MIME de los datos del cuerpo de la petición.
*[[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: devuelve los tipos de contenido MIME aceptado
por los usuarios, ordenados por puntuación de calidad. Los que tienen mejor puntuación, se devolverán primero.
*[[yii\web\Request::acceptableLanguages|acceptableLanguages]]: devuelve los idiomas aceptados por el usuario. Los
idiomas devueltos son ordenados según su orden de preferencia. El primer elemento representa el idioma preferido.
Si la aplicación soporta múltiples idiomas y se quiere mostrar las páginas en el idioma preferido por el usuario, se
puede usar el método de negociación de idioma [[yii\web\Request::getPreferredLanguage()]]. Este método obtiene una
lista de idiomas soportados por la aplicación, comparados con
[[yii\web\Request::acceptableLanguages|acceptableLanguages]], y devuelve el idioma más apropiado.
> Consejo: También se puede usar el filtro [[yii\filters\ContentNegotiator|ContentNegotiator]] para determinar
diatónicamente el content type y el idioma que debe usarse en la respuesta. El filtro implementa la negociación de
contenido en la parte superior de las propiedades y métodos descritos anteriormente.
## Información del cliente <a name="client-information"></a>
Se puede obtener el nombre del host y la dirección IP de la máquina cliente a través de [[yii\web\Request::userHost|userHost]] y [[yii\web\Request::userIP|userIP]], respectivamente. Por ejemplo:
Se puede obtener el nombre del host y la dirección IP de la máquina cliente a través de
[[yii\web\Request::userHost|userHost]] y [[yii\web\Request::userIP|userIP]], respectivamente. Por ejemplo:
Cuando una aplicación finaliza la gestión de una [petición (request)](runtime-requests.md), genera un objeto [[yii\web\Response|response]] y lo envía al usuario final. El objeto response contiene información tal como el código de estado (status code) HTTP, las cabeceras (headers) HTTP y el cuerpo (body). El objetivo final del desarrollo de una aplicación Web es esencialmente construir objetos response para varias peticiones.
Cuando una aplicación finaliza la gestión de una [petición (request)](runtime-requests.md), genera un objeto
[[yii\web\Response|response]] y lo envía al usuario final. El objeto response contiene información tal como el código
de estado (status code) HTTP, las cabeceras (headers) HTTP y el cuerpo (body). El objetivo final del desarrollo de una
aplicación Web es esencialmente construir objetos response para varias peticiones.
En la mayoría de casos principalmente se debe tratar con [componentes de aplicación](structure-application-components.md) de tipo `response` que, por defecto, son una instancia de [[yii\web\Response]]. Sin embargo, Yii permite crear sus propios objetos `response` y enviarlos al usuario final tal y como se explica a continuación.
En la mayoría de casos principalmente se debe tratar con
[componentes de aplicación](structure-application-components.md) de tipo `response` que, por defecto, son una
instancia de [[yii\web\Response]]. Sin embargo, Yii permite crear sus propios objetos `response` y enviarlos al
usuario final tal y como se explica a continuación.
En esta sección, se describirá como generar y enviar respuestas a usuarios finales.
## Códigos de Estado <a name="status-code"></a>
Una de las primeras cosas que debería hacerse cuando se genera una respuesta es indicar si la petición se ha gestionado correctamente. Esto se indica asignando la propiedad [[yii\web\Response::statusCode]] a la que se le puede asignar cualquier valor válido dentro de los [códigos de estado HTTP](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). Por ejemplo, para indicar que la petición se ha gestionado correctamente, se puede asignar el código de estado a 200, como en el siguiente ejemplo:
Una de las primeras cosas que debería hacerse cuando se genera una respuesta es indicar si la petición se ha
gestionado correctamente. Esto se indica asignando la propiedad [[yii\web\Response::statusCode]] a la que se le puede
asignar cualquier valor válido dentro de los
[códigos de estado HTTP](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). Por ejemplo, para indicar que la
petición se ha gestionado correctamente, se puede asignar el código de estado a 200, como en el siguiente ejemplo:
```php
Yii::$app->response->statusCode=200;
```
Sin embargo, en la mayoría de casos nos es necesario asignar explícitamente el código de estado. Esto se debe a que el valor por defecto de [[yii\web\Response::statusCode]] es 200. Y si se quiere indicar que la petición ha fallado, se puede lanzar una excepción HTTP apropiada como en el siguiente ejemplo:
Sin embargo, en la mayoría de casos nos es necesario asignar explícitamente el código de estado. Esto se debe a que el
valor por defecto de [[yii\web\Response::statusCode]] es 200. Y si se quiere indicar que la petición ha fallado, se
puede lanzar una excepción HTTP apropiada como en el siguiente ejemplo:
```php
thrownew\yii\web\NotFoundHttpException;
```
Cuando el [error handler](runtime-handling-errors.md) captura una excepción, obtendrá el código de estado de la excepción y lo asignará a la respuesta. En el caso anterior, la excepción [[yii\web\NotFoundHttpException]] está asociada al estado HTTP 404. En Yii existen las siguientes excepciones predefinidas.
Cuando el [error handler](runtime-handling-errors.md) captura una excepción, obtendrá el código de estado de la
excepción y lo asignará a la respuesta. En el caso anterior, la excepción [[yii\web\NotFoundHttpException]] está
asociada al estado HTTP 404. En Yii existen las siguientes excepciones predefinidas.
*[[yii\web\BadRequestHttpException]]: código de estado 400.
*[[yii\web\ConflictHttpException]]: código de estado 409.
...
...
@@ -35,7 +49,8 @@ Cuando el [error handler](runtime-handling-errors.md) captura una excepción, ob
*[[yii\web\UnauthorizedHttpException]]: código de estado 401.
*[[yii\web\UnsupportedMediaTypeHttpException]]: código de estado 415.
Si la excepción que se quiere lanzar no se encuentra en la lista anterior, se puede crear una extendiendo [[yii\web\HttpException]], o directamente lanzando un código de estado, por ejemplo:
Si la excepción que se quiere lanzar no se encuentra en la lista anterior, se puede crear una extendiendo
[[yii\web\HttpException]], o directamente lanzando un código de estado, por ejemplo:
```php
thrownew\yii\web\HttpException(402);
...
...
@@ -43,7 +58,8 @@ throw new \yii\web\HttpException(402);
## Cabeceras HTTP <a name="http-headers"></a>
Se puede enviar cabeceras HTTP modificando el [[yii\web\Response::headers|header collection]] en el componente `response`. Por ejemplo:
Se puede enviar cabeceras HTTP modificando el [[yii\web\Response::headers|header collection]] en el componente
>Información: Los nombres de las cabeceras case insensitive, es decir, no discriminan entre mayúsculas y minúsculas. Además, las nuevas cabeceras registradas no se enviarán al usuario hasta que se llame al método [[yii\web\Response::send()]].
> Información: Los nombres de las cabeceras case insensitive, es decir, no discriminan entre mayúsculas y minúsculas.
Además, las nuevas cabeceras registradas no se enviarán al usuario hasta que se llame al método
[[yii\web\Response::send()]].
## Cuerpo de la Respuesta<a name="response-body"></a>
La mayoría de las respuestas deben tener un cuerpo que contenga el contenido que se quiere mostrar a los usuarios finales.
La mayoría de las respuestas deben tener un cuerpo que contenga el contenido que se quiere mostrar a los usuarios
finales.
Si ya se tiene un texto de cuerpo con formato, se puede asignar a la propiedad [[yii\web\Response::content]] del response. Por ejemplo:
Si ya se tiene un texto de cuerpo con formato, se puede asignar a la propiedad [[yii\web\Response::content]] del
response. Por ejemplo:
```php
Yii::$app->response->content='hello world!';
```
Si se tiene que dar formato a los datos antes de enviarlo al usuario final, se deben asignar las propiedades [[yii\web\Response::format|format]] y [[yii\web\Response::data|data]]. La propiedad [[yii\web\Response::format|format]] especifica que formato debe tener [[yii\web\Response::data|data]]. Por ejemplo:
Si se tiene que dar formato a los datos antes de enviarlo al usuario final, se deben asignar las propiedades
[[yii\web\Response::format|format]] y [[yii\web\Response::data|data]]. La propiedad [[yii\web\Response::format|format]]
especifica que formato debe tener [[yii\web\Response::data|data]]. Por ejemplo:
Yii soporta a los siguientes formatos de forma predeterminada, cada uno de ellos implementado por una clase [[yii\web\ResponseFormatterInterface|formatter]]. Se pueden personalizar los formatos o añadir nuevos sobrescribiendo la propiedad [[yii\web\Response::formatters]].
Yii soporta a los siguientes formatos de forma predeterminada, cada uno de ellos implementado por una clase
[[yii\web\ResponseFormatterInterface|formatter]]. Se pueden personalizar los formatos o añadir nuevos sobrescribiendo
la propiedad [[yii\web\Response::formatters]].
*[[yii\web\Response::FORMAT_HTML|HTML]]: implementado por [[yii\web\HtmlResponseFormatter]].
*[[yii\web\Response::FORMAT_XML|XML]]: implementado por [[yii\web\XmlResponseFormatter]].
*[[yii\web\Response::FORMAT_JSON|JSON]]: implementado por [[yii\web\JsonResponseFormatter]].
*[[yii\web\Response::FORMAT_JSONP|JSONP]]: implementado por [[yii\web\JsonResponseFormatter]].
Mientras el cuerpo de la respuesta puede ser mostrado de forma explicita como se muestra a en el anterior ejemplo, en la mayoría de casos se puede asignar implícitamente por el valor de retorno de los métodos de [acción](structure-controllers.md). El siguiente, es un ejemplo de uso común:
Mientras el cuerpo de la respuesta puede ser mostrado de forma explicita como se muestra a en el anterior ejemplo, en
la mayoría de casos se puede asignar implícitamente por el valor de retorno de los métodos de
[acción](structure-controllers.md). El siguiente, es un ejemplo de uso común:
```php
publicfunctionactionIndex()
...
...
@@ -94,9 +120,12 @@ public function actionIndex()
}
```
La acción `index` anterior, devuelve el resultado renderizado de la vista `index`. el valor devuelto será recogido por el componente `response`, se le aplicará formato y se enviará al usuario final.
La acción `index` anterior, devuelve el resultado renderizado de la vista `index`. El valor devuelto será recogido por
el componente `response`, se le aplicará formato y se enviará al usuario final.
Por defecto, el formato de respuesta es [[yii\web\Response::FORMAT_HTML|HTML]], sólo se debe devolver un string en un método de acción. Si se quiere usar un formato de respuesta diferente, se debe asignar antes de devolver los datos. por ejemplo:
Por defecto, el formato de respuesta es [[yii\web\Response::FORMAT_HTML|HTML]], sólo se debe devolver un string en un
método de acción. Si se quiere usar un formato de respuesta diferente, se debe asignar antes de devolver los datos.
Por ejemplo:
```php
publicfunctionactionInfo()
...
...
@@ -109,7 +138,9 @@ public function actionInfo()
}
```
Como se ha mencionado, además de usar el componente de aplicación `response` predeterminado, también se pueden crear objetos response propios y enviarlos a los usuarios finales. Se puede hacer retornando un objeto en el método de acción, como en el siguiente ejemplo:
Como se ha mencionado, además de usar el componente de aplicación `response` predeterminado, también se pueden crear
objetos response propios y enviarlos a los usuarios finales. Se puede hacer retornando un objeto en el método de
acción, como en el siguiente ejemplo:
```php
publicfunctionactionInfo()
...
...
@@ -125,13 +156,19 @@ public function actionInfo()
}
```
>Nota: Si se crea un objeto response propio, no se podrán aprovechar las configuraciones asignadas para el componente `response` en la configuración de la aplicación. Sin embargo, se puede usar la [inyección de dependencias](concept-di-container.md) para aplicar la configuración común al nuevo objeto response.
> Nota: Si se crea un objeto response propio, no se podrán aprovechar las configuraciones asignadas para el componente
`response` en la configuración de la aplicación. Sin embargo, se puede usar la
[inyección de dependencias](concept-di-container.md) para aplicar la configuración común al nuevo objeto response.
## Redirección del Navegador <a name="browser-redirection"></a>
La redirección del navegador se basa en el envío de la cabecera HTTP `Location`. Debido a que esta característica se usa comúnmente, Yii proporciona soporte especial para ello.
La redirección del navegador se basa en el envío de la cabecera HTTP `Location`. Debido a que esta característica se
usa comúnmente, Yii proporciona soporte especial para ello.
Se puede redirigir el navegador a una URL llamando al método [[yii\web\Response::redirect()]]. El método asigna la cabecera de `Location` apropiada con la URL proporcionada y devuelve el objeto response él mismo. En un método de acción, se puede acceder a él mediante el acceso directo [[yii\web\Controller::redirect()]] como en el siguiente ejemplo:
Se puede redirigir el navegador a una URL llamando al método [[yii\web\Response::redirect()]]. El método asigna la
cabecera de `Location` apropiada con la URL proporcionada y devuelve el objeto response él mismo. En un método de
acción, se puede acceder a él mediante el acceso directo [[yii\web\Controller::redirect()]] como en el siguiente
ejemplo:
```php
publicfunctionactionOld()
...
...
@@ -140,29 +177,44 @@ public function actionOld()
}
```
En el ejemplo anterior, el método de acción devuelve el resultado del método `redirect()`. Como se ha explicado antes, el objeto response devuelto por el método de acción se usará como respuesta enviándola al usuario final.
En el ejemplo anterior, el método de acción devuelve el resultado del método `redirect()`. Como se ha explicado antes,
el objeto response devuelto por el método de acción se usará como respuesta enviándola al usuario final.
En otros sitios que no sean los métodos de acción, se puede llamar a [[yii\web\Response::redirect()]] directamente seguido por una llamada al método [[yii\web\Response::send()]] para asegurar que no habrá contenido extra en la respuesta.
En otros sitios que no sean los métodos de acción, se puede llamar a [[yii\web\Response::redirect()]] directamente
seguido por una llamada al método [[yii\web\Response::send()]] para asegurar que no habrá contenido extra en la
> Información: De forma predeterminada, el método [[yii\web\Response::redirect()]] asigna el estado de respuesta al código de estado 302 que indica al navegador que recurso solicitado está *temporalmente* alojado en una URI diferente. Se puede enviar un código de estado 301 para expresar que el recurso se ha movido de forma *permanente*.
> Información: De forma predeterminada, el método [[yii\web\Response::redirect()]] asigna el estado de respuesta al
código de estado 302 que indica al navegador que recurso solicitado está *temporalmente* alojado en una URI diferente.
Se puede enviar un código de estado 301 para expresar que el recurso se ha movido de forma *permanente*.
Cuando la petición actual es de una petición AJAX, el hecho de enviar una cabecera `Location` no causará una redirección del navegador automática. Para resolver este problema, el método [[yii\web\Response::redirect()]] asigna una cabecera `X-Redirect` con el valor de la URL de redirección. En el lado del cliente se puede escribir código JavaScript para leer la esta cabecera y redireccionar el navegador como corresponda.
Cuando la petición actual es de una petición AJAX, el hecho de enviar una cabecera `Location` no causará una
redirección del navegador automática. Para resolver este problema, el método [[yii\web\Response::redirect()]] asigna
una cabecera `X-Redirect` con el valor de la URL de redirección. En el lado del cliente se puede escribir código
JavaScript para leer la esta cabecera y redireccionar el navegador como corresponda.
> Información: Yii contiene el archivo JavaScript `yii.js` que proporciona un conjunto de utilidades comunes de JavaScript, incluyendo la redirección de navegador basada en la cabecera `X-Redirect`. Por tanto, si se usa este fichero JavaScript (registrándolo *asset bundle* [[yii\web\YiiAsset]]), no se necesitará escribir nada más para tener soporte en redirecciones AJAX.
> Información: Yii contiene el archivo JavaScript `yii.js` que proporciona un conjunto de utilidades comunes de
JavaScript, incluyendo la redirección de navegador basada en la cabecera `X-Redirect`. Por tanto, si se usa este
fichero JavaScript (registrándolo *asset bundle*[[yii\web\YiiAsset]]), no se necesitará escribir nada más para tener
soporte en redirecciones AJAX.
## Enviar Archivos <a name="sending-files"></a>
Igual que con la redirección, el envío de archivos es otra característica que se basa en cabeceras HTTP especificas. Yii proporciona un conjunto de métodos para dar soporte a varias necesidades del envío de ficheros. Todos ellos incorporan soporte para el rango de cabeceras HTTP.
Igual que con la redirección, el envío de archivos es otra característica que se basa en cabeceras HTTP especificas.
Yii proporciona un conjunto de métodos para dar soporte a varias necesidades del envío de ficheros. Todos ellos
incorporan soporte para el rango de cabeceras HTTP.
*[[yii\web\Response::sendFile()]]: envía un fichero existente al cliente.
*[[yii\web\Response::sendContentAsFile()]]: envía un string al cliente como si fuera un archivo.
*[[yii\web\Response::sendContentAsFile()]]: envía un string al cliente como si fuera un archivo.
*[[yii\web\Response::sendStreamAsFile()]]: envía un *file stream* existente al cliente como si fuera un archivo.
Estos métodos tienen la misma firma de método con el objeto response como valor de retorno. Si el archivo que se envía es muy grande, se debe considerar usar [[yii\web\Response::sendStreamAsFile()]] porque es más efectivo en términos de memoria. El siguiente ejemplo muestra como enviar un archivos en una acción de controlador.
Estos métodos tienen la misma firma de método con el objeto response como valor de retorno. Si el archivo que se envía
es muy grande, se debe considerar usar [[yii\web\Response::sendStreamAsFile()]] porque es más efectivo en términos de
memoria. El siguiente ejemplo muestra como enviar un archivo en una acción de controlador.
```php
publicfunctionactionDownload()
...
...
@@ -171,13 +223,18 @@ public function actionDownload()
}
```
Si se llama al método de envío de ficheros fuera de un método de acción, también se debe llamar al método [[yii\web\Response::send()]] después para asegurar que no se añada contenido extra a la respuesta.
Si se llama al método de envío de ficheros fuera de un método de acción, también se debe llamar al método
[[yii\web\Response::send()]] después para asegurar que no se añada contenido extra a la respuesta.
Algunos servidores Web tienen un soporte especial para enviar ficheros llamado *X-Sendfile*. La idea es redireccionar la petición para un fichero a un servidor Web que servirá el fichero directamente. Como resultado, la aplicación Web puede terminar antes mientras el servidor Web envía el fichero. Para usar esta funcionalidad, se puede llamar a [[yii\web\Response::xSendFile()]]. La siguiente lista resume como habilitar la característica `X-Sendfile` para algunos servidores Web populares.
Algunos servidores Web tienen un soporte especial para enviar ficheros llamado *X-Sendfile*. La idea es redireccionar
la petición para un fichero a un servidor Web que servirá el fichero directamente. Como resultado, la aplicación Web
puede terminar antes mientras el servidor Web envía el fichero. Para usar esta funcionalidad, se puede llamar a
[[yii\web\Response::xSendFile()]]. La siguiente lista resume como habilitar la característica `X-Sendfile` para
@@ -187,17 +244,22 @@ Algunos servidores Web tienen un soporte especial para enviar ficheros llamado *
## Enviar la Respuesta <a name="sending-response"></a>
El contenido en una respuesta no se envía al usuario hasta que se llama al método [[yii\web\Response::send()]]. De forma predeterminada, se llama a este método automáticamente al final de [[yii\base\Application::run()]]. Sin embargo, se puede llamar explícitamente a este método forzando el envío de la respuesta inmediatamente.
El contenido en una respuesta no se envía al usuario hasta que se llama al método [[yii\web\Response::send()]]. De
forma predeterminada, se llama a este método automáticamente al final de [[yii\base\Application::run()]]. Sin embargo,
se puede llamar explícitamente a este método forzando el envío de la respuesta inmediatamente.
El método [[yii\web\Response::send()]] sigue los siguientes pasos para enviar una respuesta:
1. Lanza el evento [[yii\web\Response::EVENT_BEFORE_SEND]].
2. Llama a [[yii\web\Response::prepare()]] para convertir el [[yii\web\Response::data|response data]] en [[yii\web\Response::content|response content]].
2. Llama a [[yii\web\Response::prepare()]] para convertir el [[yii\web\Response::data|response data]] en
[[yii\web\Response::content|response content]].
3. Lanza el evento [[yii\web\Response::EVENT_AFTER_PREPARE]].
4. Llama a [[yii\web\Response::sendHeaders()]] para enviar las cabeceras HTTP registradas.
5. Llama a [[yii\web\Response::sendContent()]] para enviar el contenido del cuerpo de la respuesta.
6. Lanza el evento [[yii\web\Response::EVENT_AFTER_SEND]].
Después de llamar a [[yii\web\Response::send()]] por primera vez, cualquier llamada a este método será ignorada. Esto significa que una vez se envíe una respuesta, no se le podrá añadir más contenido.
Después de llamar a [[yii\web\Response::send()]] por primera vez, cualquier llamada a este método será ignorada. Esto
significa que una vez se envíe una respuesta, no se le podrá añadir más contenido.
Como se puede observar, el método [[yii\web\Response::send()]] lanza varios eventos útiles. Al responder a estos eventos, es posible ajustar o decorar la respuesta.
Como se puede observar, el método [[yii\web\Response::send()]] lanza varios eventos útiles. Al responder a estos
eventos, es posible ajustar o decorar la respuesta.
Los Filtros son objetos que se ejecutan antes y/o después de las [acciones de controlador](structure-controllers.md#actions). Por ejemplo, un filtro de control de acceso puede ejecutarse antes de las acciones para asegurar que un usuario final tiene permitido acceder a estas; un filtro de compresión de contenido puede ejecutarse después de las acciones para comprimir el contenido de la respuesta antes de ser enviado al usuario final.
Los Filtros (filters) son objetos que se ejecutan antes y/o después de las
[acciones de controlador](structure-controllers.md#actions). Por ejemplo, un filtro de control de acceso puede
ejecutarse antes de las acciones para asegurar que un usuario final tiene permitido acceder a estas; un filtro de
compresión de contenido puede ejecutarse después de las acciones para comprimir el contenido de la respuesta antes de
ser enviado al usuario final.
Un filtro puede consistir en un pre-filtro(lógica de filtrado aplicada *antes* de las acciones) y/o un post-filtro(lógica de filtro aplicada *después* de las acciones).
Un filtro puede consistir en un pre-filtro (lógica de filtrado aplicada *antes* de las acciones) y/o un post-filtro
(lógica de filtro aplicada *después* de las acciones).
## Uso de Filtros <a name="using-filters"></a>
Los filtros son esencialmente un tipo especial de [comportamientos](concept-behaviors.md).
Por lo tanto, usar filtros es lo mismo que [uso de comportamientos](concept-behaviors.md#attaching-behaviors). Se pueden declarar los filtros en una clase controlador sobrescribiendo el método [[yii\base\Controller::behaviors()|behaviors()]] como en el siguiente ejemplo:
Los filtros son esencialmente un tipo especial de [comportamientos (behaviors)](concept-behaviors.md).
Por lo tanto, usar filtros es lo mismo que [uso de comportamientos](concept-behaviors.md#attaching-behaviors). Se
pueden declarar los filtros en una clase controlador sobrescribiendo el método
[[yii\base\Controller::behaviors()|behaviors()]] como en el siguiente ejemplo:
```php
publicfunctionbehaviors()
...
...
@@ -26,13 +33,22 @@ public function behaviors()
}
```
Por defecto, los filtros declarados en una clase controlador, serán aplicados en *todas* las acciones de este controlador. Sin embargo, se puede especificar explícitamente en que acciones serán aplicadas configurando la propiedad [[yii\base\ActionFilter::only|only]]. En el anterior ejemplo, el filtro 'HttpCache' solo se aplica a las acciones 'index' y 'view'. También se puede configurar la propiedad [[yii\base\ActionFilter::except|except]] para prevenir que ciertas acciones sean filtradas.
Por defecto, los filtros declarados en una clase controlador, serán aplicados en *todas* las acciones de este
controlador. Sin embargo, se puede especificar explícitamente en que acciones serán aplicadas configurando la
propiedad [[yii\base\ActionFilter::only|only]]. En el anterior ejemplo, el filtro 'HttpCache' solo se aplica a las
acciones 'index' y 'view'. También se puede configurar la propiedad [[yii\base\ActionFilter::except|except]] para
prevenir que ciertas acciones sean filtradas.
Además de en los controladores, se pueden declarar filtros en [modulos](structure-modules.md) o [aplicaciones](structure-applications.md).
Una vez hecho, los filtros serán aplicados a *todas* las acciones de controlador que pertenezcan a ese modulo o aplicación, a menos que las propiedades [[yii\base\ActionFilter::only|only]] y [[yii\base\ActionFilter::except|except]] sean configuradas como se ha descrito anteriormente.
Además de en los controladores, se pueden declarar filtros en [módulos](structure-modules.md) o
[aplicaciones](structure-applications.md).
Una vez hecho, los filtros serán aplicados a *todas* las acciones de controlador que pertenezcan a ese modulo o
aplicación, a menos que las propiedades [[yii\base\ActionFilter::only|only]] y [[yii\base\ActionFilter::except|except]]
sean configuradas como se ha descrito anteriormente.
>Nota: Cuando se declaran filtros en módulos o aplicaciones, deben usarse [rutas](structure-controllers.md#routes) en lugar de IDs de acciones en las propiedades [[yii\base\ActionFilter::only|only]] y [[yii\base\ActionFilter::except|except]].
Esto es debido a que los IDs de acciones no pueden especificar acciones dentro del ámbito de un modulo o una aplicación por si mismos.
> Nota: Cuando se declaran filtros en módulos o aplicaciones, deben usarse [rutas](structure-controllers.md#routes) en
lugar de IDs de acciones en las propiedades [[yii\base\ActionFilter::only|only]] y
[[yii\base\ActionFilter::except|except]]. Esto es debido a que los IDs de acciones no pueden especificar acciones
dentro del ámbito de un modulo o una aplicación por si mismos.
Cuando se configuran múltiples filtros para una misma acción, se aplican de acuerdo a las siguientes reglas:
...
...
@@ -40,17 +56,22 @@ Cuando se configuran múltiples filtros para una misma acción, se aplican de ac
- Aplica filtros declarados en la aplicación en orden de aparición en `behaviors()`.
- Aplica filtros declarados en el modulo en orden de aparición en `behaviors()`.
- Aplica filtros declarados en el controlador en orden de aparición en `behaviors()`.
- Si hay algún filtro que cancele la ejecución de la acción, los filtros(tanto pre-filtros como post-filtros) posteriores a este no serán aplicados.
- Si hay algún filtro que cancele la ejecución de la acción, los filtros(tanto pre-filtros como post-filtros)
posteriores a este no serán aplicados.
* Ejecución de la acción si pasa el pre-filtro.
* Post-filtrado
- Aplica los filtros declarados en el controlador en el controlador en orden inverso al de aparición en `behaviors()`.
- Aplica los filtros declarados en el controlador en el controlador en orden inverso al de aparición en
`behaviors()`.
- Aplica los filtros declarados en el modulo en orden inverso al de aparición en `behaviors()`.
- Aplica los filtros declarados en la aplicación en orden inverso al de aparición en `behaviors()`.
##Creación de Filtros <a name="creating-filters"></a>
Para crear un nuevo filtro de acción, hay que extender a [[yii\base\ActionFilter]] y sobrescribir los métodos [[yii\base\ActionFilter::beforeAction()|beforeAction()]] y/o [[yii\base\ActionFilter::afterAction()|afterAction()]]. El primero será ejecutado antes de la acción mientras que el segundo lo hará una vez ejecutada la acción.
El valor devuelto por [[yii\base\ActionFilter::beforeAction()|beforeAction()]] determina si una acción debe ejecutarse o no. Si el valor es falso, los filtros posteriores a este serán omitidos y la acción no será ejecutada.
Para crear un nuevo filtro de acción, hay que extender a [[yii\base\ActionFilter]] y sobrescribir los métodos
El primero será ejecutado antes de la acción mientras que el segundo lo hará una vez ejecutada la acción.
El valor devuelto por [[yii\base\ActionFilter::beforeAction()|beforeAction()]] determina si una acción debe ejecutarse
o no. Si el valor es falso, los filtros posteriores a este serán omitidos y la acción no será ejecutada.
El siguiente ejemplo muestra un filtro que registra el tiempo de ejecución de una acción:
...
...
@@ -81,14 +102,19 @@ class ActionTimeFilter extends ActionFilter
## Filtros del Núcleo <a name="core-filters"></a>
Yii proporciona una serie de filtros de uso general, que se encuentran principalmente en `yii\filters` namespace. En adelante introduciremos estos filtros brevemente.
Yii proporciona una serie de filtros de uso general, que se encuentran principalmente en `yii\filters` namespace. En
AccessControl proporciona control de acceso simple basado en un conjunto de [[yii\filters\AccessControl::rules|rules]].
En concreto, antes de ejecutar una acción, AccessControl examinará la lista de reglas y encontrará la primera que concuerde con las actuales variables de contexto(tales como dirección IP de usuario, estado de inicio de sesión del usuario, etc.). La regla que concuerde dictara si se permite o deniega la ejecución de la acción solicitada. Si ninguna regla concuerda, el acceso será denegado.
En concreto, antes de ejecutar una acción, AccessControl examinará la lista de reglas y encontrará la primera que
concuerde con las actuales variables de contexto(tales como dirección IP de usuario, estado de inicio de sesión del
usuario, etc.). La regla que concuerde dictara si se permite o deniega la ejecución de la acción solicitada. Si
ninguna regla concuerda, el acceso será denegado.
El siguiente ejemplo muestra como habilitar el acceso a los usuarios autenticados a las acciones 'create' y 'update' mientras deniega a todos los otros usuarios el acceso a estas dos acciones.
El siguiente ejemplo muestra como habilitar el acceso a los usuarios autenticados a las acciones 'create' y 'update'
mientras deniega a todos los otros usuarios el acceso a estas dos acciones.
```php
...
...
@@ -101,25 +127,31 @@ public function behaviors()
'class' => AccessControl::className(),
'only' => ['create', 'update'],
'rules' => [
// allow authenticated users
// permitido para usuarios autenticados
[
'allow' => true,
'roles' => ['@'],
],
// everything else is denied by default
// todo lo demás se deniega por defecto
],
],
];
}
```
Para conocer más detalles acerca del control de acceso en general, refiérase a la sección de [Autorización](security-authorization.md)
Para conocer más detalles acerca del control de acceso en general, refiérase a la sección de
[Autorización](security-authorization.md)
### Filtros del Método de Autenticación <a name="auth-method-filters"></a>
Los filtros del método de autenticación se usan para autenticar a un usuario utilizando varios métodos, tales como la [Autenticación de acceso básica HTTP](http://es.wikipedia.org/wiki/Autenticaci%C3%B3n_de_acceso_b%C3%A1sica), [Oauth 2](http://oauth.net/2/). Estas clases de filtros se encuentran en el espacio de nombres `yii\filters\auth`.
Los filtros del método de autenticación se usan para autenticar a un usuario utilizando varios métodos, tales como la
[Autenticación de acceso básico HTTP](http://es.wikipedia.org/wiki/Autenticaci%C3%B3n_de_acceso_b%C3%A1sica),
[Oauth 2](http://oauth.net/2/). Estas clases de filtros se encuentran en el espacio de nombres `yii\filters\auth`.
El siguiente ejemplo muestra como usar [[yii\filters\auth\HttpBasicAuth]] para autenticar un usuario usando un token de acceso basado en el método de Autenticación de acceso básica HTTP. Tenga en cuenta que para que esto funcione, la clase [[yii\web\User::identityClass|user identity class]] debe implementar el método [[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]] .
El siguiente ejemplo muestra como usar [[yii\filters\auth\HttpBasicAuth]] para autenticar un usuario usando un token
de acceso basado en el método de Autenticación de acceso básico HTTP. Tenga en cuenta que para que esto funcione, la
clase [[yii\web\User::identityClass|user identity class]] debe implementar el método
Los filtros del método de autenticación se usan a menudo para implementar APIs RESTful. Para más detalles, por favor refiérase a la sección [Autenticación RESTful](rest-authentication.md).
Los filtros del método de autenticación se usan a menudo para implementar APIs RESTful. Para más detalles, por favor
refiérase a la sección [Autenticación RESTful](rest-authentication.md).
El filtro ContentNegotiator da soporte a la negociación del formato de respuesta y a la negociación del idioma de la aplicación. Este determinara el formato de respuesta y/o el idioma examinando los parámetros 'GET' y 'Accept' del encabezado HTTP.
El filtro ContentNegotiator da soporte a la negociación del formato de respuesta y a la negociación del idioma de la
aplicación. Este determinara el formato de respuesta y/o el idioma examinando los parámetros 'GET' y 'Accept' del
encabezado HTTP.
En el siguiente ejemplo, el filtro ContentNegotiator se configura para soportar los formatos de respuesta 'JSON' y 'XML', y los idiomas Ingles(Estados Unidos) y Alemán.
En el siguiente ejemplo, el filtro ContentNegotiator se configura para soportar los formatos de respuesta 'JSON' y
'XML', y los idiomas Ingles(Estados Unidos) y Alemán.
```php
useyii\filters\ContentNegotiator;
...
...
@@ -163,7 +199,11 @@ public function behaviors()
}
```
Los formatos de respuesta y los idiomas a menudo precisan ser determinados mucho antes durante el [ciclo de vida de la aplicación](structure-applications.md#application-lifecycle). Por esta razón, ContentNegotiator esta diseñado de tal manera que se pueda usar como componente de [bootstrapping](structure-applications.md#bootstrap) así como de filtro. Por ejemplo, ContentNegotiator se puede configurar en la configuración de la aplicación como en el siguiente ejemplo:
Los formatos de respuesta y los idiomas a menudo precisan ser determinados mucho antes durante el
[ciclo de vida de la aplicación](structure-applications.md#application-lifecycle). Por esta razón, ContentNegotiator
esta diseñado de tal manera que se pueda usar como componente de [bootstrapping](structure-applications.md#bootstrap)
así como de filtro. Por ejemplo, ContentNegotiator se puede configurar en la configuración de la aplicación como en el
siguiente ejemplo:
```php
useyii\filters\ContentNegotiator;
...
...
@@ -186,12 +226,14 @@ use yii\web\Response;
];
```
> Info: En el caso que el tipo preferido de contenido y el idioma no puedan ser determinados por una petición, será utilizando el primer elemento de formato e idioma de la lista [[formats]] y [[lenguages]].
> Información: En el caso que el tipo preferido de contenido y el idioma no puedan ser determinados por una petición,
será utilizando el primer elemento de formato e idioma de la lista [[formats]] y [[lenguages]].
PageCache implementa una caché por parte del servidor de paginas enteras. En el siguiente ejemplo, se aplica PageCache a la acción 'index' para generar una cache de la pagina entera durante 60 segundos como máximo o hasta que el contador de entradas de la tabla 'post' varíe. Tambien se encarga de almacenar diferentes versiones de la pagina dependiendo del idioma de la aplicación seleccionado.
PageCache implementa una caché por parte del servidor de paginas enteras. En el siguiente ejemplo, se aplica PageCache
a la acción 'index' para generar una cache de la pagina entera durante 60 segundos como máximo o hasta que el contador
de entradas de la tabla 'post' varíe. También se encarga de almacenar diferentes versiones de la pagina dependiendo
del idioma de la aplicación seleccionado.
```php
useyii\filters\PageCache;
...
...
@@ -244,11 +289,16 @@ Por favor refiérase a [Caché de Páginas](caching-page.md) para obtener más d
RateLimiter implementa un algoritmo de para limitar la tasa de descarga basándose en (leaky bucket algorithm)[http://en.wikipedia.org/wiki/Leaky_bucket]. Este se utiliza sobre todo en la implementación de APIs RESTful. Por favor, refiérase a la seccion (limite de tasa)[rest-rate-limiting.md] para obtener más detalles acerda de el uso de este filtro.
RateLimiter implementa un algoritmo de para limitar la tasa de descarga basándose en
(leaky bucket algorithm)[http://en.wikipedia.org/wiki/Leaky_bucket]. Este se utiliza sobre todo en la implementación
de APIs RESTful. Por favor, refiérase a la sección (limite de tasa)[rest-rate-limiting.md] para obtener más detalles
VerbFilter comprueba que los métodos de las peticiones HTTP estén permitidas para las acciones solicitadas. Si no están permitidas, lanzara una excepción de tipo HTTP 405. En el siguiente ejemplo, se declara VerbFilter para especificar el conjunto típico métodos de petición permitidos para acciones CRUD.
VerbFilter comprueba que los métodos de las peticiones HTTP estén permitidas para las acciones solicitadas. Si no
están permitidas, lanzara una excepción de tipo HTTP 405. En el siguiente ejemplo, se declara VerbFilter para
especificar el conjunto típico métodos de petición permitidos para acciones CRUD.
```php
useyii\filters\VerbFilter;
...
...
@@ -272,8 +322,14 @@ public function behaviors()
### [[yii\filters\Cors|Cors]] <a name="cors"></a>
(CORS)[https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS] es un mecanismo que permite a diferentes recursos (por ejemplo: fuentes, JavaScript, etc) de una pagina Web ser solicitados por otro dominio diferente al dominio que esta haciendo la petición. En particular las llamadas AJAX de JavasCript pueden utilizar el mecanismo XMLHttpRequest. De otro modo esta petición de dominio cruzado seria prohibida por los navegadores Web, por la misma pollita de seguridad de origen. CORS establece la manera en que el navegador y el servidor pueden interaccionar para determinar si se permite o no la petición de dominio cruzado.
El filtro [[yii\filters\Cors|Cors filter]] puede ser definido antes de los filtros Autenticación / Autorización para asegurar que las cabeceras de CORS siempre serán enviadas.
(CORS)[https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS] es un mecanismo que permite a diferentes
recursos (por ejemplo: fuentes, JavaScript, etc) de una pagina Web ser solicitados por otro dominio diferente al
dominio que esta haciendo la petición. En particular las llamadas AJAX de JavaScript pueden utilizar el mecanismo
XMLHttpRequest. De otro modo esta petición de dominio cruzado seria prohibida por los navegadores Web, por la misma
pollita de seguridad de origen. CORS establece la manera en que el navegador y el servidor pueden interaccionar para
determinar si se permite o no la petición de dominio cruzado. El filtro [[yii\filters\Cors|Cors filter]] puede ser
definido antes de los filtros Autenticación / Autorización para asegurar que las cabeceras de CORS siempre serán
enviadas.
```php
useyii\filters\Cors;
...
...
@@ -291,12 +347,17 @@ public function behaviors()
El filtrado CORS puede ser ajustado utilizando la propiedad 'cors'.
*`cors['Origin']`: array utilizado para definir los origenes permitidos. Puede ser `['*']` (everyone) o `['http://www.myserver.net', 'http://www.myotherserver.com']`. Por defecto `['*']`.
*`cors['Access-Control-Request-Method']`: array de los verbos permitidos como `['GET', 'OPTIONS', 'HEAD']`. Por defecto `['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']`.
*`cors['Access-Control-Request-Headers']`: array de las cabeceras permitidas. Puede ser `['*']` todas las cabeceras o algunas especificas `['X-Request-With']`. Por defecto `['*']`.
*`cors['Access-Control-Allow-Credentials']`: define si la petición actual puede hacer uso de credenciales. Puede ser `true`, `false` o `null` (not set). Por defecto `null`.
*`cors['Access-Control-Max-Age']`: define el tiempo de vida del la petición pref-flight. Por defecto `86400`.
Por ejemplo, habilitar CORS para el origen: `http://www.myserver.net` con metodos `GET`, `HEAD` y `OPTIONS` :
*`cors['Origin']`: array utilizado para definir los orígenes permitidos. Puede ser `['*']` (everyone) o
`['http://www.myserver.net', 'http://www.myotherserver.com']`. Por defecto `['*']`.
*`cors['Access-Control-Request-Method']`: array de los verbos permitidos como `['GET', 'OPTIONS', 'HEAD']`. Por
*`cors['Access-Control-Request-Headers']`: array de las cabeceras permitidas. Puede ser `['*']` todas las cabeceras o
algunas especificas `['X-Request-With']`. Por defecto `['*']`.
*`cors['Access-Control-Allow-Credentials']`: define si la petición actual puede hacer uso de credenciales. Puede ser
`true`, `false` o `null` (not set). Por defecto `null`.
*`cors['Access-Control-Max-Age']`: define el tiempo de vida del la petición pref-flight. Por defecto `86400`. Por
ejemplo, habilitar CORS para el origen: `http://www.myserver.net` con métodos `GET`, `HEAD` y `OPTIONS`:
```php
useyii\filters\Cors;
useyii\helpers\ArrayHelper;
...
...
@@ -315,7 +376,8 @@ public function behaviors()
}
```
Se pueden ajustar las cabeceras de CORS sobrescribiendo los parámetros por defecto de una acción. Por ejemplo añadir `Access-Control-Allow-Credentials` a la acción 'login', se podría hacer así:
Se pueden ajustar las cabeceras de CORS sobrescribiendo los parámetros por defecto de una acción. Por ejemplo añadir
`Access-Control-Allow-Credentials` a la acción 'login', se podría hacer así:
Los modelos forman parte de la arquitectura [MVC](http://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador). Son objetos que representan datos de negocio, reglas y lógica.
Los modelos forman parte de la arquitectura
[MVC](http://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador). Son objetos que representan datos de
negocio, reglas y lógica.
Se pueden crear clases modelo extendiendo a [[yii\base\Model]] o a sus clases hijas. La clase base [[yii\base\Model]] soporta muchas características útiles:
Se pueden crear clases modelo extendiendo a [[yii\base\Model]] o a sus clases hijas. La clase base [[yii\base\Model]]
soporta muchas características útiles:
*[Atributos](#attributes): representan los datos de negocio y se puede acceder a ellos como propiedades normales de un objeto o como elementos de un array;
*[Atributos](#attributes): representan los datos de negocio y se puede acceder a ellos como propiedades normales de
un objeto o como elementos de un array;
*[Etiquetas de atributo](#attribute-labels): especifica la etiqueta a mostrar para los atributos;
*[Asignación masiva](#massive-assignment): soporta la asignación múltiple de atributos en un único paso;
*[validación](#validation-rules): asegura la validez de los datos de entrada basándose en reglas declaradas;
*[Exportación de datos](#data-exporting): permite que los datos del modelo sean exportados en términos de arrays con formatos personalizables.
*[Exportación de datos](#data-exporting): permite que los datos del modelo sean exportados en términos de arrays con
formatos personalizables.
La clase 'modelo' también es una base para modelos más avanzados, tales como [Active Records](db-active-record.md).
>Info: No es obligatorio basar las clases modelo en [[yii\base\Model]]. Sin embargo, debido a que hay muchos componentes de Yii construidos para dar soporte a [[yii\base\Model]], por lo general es la clase base preferible para un modelo.
> Información: No es obligatorio basar las clases modelo en [[yii\base\Model]]. Sin embargo, debido a que hay muchos
componentes de Yii construidos para dar soporte a [[yii\base\Model]], por lo general, es la clase base preferible
para un modelo.
### Atributos <a name="attributes"></a>
Los modelos representan los datos de negocio en términos de *atributos*. Cada atributos es como una propiedad públicamente accesible de un modelo. El método [[yii\base\Model::attributes()]] especifica qué atributos tiene la clase modelo.
Los modelos representan los datos de negocio en términos de *atributos*. Cada atributos es como una propiedad
públicamente accesible de un modelo. El método [[yii\base\Model::attributes()]] especifica qué atributos tiene la
clase modelo.
Se puede acceder a un atributo como se accede a una propiedad de un objeto normal.
...
...
@@ -29,7 +38,9 @@ $model->name = 'example';
echo$model->name;
```
También se puede acceder a los atributos como se accede a los elementos de un array, gracias al soporte para [ArrayAccess](http://php.net/manual/es/class.arrayaccess.php) y [ArrayIterator](http://php.net/manual/es/class.arrayiterator.php) que brinda [[yii\base\Model]]:
También se puede acceder a los atributos como se accede a los elementos de un array, gracias al soporte para
[ArrayAccess](http://php.net/manual/es/class.arrayaccess.php) y
[ArrayIterator](http://php.net/manual/es/class.arrayiterator.php) que brinda [[yii\base\Model]]:
Por defecto, si un modelo extiende directamente a [[yii\base\Model]], todas sus variables miembro no estáticas son atributos. Por ejemplo, la siguiente clase modelo 'ContactForm' tiene cuatro atributos: 'name', 'email', 'subject', 'body'. El modelo 'ContactForm' se usa para representar los datos de entrada recibidos desde un formulario HTML.
Por defecto, si un modelo extiende directamente a [[yii\base\Model]], todas sus variables miembro no estáticas son
atributos. Por ejemplo, la siguiente clase modelo 'ContactForm' tiene cuatro atributos: 'name', 'email', 'subject',
'body'. El modelo 'ContactForm' se usa para representar los datos de entrada recibidos desde un formulario HTML.
```php
namespace app\models;
...
...
@@ -62,13 +75,20 @@ class ContactForm extends Model
}
```
Se puede sobrescribir [[yii\base\Model::attributes()]] para definir los atributos de diferente manera. El método debe devolver los nombres de los atributos de un modelo. Por ejemplo [[yii\db\ActiveRecord]] lo hace devolviendo el nombre de las columnas de la tabla de la base de datos asociada como el nombre de sus atributos. Hay que tener en cuenta que también puede necesitar sobrescribir los métodos mágicos como `__get()`, `__set()` de modo que se puede acceder a los atributos como a propiedades de objetos normales.
Se puede sobrescribir [[yii\base\Model::attributes()]] para definir los atributos de diferente manera. El método debe
devolver los nombres de los atributos de un modelo. Por ejemplo [[yii\db\ActiveRecord]] lo hace devolviendo el nombre
de las columnas de la tabla de la base de datos asociada como el nombre de sus atributos. Hay que tener en cuenta que
también puede necesitar sobrescribir los métodos mágicos como `__get()`, `__set()` de modo que se puede acceder a los
atributos como a propiedades de objetos normales.
### Etiquetas de atributo <a name="attribute-labels"></a>
Cuando se muestran valores o se obtienen entradas para atributos, normalmente se necesita mostrar etiquetas asociadas a los atributos. Por ejemplo, dado un atributo con nombre 'segundoApellido', es posible que se quiera mostrar la etiqueta 'Segundo Apellido' ya que es más fácil de interpretar por el usuario final en lugares como campos de formularios y en mensajes de error.
Cuando se muestran valores o se obtienen entradas para atributos, normalmente se necesita mostrar etiquetas asociadas
a los atributos. Por ejemplo, dado un atributo con nombre 'segundoApellido', es posible que se quiera mostrar la
etiqueta 'Segundo Apellido' ya que es más fácil de interpretar por el usuario final en lugares como campos de
formularios y en mensajes de error.
Se puede obtener la etiqueta de un atributo llamando a [[yii\base\Model::getAttributeLabel()]]. Por ejemplo:
Se puede obtener la etiqueta de un atributo llamando a [[yii\base\Model::getAttributeLabel()]]. Por ejemplo:
```php
$model = new \app\models\ContactForm;
...
...
@@ -77,8 +97,12 @@ $model = new \app\models\ContactForm;
echo $model->getAttributeLabel('name');
```
Por defecto, una etiqueta de atributo se genera automáticamente a partir del nombre de atributo. La generación se hace con el método [[yii\base\Model::generateAttributeLabel()]]. Este convertirá los nombres de variables de tipo came-case en múltiples palabras con la primera letra de cada palabra en mayúsculas. Por ejemplo 'usuario' se convertirá en 'Nombre', y 'primerApellido' se convertirá en 'Primer Apellido'.
Si no se quieren usar las etiquetas generadas automáticamente, se puede sobrescribir [[yii\base\Model::attributeLabels()]] a una declaración de etiquetas de atributo especifica. Por ejemplo:
Por defecto, una etiqueta de atributo se genera automáticamente a partir del nombre de atributo. La generación se hace
con el método [[yii\base\Model::generateAttributeLabel()]]. Este convertirá los nombres de variables de tipo
camel-case en múltiples palabras con la primera letra de cada palabra en mayúsculas. Por ejemplo 'usuario' se
convertirá en 'Nombre', y 'primerApellido' se convertirá en 'Primer Apellido'.
Si no se quieren usar las etiquetas generadas automáticamente, se puede sobrescribir
[[yii\base\Model::attributeLabels()]] a una declaración de etiquetas de atributo especifica. Por ejemplo:
```php
namespace app\models;
...
...
@@ -104,7 +128,8 @@ class ContactForm extends Model
}
```
Para aplicaciones con soporte para múltiples idiomas, se puede querer traducir las etiquetas de los atributos. Esto se puede hacer en el método [[yii\base\Model::attributeLabels()|attributeLabels()]], como en el siguiente ejemplo:
Para aplicaciones con soporte para múltiples idiomas, se puede querer traducir las etiquetas de los atributos. Esto se
puede hacer en el método [[yii\base\Model::attributeLabels()|attributeLabels()]], como en el siguiente ejemplo:
```php
public function attributeLabels()
...
...
@@ -118,15 +143,22 @@ public function attributeLabels()
}
```
Incluso se puede definir etiquetas de atributo condicionales. Por ejemplo, basándose en el [escenario](#scenarios) en que se esta usando el modelo, se pueden devolver diferentes etiquetas para un mismo atributo.
Incluso se puede definir etiquetas de atributo condicionales. Por ejemplo, basándose en el [escenario](#scenarios) en
que se esta usando el modelo, se pueden devolver diferentes etiquetas para un mismo atributo.
> Info: Estrictamente hablando, los atributos son parte de las [vistas](structure-views.md). Pero declarar las etiquetas en los modelos, a menudo, es muy conveniente y puede generar a un código muy limpio y reutilizable.
> Información: Estrictamente hablando, los atributos son parte de las [vistas](structure-views.md). Pero declarar las
etiquetas en los modelos, a menudo, es muy conveniente y puede generar a un código muy limpio y reutilizable.
## Escenarios <a name="scenarios"></a>
Un modelo puede usarse en diferentes *escenarios*. Por ejemplo, un modelo 'Usuario', puede ser utilizado para recoger entradas de inicio de sesión de usuarios, pero también puede usarse para generar usuarios. En diferentes escenarios, un modelo puede usar diferentes reglas de negocio y lógica. Por ejemplo, un atributo 'email' puede ser requerido durante un registro de usuario, pero no ser necesario durante el inicio de sesión del mismo.
Un modelo puede usarse en diferentes *escenarios*. Por ejemplo, un modelo 'Usuario', puede ser utilizado para recoger
entradas de inicio de sesión de usuarios, pero también puede usarse para generar usuarios. En diferentes escenarios,
un modelo puede usar diferentes reglas de negocio y lógica. Por ejemplo, un atributo 'email' puede ser requerido
durante un registro de usuario, pero no ser necesario durante el inicio de sesión del mismo.
Un modelo utiliza la propiedad [[yii\base\Model::scenario]] para mantener saber en qué escenario se esta usando. Por defecto, un modelo soporta sólo un escenario llamado 'default'. El siguiente código muestra dos maneras de establecer el escenario en un modelo.
Un modelo utiliza la propiedad [[yii\base\Model::scenario]] para mantener saber en qué escenario se esta usando. Por
defecto, un modelo soporta sólo un escenario llamado 'default'. El siguiente código muestra dos maneras de establecer
el escenario en un modelo.
```php
// el escenario se establece como una propiedad
...
...
@@ -137,7 +169,9 @@ $model->scenario = 'login';
$model = new User(['scenario' => 'login']);
```
Por defecto, los escenarios soportados por un modelo se determinan por las [reglas de validación](#validation-rules) declaradas en el modelo. Sin embargo, se puede personalizar este comportamiento sobrescribiendo el método [[yii\base\Model::scenarios()]], como en el siguiente ejemplo:
Por defecto, los escenarios soportados por un modelo se determinan por las [reglas de validación](#validation-rules)
declaradas en el modelo. Sin embargo, se puede personalizar este comportamiento sobrescribiendo el método
[[yii\base\Model::scenarios()]], como en el siguiente ejemplo:
```php
namespace app\models;
...
...
@@ -156,11 +190,18 @@ class User extends ActiveRecord
}
```
> Info: En el anterior y en los siguientes ejemplos, las clases modelo extienden a [[yii\db\ActiveRecord]] porque el uso de múltiples escenarios normalmente sucede con clases de [Active Records](db-active-record.md).
> Información: En el anterior y en los siguientes ejemplos, las clases modelo extienden a [[yii\db\ActiveRecord]]
porque el uso de múltiples escenarios normalmente sucede con clases de [Active Records](db-active-record.md).
El método 'scenarios()' devuelve un array cuyas claves son el nombre de escenario y los valores correspondientes a los *atributos activos*. Un atributo activo puede ser [asignado masivamente](#massive-assignment) y esta sujeto a [validación](#validation-rules). En el anterior ejemplo, los atributos 'username' y 'password' están activados en el escenario 'login'; mientras que en el escenario 'register', el atributo 'email' esta activado junto con 'username' y 'password'.
El método 'scenarios()' devuelve un array cuyas claves son el nombre de escenario y los valores correspondientes a los
*atributos activos*. Un atributo activo puede ser [asignado masivamente](#massive-assignment) y esta sujeto a
[validación](#validation-rules). En el anterior ejemplo, los atributos 'username' y 'password' están activados en el
escenario 'login'; mientras que en el escenario 'register', el atributo 'email' esta activado junto con 'username' y
'password'.
La implementación por defecto de los 'scenarios()' devolverá todos los escenarios encontrados en el método de declaración de las reglas de validación [[yii\base\Model::rules()]]. Cuando se sobrescribe 'scenarios()', si se quiere introducir nuevos escenarios además de los predeterminados, se puede hacer como en el siguiente ejemplo:
La implementación por defecto de los 'scenarios()' devolverá todos los escenarios encontrados en el método de
declaración de las reglas de validación [[yii\base\Model::rules()]]. Cuando se sobrescribe 'scenarios()', si se quiere
introducir nuevos escenarios además de los predeterminados, se puede hacer como en el siguiente ejemplo:
```php
namespace app\models;
...
...
@@ -179,13 +220,22 @@ class User extends ActiveRecord
}
```
La característica escenario se usa principalmente en las [validaciones](#validation-rules) y por la [asignación masiva de atributos](#massive-assignment). Aunque también se puede usar para otros propósitos. Por ejemplo, se pueden declarar [etiquetas de atributo](#attribute-labels) diferentes basándose en el escenario actual.
La característica escenario se usa principalmente en las [validaciones](#validation-rules) y por la
[asignación masiva de atributos](#massive-assignment). Aunque también se puede usar para otros propósitos. Por
ejemplo, se pueden declarar [etiquetas de atributo](#attribute-labels) diferentes basándose en el escenario actual.
## Reglas de Validación <a name="validation-rules"></a>
Cuando un modelo recibe datos del usuario final, estos deben ser validados para asegurar que cumplan ciertas reglas (llamadas *reglas de validación*, también conocidas como *reglas de negocio*). Por ejemplo, dado un modelo 'ContactForm', se puede querer asegurar que ningún atributo este vacío y que el atributo 'email' contenga una dirección de correo válida. Si algún valor no cumple con las reglas, se debe mostrar el mensaje de error apropiado para ayudar al usuario a corregir estos errores.
Cuando un modelo recibe datos del usuario final, estos deben ser validados para asegurar que cumplan ciertas reglas
(llamadas *reglas de validación*, también conocidas como *reglas de negocio*). Por ejemplo, dado un modelo
'ContactForm', se puede querer asegurar que ningún atributo este vacío y que el atributo 'email' contenga una
dirección de correo válida. Si algún valor no cumple con las reglas, se debe mostrar el mensaje de error apropiado
para ayudar al usuario a corregir estos errores.
Se puede llamar a [[yii\base\Model::validate()]] para validar los datos recibidos. El método se usará para validar las reglas declaradas en [[yii\base\Model::rules()]] para validar cada atributo relevante. Si no se encuentran errores, se devolverá true. De otro modo, este almacenará los errores en la propiedad [[yii\base\Model::errors]] y devolverá falso. Por ejemplo:
Se puede llamar a [[yii\base\Model::validate()]] para validar los datos recibidos. El método se usará para validar las
reglas declaradas en [[yii\base\Model::rules()]] para validar cada atributo relevante. Si no se encuentran errores, se
devolverá true. De otro modo, este almacenará los errores en la propiedad [[yii\base\Model::errors]] y devolverá falso.
Por ejemplo:
```php
$model = new \app\models\ContactForm;
...
...
@@ -201,7 +251,9 @@ if ($model->validate()) {
}
```
Para declarar reglas de validación asociadas a un modelo, se tiene que sobrescribir el método [[yii\base\Model::rules()]] para que devuelva las reglas que los atributos del modelo deben satisfacer. El siguiente ejemplo muestra las reglas de validación declaradas para el modelo 'ContactForm'.
Para declarar reglas de validación asociadas a un modelo, se tiene que sobrescribir el método
[[yii\base\Model::rules()]] para que devuelva las reglas que los atributos del modelo deben satisfacer. El siguiente
ejemplo muestra las reglas de validación declaradas para el modelo 'ContactForm'.
```php
public function rules()
...
...
@@ -216,9 +268,12 @@ public function rules()
}
```
Una regla puede usarse para validar uno o más atributos, y un atributo puede validarse por una o múltiples reglas. Por favor refiérase a la sección [Validación de entrada](input-validation.md) para obtener más detalles sobre cómo declarar reglas de validación.
Una regla puede usarse para validar uno o más atributos, y un atributo puede validarse por una o múltiples reglas. Por
favor refiérase a la sección [Validación de entrada](input-validation.md) para obtener más detalles sobre cómo
declarar reglas de validación.
A veces, solamente se quiere aplicar una regla en ciertos [escenarios](#scenarios). Para hacerlo, se puede especificar la propiedad 'on' de una regla, como en el siguiente ejemplo:
A veces, solamente se quiere aplicar una regla en ciertos [escenarios](#scenarios). Para hacerlo, se puede especificar
la propiedad 'on' de una regla, como en el siguiente ejemplo:
```php
public function rules()
...
...
@@ -233,13 +288,19 @@ public function rules()
}
```
Si no se especifica la propiedad 'on', la regla se aplicará en todos los escenarios. Se llama a una regla *regla activa* si esta puede aplicarse en el [[yii\base\Model::scenario|scenario]] actual.
Si no se especifica la propiedad 'on', la regla se aplicará en todos los escenarios. Se llama a una regla
*regla activa* si esta puede aplicarse en el [[yii\base\Model::scenario|scenario]] actual.
Un atributo será validado si y sólo si es un atributo activo declarado en 'scenarios()' y esta asociado con una o más reglas activas declaradas en 'rules()'.
Un atributo será validado si y sólo si es un atributo activo declarado en 'scenarios()' y esta asociado con una o más
La asignación masiva es una buena forma de rellenar los atributos de un modelo con las entradas de usuario en una única línea de código. Rellena los atributos de un modelo asignando los datos de entrada directamente a las propiedades de [[yii\base\Model::$attributes]]. Los siguientes dos ejemplos son equivalentes, ambos intentan asignar los datos enviados por el usuario final a través de un formulario a los atributos del modelo 'ContactForm'. Claramente, el primero, que usa la asignación masiva, es más claro y menos propenso a errores que el segundo:
La asignación masiva es una buena forma de rellenar los atributos de un modelo con las entradas de usuario en una
única línea de código. Rellena los atributos de un modelo asignando los datos de entrada directamente a las
propiedades de [[yii\base\Model::$attributes]]. Los siguientes dos ejemplos son equivalentes, ambos intentan asignar
los datos enviados por el usuario final a través de un formulario a los atributos del modelo 'ContactForm'.
Claramente, el primero, que usa la asignación masiva, es más claro y menos propenso a errores que el segundo:
La asignación masiva sólo se aplica a los llamados *atributos seguros* qué son los atributos listados en [[yii\base\Model::scenarios()]] para el actual [[yii\base\Model::scenario|scenario]] del modelo. Por ejemplo, si en el modelo 'User' tenemos la siguiente declaración de escenario, entonces cuando el escenario actual sea 'login', sólo los atributos 'username' y 'password' podrán ser asignados masivamente. Cualquier otro atributo permanecerá intacto
La asignación masiva sólo se aplica a los llamados *atributos seguros* qué son los atributos listados en
[[yii\base\Model::scenarios()]] para el actual [[yii\base\Model::scenario|scenario]] del modelo. Por ejemplo, si en el
modelo 'User' tenemos la siguiente declaración de escenario, entonces cuando el escenario actual sea 'login', sólo los
atributos 'username' y 'password' podrán ser asignados masivamente. Cualquier otro atributo permanecerá intacto
```php
public function scenarios()
...
...
@@ -269,11 +333,18 @@ public function scenarios()
}
```
> Info: La razón de que la asignación masiva sólo se aplique a los atributos seguros es debida a que se quiere controlar qué atributos pueden ser modificados por los datos del usuario final. Por ejemplo, si el modelo 'User' tiene un atributo 'permission' que determina los permisos asignados al usuario, se quiere que estos atributos sólo sean modificados por administradores desde la interfaz backend.
> Información: La razón de que la asignación masiva sólo se aplique a los atributos seguros es debida a que se quiere
controlar qué atributos pueden ser modificados por los datos del usuario final. Por ejemplo, si el modelo 'User' tiene
un atributo 'permission' que determina los permisos asignados al usuario, se quiere que estos atributos sólo sean
modificados por administradores desde la interfaz backend.
Debido a hecho que la implementación por defecto de [[yii\base\Model::scenarios()]] devolverá todos los escenarios y atributos encontrados en[[yii\base\Model::rules()]], si no se sobrescribe este método, significa que un atributo es seguro mientras aparezca en una de las reglas de validación activas.
Debido a que la implementación predeterminada de [[yii\base\Model::scenarios()]] devolverá todos los escenarios y
atributos encontrados en [[yii\base\Model::rules()]], si no se sobrescribe este método, significa que un atributo es
seguro mientras aparezca en una de las reglas de validación activas.
Por esta razón, se proporciona un validador especial con alias 'safe' con el que se puede declarar un atributo como seguro sin llegar a validarlo. Por ejemplo, las siguientes reglas declaran que los atributos 'title' y 'description' son atributos seguros.
Por esta razón, se proporciona un validador especial con alias 'safe' con el que se puede declarar un atributo como
seguro sin llegar a validarlo. Por ejemplo, las siguientes reglas declaran que los atributos 'title' y 'description'
Como se ha descrito anteriormente, el método [[yii\base\Model::scenarios()]] sirve para dos propósitos: determinar qué atributos deben ser validados y determinar qué atributos son seguros. En situaciones poco comunes, se puede querer validar un atributo pero sin marcarlo como seguro. Se puede hacer prefijando el signo de exclamación '!' delante del nombre del atributo cuando se declaran en 'scenarios()', como el atributo 'secret' del siguiente ejemplo:
Como se ha descrito anteriormente, el método [[yii\base\Model::scenarios()]] sirve para dos propósitos: determinar qué
atributos deben ser validados y determinar qué atributos son seguros. En situaciones poco comunes, se puede querer
validar un atributo pero sin marcarlo como seguro. Se puede hacer prefijando el signo de exclamación '!' delante del
nombre del atributo cuando se declaran en 'scenarios()', como el atributo 'secret' del siguiente ejemplo:
```php
public function scenarios()
...
...
@@ -297,7 +371,9 @@ public function scenarios()
}
```
Cuando el modelo esté en el escenario 'login', los tres atributos serán validados. Sin embargo, sólo los atributos 'username' y 'password' se asignarán masivamente. Para asignar un valor de entrada al atribuido 'secret', se tendrá que hacer explícitamente como en el ejemplo:
Cuando el modelo esté en el escenario 'login', los tres atributos serán validados. Sin embargo, sólo los atributos
'username' y 'password' se asignarán masivamente. Para asignar un valor de entrada al atribuido 'secret', se tendrá
que hacer explícitamente como en el ejemplo:
```php
$model->secret = $secret;
...
...
@@ -305,27 +381,50 @@ $model->secret = $secret;
## Exportación de Datos <a name="data-exporting"></a>
A menudo necesitamos exportar modelos a diferentes formatos. Por ejemplo, se puede querer convertir un conjunto de modelos a formato JSON o Excel. El proceso de exportación se puede dividir en dos pasos independientes. En el primer paso, se convierten los modelos en arrays; en el segundo paso, los arrays se convierten a los formatos deseados. Nos puede interesar fijarnos en el primer paso, ya que el segundo paso se puede lograr mediante un formateador de datos genérico, tal como [[yii\web\JsonResponseFormatter]].
La manera más simple de convertir un modelo en un array es usar la propiedad [[yii\base\Model::$attributes]]. Por ejemplo:
A menudo necesitamos exportar modelos a diferentes formatos. Por ejemplo, se puede querer convertir un conjunto de
modelos a formato JSON o Excel. El proceso de exportación se puede dividir en dos pasos independientes. En el primer
paso, se convierten los modelos en arrays; en el segundo paso, los arrays se convierten a los formatos deseados. Nos
puede interesar fijarnos en el primer paso, ya que el segundo paso se puede lograr mediante un formateador de datos
genérico, tal como [[yii\web\JsonResponseFormatter]].
La manera más simple de convertir un modelo en un array es usar la propiedad [[yii\base\Model::$attributes]]. Por
ejemplo:
```php
$post = \app\models\Post::findOne(100);
$array = $post->attributes;
```
Por defecto, la propiedad [[yii\base\Model::$attributes]] devolverá los valores de *todos* los atributos declarados en [[yii\base\Model::attributes()]].
Por defecto, la propiedad [[yii\base\Model::$attributes]] devolverá los valores de *todos* los atributos declarados en
[[yii\base\Model::attributes()]].
Una manera más flexible y potente de convertir un modelo en un array es usar el método [[yii\base\Model::toArray()]]. Su funcionamiento general es el mismo que el de [[yii\base\Model::$attributes]]. Sin embargo, este permite elegir que elementos de datos, llamados *campos*, queremos poner en el array resultante y elegir como debe ser formateado. De hecho, es la manera por defecto de exportar modelos en desarrollo de servicios Web RESTful, tal y como se describe en [Formatos de Respuesta](rest-response-formatting.md).
Una manera más flexible y potente de convertir un modelo en un array es usar el método [[yii\base\Model::toArray()]].
Su funcionamiento general es el mismo que el de [[yii\base\Model::$attributes]]. Sin embargo, este permite elegir que
elementos de datos, llamados *campos*, queremos poner en el array resultante y elegir como debe ser formateado. De
hecho, es la manera por defecto de exportar modelos en desarrollo de servicios Web RESTful, tal y como se describe en
[Formatos de Respuesta](rest-response-formatting.md).
### Campos <a name="fields"></a>
Un campo es simplemente un elemento nombrado en el array resultante de ejecutar el método [[yii\base\Model::toArray()]] de un modelo.
Por defecto, los nombres de los campos son equivalentes a los nombres de los atributos. Sin embargo, se puede modificar este comportamiento sobrescribiendo el método [[yii\base\Model::fields()|fields()]] y/o el método [[yii\base\Model::extraFields()|extraFields()]]. Ambos métodos deben devolver una lista de las definiciones de los campos. Los campos definidos mediante 'fields()' son los campos por defecto, esto significa que 'toArray()' devolverá estos campos por defecto. El método 'extraFields()' define campos adicionalmente disponibles que también pueden devolverse mediante 'toArray()' siempre y cuando se especifiquen a través del parámetro '$expand'. Por ejemplo, el siguiente código devolverá todos los campos definidos en 'fields()' y los campos 'prettyName' y 'fullAdress' si estos están definidos en 'extraFields()'.
Un campo es simplemente un elemento nombrado en el array resultante de ejecutar el método [[yii\base\Model::toArray()]]
de un modelo.
Por defecto, los nombres de los campos son equivalentes a los nombres de los atributos. Sin embargo, se puede
modificar este comportamiento sobrescribiendo el método [[yii\base\Model::fields()|fields()]] y/o el método
[[yii\base\Model::extraFields()|extraFields()]]. Ambos métodos deben devolver una lista de las definiciones de los
campos. Los campos definidos mediante 'fields()' son los campos por defecto, esto significa que 'toArray()' devolverá
estos campos por defecto. El método 'extraFields()' define campos adicionalmente disponibles que también pueden
devolverse mediante 'toArray()' siempre y cuando se especifiquen a través del parámetro '$expand'. Por ejemplo, el
siguiente código devolverá todos los campos definidos en 'fields()' y los campos 'prettyName' y 'fullAdress' si estos
Se puede sobrescribir 'fields()' para añadir, eliminar, renombrar o redefinir campos. El valor devuelto por 'fields()' debe se un array. Las claves del array son los nombres de los campos, y los valores son las correspondientes definiciones de los campos que pueden ser nombres de propiedades/atributos o funciones anónimas que devuelvan los correspondientes valores de campo. En el caso especial en que un nombre de un campo es el mismo a su definición de nombre de atributo, se puede omitir la clave del array. Por ejemplo:
Se puede sobrescribir 'fields()' para añadir, eliminar, renombrar o redefinir campos. El valor devuelto por 'fields()'
debe se un array. Las claves del array son los nombres de los campos, y los valores son las correspondientes
definiciones de los campos que pueden ser nombres de propiedades/atributos o funciones anónimas que devuelvan los
correspondientes valores de campo. En el caso especial en que un nombre de un campo es el mismo a su definición de
nombre de atributo, se puede omitir la clave del array. Por ejemplo:
```php
// lista explícitamente cada campo, es mejor usarlo cuando nos queremos asegurar
...
...
@@ -360,23 +459,42 @@ public function fields()
}
```
>Atención: debido a que por defecto todos los atributos de un modelo serán incluidos en el array exportado, se debe examinar los datos para asegurar que no contienen información sensible. Si existe dicha información, se debe sobrescribir 'fields()' para filtrarla. En el anterior ejemplo, se filtra 'aut_key', 'password_hash' y 'password_reset_token'.
> Atención: debido a que por defecto todos los atributos de un modelo serán incluidos en el array exportado, se debe
examinar los datos para asegurar que no contienen información sensible. Si existe dicha información, se debe
sobrescribir 'fields()' para filtrarla. En el anterior ejemplo, se filtra 'aut_key', 'password_hash' y
Los modelos son los lugares centrales para representar datos de negocio, reglas y lógica. Estos a menudo necesitan ser reutilizados en diferentes lugares. En una aplicación bien diseñada, los modelos normalmente son más grandes que los [controladores](structure-controllers.md).
Los modelos son los lugares centrales para representar datos de negocio, reglas y lógica. Estos a menudo necesitan ser
reutilizados en diferentes lugares. En una aplicación bien diseñada, los modelos normalmente son más grandes que los
[controladores](structure-controllers.md).
En resumen, los modelos:
* pueden contener atributos para representar los datos de negocio;
* pueden contener reglas de validación para asegurar la validez e integridad de los datos;
* pueden contener métodos que para implementar la lógica de negocio;
* NO deben acceder directamente a peticiones, sesiones, u otro tipo de datos de entorno. Estos datos deben ser inyectados por los [controladores](structure-controllers.md) en los modelos.
* NO deben acceder directamente a peticiones, sesiones, u otro tipo de datos de entorno. Estos datos deben ser
inyectados por los [controladores](structure-controllers.md) en los modelos.
* deben evitar embeber HTML u otro código de presentación – esto es mejor hacerlo en las [vistas](structure-views.md);
* evitar tener demasiados [escenarios](#scenarios) en un mismo modelo.
Generalmente se puede considerar la última recomendación cuando se estén desarrollando grandes sistemas complejos. En estos sistemas, los modelos podrían ser muy grandes debido a que podrían ser usados en muchos lugares y por tanto contener muchos conjuntos de reglas y lógicas de negocio. A menudo esto desemboca en un código muy difícil de mantener ya que una simple modificación en el código puede afectar a muchos sitios diferentes. Para mantener el código más fácil de mantener, se puede seguir la siguiente estrategia:
* Definir un conjunto de clases modelo base que sean compartidas por diferentes [aplicaciones](structure-applications.md) o [módulos](structure-modules.md). Estas clases modelo deben contener el conjunto mínimo de reglas y lógica que sean comunes para todos sus usos.
* En cada [aplicación](structure-applications.md) o [módulo](structure-modules.md) que use un modelo, definir una clase modelo concreta que extienda a la correspondiente clase modelo base. La clase modelo concreta debe contener reglas y lógica que sean específicas para esa aplicación o módulo.
Por ejemplo, en la [Plantilla de Aplicación Avanzada](tutorial-advanced-app.md), definiendo una clase modelo base 'common\models\Post'. Después en la aplicación front end, definiendo y usando una clase modelo concreta 'frontend\models\Post' que extienda a 'common\models\Post'. Y de forma similar en la aplicación back end, definiendo 'backend\models\Post'. Con esta estrategia, nos aseguramos que el código de 'frontend\models\Post' es específico para la aplicación front end, y si se efectúa algún cambio en el, no nos tenemos que preocupar de si el cambio afectará a la aplicación back end.
Generalmente se puede considerar la última recomendación cuando se estén desarrollando grandes sistemas complejos. En
estos sistemas, los modelos podrían ser muy grandes debido a que podrían ser usados en muchos lugares y por tanto
contener muchos conjuntos de reglas y lógicas de negocio. A menudo esto desemboca en un código muy difícil de mantener
ya que una simple modificación en el código puede afectar a muchos sitios diferentes. Para mantener el código más
fácil de mantener, se puede seguir la siguiente estrategia:
* Definir un conjunto de clases modelo base que sean compartidas por diferentes
[aplicaciones](structure-applications.md) o [módulos](structure-modules.md). Estas clases modelo deben contener el
conjunto mínimo de reglas y lógica que sean comunes para todos sus usos.
* En cada [aplicación](structure-applications.md) o [módulo](structure-modules.md) que use un modelo, definir una
clase modelo concreta que extienda a la correspondiente clase modelo base. La clase modelo concreta debe contener
reglas y lógica que sean específicas para esa aplicación o módulo.
Por ejemplo, en la [Plantilla de Aplicación Avanzada](tutorial-advanced-app.md), definiendo una clase modelo base
'common\models\Post'. Después en la aplicación front end, definiendo y usando una clase modelo concreta
'frontend\models\Post' que extienda a 'common\models\Post'. Y de forma similar en la aplicación back end, definiendo
'backend\models\Post'. Con esta estrategia, nos aseguramos que el código de 'frontend\models\Post' es específico para
la aplicación front end, y si se efectúa algún cambio en el, no nos tenemos que preocupar de si el cambio afectará a
Los módulos son unidades de software independientes que consisten en [modelos](structure-models.md), [vistas](structure-views.md), [controladores](structure-controllers.md), y otros componentes de apoyo. Los usuarios finales pueden acceder a los controladores de un módulo cuando éste está instalado en la [aplicación](structure-applications.md). Por éstas razones, los módulos a menudo se considerados como mini-aplicaciones. Los módulos difieren de las [aplicaciones](structure-applications.md) en que los módulos no pueden ser desplegados solos y tienen que residir dentro de aplicaciones.
Los módulos son unidades de software independientes que consisten en [modelos](structure-models.md),
[vistas](structure-views.md), [controladores](structure-controllers.md), y otros componentes de apoyo. Los usuarios
finales pueden acceder a los controladores de un módulo cuando éste está instalado en la
[aplicación](structure-applications.md). Por éstas razones, los módulos a menudo se considerados como
mini-aplicaciones. Los módulos difieren de las [aplicaciones](structure-applications.md) en que los módulos no pueden
ser desplegados solos y tienen que residir dentro de aplicaciones.
## Creación de Módulos<a name="creating-modules"></a>
Un módulo está organizado de tal manera que contiene un directorio llamado [[yii\base\Module::basePath|base path]] del módulo. Dentro de este directorio, hay subdirectorios tales como 'controllers', 'models', 'views', que contienen controladores, modelos, vistas y otro código, exactamente como una aplicación. El siguiente ejemplo muestra el contenido dentro de un módulo:
Un módulo está organizado de tal manera que contiene un directorio llamado [[yii\base\Module::basePath|base path]] del
módulo. Dentro de este directorio, hay subdirectorios tales como 'controllers', 'models', 'views', que contienen
controladores, modelos, vistas y otro código, exactamente como una aplicación. El siguiente ejemplo muestra el
contenido dentro de un módulo:
```
forum/
...
...
@@ -20,7 +28,11 @@ forum/
### Clases Módulo <a name="module-classes"></a>
Cada módulo debe tener una única clase módulo que extiende a [[yii\base\Module]]. La clase debe encontrarse directamente debajo del [[yii\base\Module::basePath|base path]] y debe ser [autocargable](concept-autoloading.md). Cuando se está accediendo a un módulo, se creará una única instancia de la clase módulo correspondiente. Como en las [instancias de aplicación](structure-applications.md), las instancias de módulo se utilizan para compartir datos y componentes de código dentro de los módulos.
Cada módulo debe tener una única clase módulo que extiende a [[yii\base\Module]]. La clase debe encontrarse
directamente debajo del [[yii\base\Module::basePath|base path]] y debe ser [autocargable](concept-autoloading.md).
Cuando se está accediendo a un módulo, se creará una única instancia de la clase módulo correspondiente. Como en las
[instancias de aplicación](structure-applications.md), las instancias de módulo se utilizan para compartir datos y
componentes de código dentro de los módulos.
El siguiente ejemplo muestra como podría ser una clase módulo.
...
...
@@ -39,7 +51,8 @@ class Module extends \yii\base\Module
}
```
Si el método 'init()' contiene mucho código de inicialización de las propiedades del módulo, también se puede guardar en términos de configuración y cargarlo con el siguiente código ‘init()’:
Si el método 'init()' contiene mucho código de inicialización de las propiedades del módulo, también se puede guardar
en términos de configuración y cargarlo con el siguiente código ‘init()’:
```php
publicfunctioninit()
...
...
@@ -50,7 +63,8 @@ public function init()
}
```
donde el archivo de configuración ‘config.php’ puede contener el siguiente contenido, similar al de [configuraciones de aplicación](structure-applications.md#application-configurations).
donde el archivo de configuración ‘config.php’ puede contener el siguiente contenido, similar al de
[configuraciones de aplicación](structure-applications.md#application-configurations).
```php
<?php
...
...
@@ -66,7 +80,11 @@ return [
### Controladores en Módulos <a name="controllers-in-modules"></a>
Cuando se crean controladores en un modelo, una convención es poner las clases controlador debajo del sub-espacio de nombres de ‘controllers’ del espacio de nombres de la clase módulo. Esto también significa que los archivos de la clase controlador deben ponerse en el directorio ‘controllers’ dentro del [[yii\base\Module::basePath|base path]] del módulo. Por ejemplo, para crear un controlador ‘post’ en el módulo ‘forum’ mostrado en la última subdivisión, se debe declarar la clase controlador de la siguiente manera:
Cuando se crean controladores en un modelo, una convención es poner las clases controlador debajo del sub-espacio de
nombres de ‘controllers’ del espacio de nombres de la clase módulo. Esto también significa que los archivos de la
clase controlador deben ponerse en el directorio ‘controllers’ dentro del [[yii\base\Module::basePath|base path]] del
módulo. Por ejemplo, para crear un controlador ‘post’ en el módulo ‘forum’ mostrado en la última subdivisión, se debe
declarar la clase controlador de la siguiente manera:
```php
namespaceapp\modules\forum\controllers;
...
...
@@ -79,17 +97,29 @@ class PostController extends Controller
}
```
Se puede personalizar el espacio de nombres de las clases controlador configurando la propiedad [[yii\base\Module::controllerNamespace]]. En el caso que alguno de los controladores esté fuera del espacio de nombres, se puede hacer accesible configurando la propiedad [[yii\base\Module::controllerMap]], similar a [como se hace en una aplicación](structure-applications.md#controller-map).
Se puede personalizar el espacio de nombres de las clases controlador configurando la propiedad
[[yii\base\Module::controllerNamespace]]. En el caso que alguno de los controladores esté fuera del espacio de
nombres, se puede hacer accesible configurando la propiedad [[yii\base\Module::controllerMap]], similar a
[como se hace en una aplicación](structure-applications.md#controller-map).
### Vistas en Módulos <a name="views-in-modules"></a>
Las vistas en un módulo deben alojarse en el directorio ‘views’ dentro del módulo del [[yii\base\Module::basePath|base path]]. Las vistas renderizadas por un controlador en el módulo, deben alojarse en el directorio ‘views/ControllerID’, donde el ‘ControllerID’ hace referencia al [ID del controlador](structure-controllers.md#routes). Por ejemplo, si la clase controlador es ‘PostController’, el directorio sería ‘views/post’ dentro del [[yii\base\Module::basePath|base path]] del módulo.
Las vistas en un módulo deben alojarse en el directorio ‘views’ dentro del módulo del
[[yii\base\Module::basePath|base path]]. Las vistas renderizadas por un controlador en el módulo, deben alojarse en el
directorio ‘views/ControllerID’, donde el ‘ControllerID’ hace referencia al
[ID del controlador](structure-controllers.md#routes). Por ejemplo, si la clase controlador es ‘PostController’, el
directorio sería ‘views/post’ dentro del [[yii\base\Module::basePath|base path]] del módulo.
Un modulo puede especificar un [layout](structure-views.md#layouts) que se aplica a las vistas renderizadas por los controladores del módulo. El layout debe alojarse en el directorio ‘views/layouts’ por defecto, y se puede configurar la propiedad [[yii\base\Module::layout]] para apuntar al nombre del layout. Si no se configura la propiedad ‘layout’, se usar el layout de la aplicación.
Un modulo puede especificar un [layout](structure-views.md#layouts) que se aplica a las vistas renderizadas por los
controladores del módulo. El layout debe alojarse en el directorio ‘views/layouts’ por defecto, y se puede configurar
la propiedad [[yii\base\Module::layout]] para apuntar al nombre del layout. Si no se configura la propiedad ‘layout’,
se usar el layout de la aplicación.
## Uso de los Módulos <a name="using-modules"></a>
Para usar un módulo en una aplicación, simplemente se tiene que configurar la aplicación añadiendo el módulo en la propiedad [[yii\base\Application::modules|modules]] de la aplicación. El siguiente ejemplo de la [configuración de la aplicación](structure-applications.md#application-configurations) usa el modelo ‘forum’:
Para usar un módulo en una aplicación, simplemente se tiene que configurar la aplicación añadiendo el módulo en la
propiedad [[yii\base\Application::modules|modules]] de la aplicación. El siguiente ejemplo de la
[configuración de la aplicación](structure-applications.md#application-configurations) usa el modelo ‘forum’:
```php
[
...
...
@@ -102,23 +132,38 @@ Para usar un módulo en una aplicación, simplemente se tiene que configurar la
]
```
La propiedad [[yii\base\Application::modules|modules]] contiene un array de configuraciones de módulo. Cada clave del array representa un *ID de módulo* que identifica de forma única el módulo de entre todos los módulos de la aplicación, y el correspondiente valor del array es la [configuración](concept-configurations.md) para crear el módulo.
La propiedad [[yii\base\Application::modules|modules]] contiene un array de configuraciones de módulo. Cada clave del
array representa un *ID de módulo* que identifica de forma única el módulo de entre todos los módulos de la
aplicación, y el correspondiente valor del array es la [configuración](concept-configurations.md) para crear el módulo.
### Rutas <a name="routes"></a>
De Igual manera que el acceso a los controladores en una aplicación, las [rutas](structure-controllers.md#routes) se utiliza para dirigirse a los controladores en un módulo. Una ruta para un controlador dentro de un módulo debe empezar con el ID del módulo seguido por el ID del controlador y el ID de la acción. Por ejemplo, si una aplicación usa un módulo llamado ‘forum’, la ruta ‘forum/post/index’ representaría la acción ‘index’ del controlador ‘post’ en el módulo. Si la ruta sólo contiene el ID del módulo, entonces la propiedad [[yii\base\Module::defaultRoute]] que por defecto es ‘default’, determinara que controlador/acción debe usarse. Esto significa que la ruta ‘forum’ representaría el controlador ‘default’ en el módulo ‘forum’.
De Igual manera que el acceso a los controladores en una aplicación, las [rutas](structure-controllers.md#routes) se
utiliza para dirigirse a los controladores en un módulo. Una ruta para un controlador dentro de un módulo debe empezar
con el ID del módulo seguido por el ID del controlador y el ID de la acción. Por ejemplo, si una aplicación usa un
módulo llamado ‘forum’, la ruta ‘forum/post/index’ representaría la acción ‘index’ del controlador ‘post’ en el
módulo. Si la ruta sólo contiene el ID del módulo, entonces la propiedad [[yii\base\Module::defaultRoute]] que por
defecto es ‘default’, determinara que controlador/acción debe usarse. Esto significa que la ruta ‘forum’ representaría
el controlador ‘default’ en el módulo ‘forum’.
### Acceder a los Módulos <a name="accessing-modules"></a>
Dentro de un módulo, se puede necesitar obtener la instancia de la [clase módulo](#module-classes) para poder acceder al ID del módulo, componentes del módulo, etc. Se puede hacer usando la siguiente declaración:
Dentro de un módulo, se puede necesitar obtener la instancia de la [clase módulo](#module-classes) para poder acceder
al ID del módulo, componentes del módulo, etc. Se puede hacer usando la siguiente declaración:
```php
$module=MyModuleClass::getInstance();
```
Dónde ‘MyModuleClass’ hace referencia al nombre de la clase módulo en la que estemos interesados. El método ‘getInstance()’ devolverá la instancia actualmente solicitada de la clase módulo. Si no se solicita el módulo, el método devolverá nulo. Hay que tener en cuenta que si se crea una nueva instancia del módulo, esta será diferente a la creada por Yii en respuesta a la solicitud.
Dónde ‘MyModuleClass’ hace referencia al nombre de la clase módulo en la que estemos interesados. El método
‘getInstance()’ devolverá la instancia actualmente solicitada de la clase módulo. Si no se solicita el módulo, el
método devolverá nulo. Hay que tener en cuenta que si se crea una nueva instancia del módulo, esta será diferente a la
creada por Yii en respuesta a la solicitud.
>Info: Cuando se desarrolla un módulo, no se debe dar por sentado que el módulo usará un ID fijo. Esto se debe a que un módulo puede asociarse a un ID arbitrario cuando se usa en una aplicación o dentro de otro módulo. Para obtener el ID del módulo, primero se debe usar el código del anterior ejemplo para obtener la instancia y luego el ID mediante ‘$modeule->id’.
> Información: Cuando se desarrolla un módulo, no se debe dar por sentado que el módulo usará un ID fijo. Esto se debe
a que un módulo puede asociarse a un ID arbitrario cuando se usa en una aplicación o dentro de otro módulo. Para
obtener el ID del módulo, primero se debe usar el código del anterior ejemplo para obtener la instancia y luego el
ID mediante ‘$modeule->id’.
También se puede acceder a la instancia de un módulo usando las siguientes declaraciones:
El primer ejemplo sólo es útil cuando conocemos el ID del módulo, mientras que el segundo es mejor usarlo cuando conocemos los controladores que se están solicitando.
El primer ejemplo sólo es útil cuando conocemos el ID del módulo, mientras que el segundo es mejor usarlo cuando
conocemos los controladores que se están solicitando.
Una vez obtenida la instancia del módulo, se puede acceder a parámetros o componentes registrados con el módulo. Por ejemplo:
Una vez obtenida la instancia del módulo, se puede acceder a parámetros o componentes registrados con el módulo. Por
Puede darse el caso en que necesitemos que un módulo se ejecute en cada petición. El módulo [[yii\debug\Module|debug]] es un ejemplo. Para hacerlo, tenemos que listar los IDs de los módulos en la propiedad [[yii\base\Application::bootstrap|bootstrap]] de la aplicación.
Puede darse el caso en que necesitemos que un módulo se ejecute en cada petición. El módulo [[yii\debug\Module|debug]]
es un ejemplo. Para hacerlo, tenemos que listar los IDs de los módulos en la propiedad
[[yii\base\Application::bootstrap|bootstrap]] de la aplicación.
Por ejemplo, la siguiente configuración de aplicación se asegura de que el módulo ‘debug’ siempre se cargue:
...
...
@@ -158,7 +207,9 @@ Por ejemplo, la siguiente configuración de aplicación se asegura de que el mó
## Módulos anidados <a name="nested-modules"></a>
Los módulos pueden ser anidados sin límite de niveles. Es decir, un módulo puede contener un módulo y éste a la vez contener otro módulo. Nombramos *padre* al primero mientras que al segundo lo nombramos *hijo*. Los módulos hijo se tienen que declarar en la propiedad [[yii\base\Module::modules|modules]] de sus módulos padre. Por ejemplo:
Los módulos pueden ser anidados sin límite de niveles. Es decir, un módulo puede contener un módulo y éste a la vez
contener otro módulo. Nombramos *padre* al primero mientras que al segundo lo nombramos *hijo*. Los módulos hijo se
tienen que declarar en la propiedad [[yii\base\Module::modules|modules]] de sus módulos padre. Por ejemplo:
```php
namespaceapp\modules\forum;
...
...
@@ -179,12 +230,20 @@ class Module extends \yii\base\Module
}
```
En un controlador dentro de un módulo anidado, la ruta debe incluir el ID de todos los módulos antecesores. Por ejemplo, la ruta ‘forum/admin/dashboard/index’ representa la acción ‘index’ del controlador ‘dashboard’ en el módulo ‘admin’ que es el módulo hijo del módulo ‘forum’.
En un controlador dentro de un módulo anidado, la ruta debe incluir el ID de todos los módulos antecesores. Por
ejemplo, la ruta ‘forum/admin/dashboard/index’ representa la acción ‘index’ del controlador ‘dashboard’ en el módulo
‘admin’ que es el módulo hijo del módulo ‘forum’.
>Info: El método [[yii\base\Module::getModule()|getModule()]] sólo devuelve el módulo hijo que pertenece directamente a su padre. La propiedad [[yii\base\Application::loadedModules]] contiene una lista de los módulos cargados, incluyendo los hijos directos y los anidados, indexados por sus nombres de clase.
> Información: El método [[yii\base\Module::getModule()|getModule()]] sólo devuelve el módulo hijo que pertenece
directamente a su padre. La propiedad [[yii\base\Application::loadedModules]] contiene una lista de los módulos
cargados, incluyendo los hijos directos y los anidados, indexados por sus nombres de clase.
Es mejor usar los módulos en grandes aplicaciones en las que sus funcionalidades puedan ser divididas en diferentes grupos, cada uno compuesto por funcionalidades directamente relacionadas. Cada grupo de funcionalidades se puede desarrollar como un módulo que puede ser desarrollado y mantenido por un programador o equipo específico.
Es mejor usar los módulos en grandes aplicaciones en las que sus funcionalidades puedan ser divididas en diferentes
grupos, cada uno compuesto por funcionalidades directamente relacionadas. Cada grupo de funcionalidades se puede
desarrollar como un módulo que puede ser desarrollado y mantenido por un programador o equipo específico.
Los módulos también son una buena manera de reutilizar código a nivel de grupo de funcionalidades. Algunas funcionalidades de uso común, tales como la gestión de usuarios o la gestión de comentarios, pueden ser desarrollados como módulos para que puedan ser fácilmente reutilizados en futuros proyectos.
Los módulos también son una buena manera de reutilizar código a nivel de grupo de funcionalidades. Algunas
funcionalidades de uso común, tales como la gestión de usuarios o la gestión de comentarios, pueden ser desarrollados
como módulos para que puedan ser fácilmente reutilizados en futuros proyectos.
Los Widgets son bloques de código reutilizables utilizados en las [vistas](structure-views.md) para crear elementos de interfaz de usuario complejos y configurables de forma orientada a objetos. Por ejemplo, widget DatePicker puede generar un DatePicker de lujo que permita a los usuarios seleccionar una fecha. Todo lo que se tiene que hacer es insertar el siguiente código en una vista.
Los Widgets son bloques de código reutilizables utilizados en las [vistas](structure-views.md) para crear elementos de
interfaz de usuario complejos y configurables de forma orientada a objetos. Por ejemplo, widget DatePicker puede
generar un DatePicker de lujo que permita a los usuarios seleccionar una fecha. Todo lo que se tiene que hacer es
insertar el siguiente código en una vista.
```php
<?php
...
...
@@ -10,11 +13,18 @@ use yii\jui\DatePicker;
<?=DatePicker::widget(['name'=>'date'])?>
```
Hay un buen número de widgets incluidos en Yii, tales como [[yii\widgets\ActiveForm|active form]], [[yii\widgets\Menu|menu]], [Widgets de jQuery UI](widget-jui.md), [widgets de Twitter Bootstrap](widget-bootstrap.md). En adelante, introduciremos las nociones básicas acerca de los widgets. Por favor, refiérase a la documentación de la API de clases si quiere aprender más acerca de el uso de un widget en particular.
Hay un buen número de widgets incluidos en Yii, tales como [[yii\widgets\ActiveForm|active form]],
[[yii\widgets\Menu|menu]], [Widgets de jQuery UI](widget-jui.md), [widgets de Twitter Bootstrap](widget-bootstrap.md).
En adelante, introduciremos las nociones básicas acerca de los widgets. Por favor, refiérase a la documentación de la
API de clases si quiere aprender más acerca de el uso de un widget en particular.
## Uso de los Widgets <a name="using-widgets"></a>
Los Widgets son usados principalmente en las [vistas](structure-views.md). Se puede llamar al método [[yii\base\Widget::widget()]] para usar un widget en una vista. El método obtiene un array de [configuración](concept-configurations.md) para inicializar el widget y retorna la representación resultante del widget. Por ejemplo, el siguiente código inserta un widget DatePicker que esta configurado para usar el idioma Ruso y mantener la entrada en atributo 'form_date' del '$model'.
Los Widgets son usados principalmente en las [vistas](structure-views.md). Se puede llamar al método
[[yii\base\Widget::widget()]] para usar un widget en una vista. El método obtiene un array de
[configuración](concept-configurations.md) para inicializar el widget y retorna la representación resultante del
widget. Por ejemplo, el siguiente código inserta un widget DatePicker que esta configurado para usar el idioma Ruso y
mantener la entrada en atributo 'form_date' del '$model'.
```php
<?php
...
...
@@ -30,7 +40,11 @@ use yii\jui\DatePicker;
])?>
```
Algunos widgets pueden coger un bloque de contenido que debería encontrarse entre la invocación de [[yii\base\Widget::begin()]] y [[yii\base\Widget::end()]]. Por ejemplo, el siguiente código usa el widget [[yii\widgets\ActiveForm]] para generar un formulario de inicio de sesión. El widget generara las etiquetas '<form>' de apertura y cierre donde sean llamados 'begin()' y 'end()', respectivamente. Cualquier cosa que este en medio será representado como tal.
Algunos widgets pueden coger un bloque de contenido que debería encontrarse entre la invocación de
[[yii\base\Widget::begin()]] y [[yii\base\Widget::end()]]. Por ejemplo, el siguiente código usa el widget
[[yii\widgets\ActiveForm]] para generar un formulario de inicio de sesión. El widget generará las etiquetas '<form>'
de apertura y cierre donde sean llamados 'begin()' y 'end()', respectivamente. Cualquier cosa que este en medio será
representado como tal.
```php
<?php
...
...
@@ -51,13 +65,20 @@ use yii\helpers\Html;
<?phpActiveForm::end();?>
```
Hay que tener en cuenta que a diferencia de [[yii\base\Widget::widget()]] que devuelve la representación resultante del widget, el método [[yii\base\Widget::begin()]] devuelve una instancia del widget que se puede usar para generar el contenido del widget.
Hay que tener en cuenta que a diferencia de [[yii\base\Widget::widget()]] que devuelve la representación resultante
del widget, el método [[yii\base\Widget::begin()]] devuelve una instancia del widget que se puede usar para generar el
contenido del widget.
## Creación Widgets <a name="creating-widgets"></a>
Para crear un widget, se debe extender a [[yii\base\Widget]] y sobrescribir los métodos [[yii\base\Widget::init()]] y/o [[yii\base\Widget::run()]]. Normalmente el método 'init()' debería contener el código que estandariza las propiedades del widget, mientras que el método 'run()' debería contener el código que genere la representación resultante del widget. La representación resultante puede ser "pintada" directamente o devuelta como una cadena por el método 'run()'.
Para crear un widget, se debe extender a [[yii\base\Widget]] y sobrescribir los métodos [[yii\base\Widget::init()]]
y/o [[yii\base\Widget::run()]]. Normalmente el método 'init()' debería contener el código que estandariza las
propiedades del widget, mientras que el método 'run()' debería contener el código que genere la representación
resultante del widget. La representación resultante puede ser "pintada" directamente o devuelta como una cadena por el
método 'run()'.
En el siguiente ejemplo, 'HelloWidget' codifica en HTML y muestra el contenido asignado a su propiedad 'message'. Si la propiedad no está establecida, mostrará "Hello World" por defecto.
En el siguiente ejemplo, 'HelloWidget' codifica en HTML y muestra el contenido asignado a su propiedad 'message'. Si
la propiedad no está establecida, mostrará "Hello World" por defecto.
```php
namespaceapp\components;
...
...
@@ -93,7 +114,8 @@ use app\components\HelloWidget;
Abajo se muestra una variante de 'HelloWidget' obtiene el contenido entre las llamadas 'begin()' y 'end()', lo codifica en HTML y posteriormente lo muestra.
Abajo se muestra una variante de 'HelloWidget' obtiene el contenido entre las llamadas 'begin()' y 'end()', lo
codifica en HTML y posteriormente lo muestra.
```php
namespaceapp\components;
...
...
@@ -117,9 +139,12 @@ class HelloWidget extends Widget
}
```
Como se puede observar, el búfer de salida PHP es iniciado en 'init()' por tanto cualquier salida entre las llamadas de 'init()' y 'run()' puede ser capturada, procesada y devuelta en 'run()'.
Como se puede observar, el búfer de salida PHP es iniciado en 'init()' por tanto cualquier salida entre las llamadas
de 'init()' y 'run()' puede ser capturada, procesada y devuelta en 'run()'.
>Info: Cuando se llama a [[yii\base\Widget::begin()]], se creará una nueva instancia del widget y el método 'init()' será llamado al final del constructor del widget. Cuando se llama [[yii\base\Widget::end()]], el método 'run()' será llamado el resultado que devuelva será escrito por 'end()'.
> Info: Cuando se llama a [[yii\base\Widget::begin()]], se creará una nueva instancia del widget y el método 'init()'
será llamado al final del constructor del widget. Cuando se llama [[yii\base\Widget::end()]], el método 'run()' será
llamado el resultado que devuelva será escrito por 'end()'.
El siguiente código muestra como usar esta nueva variante de 'HelloWidget':
...
...
@@ -134,7 +159,9 @@ use app\components\HelloWidget;
<?phpHelloWidget::end();?>
```
A veces, un widget puede necesitar representar una gran cantidad de contenido. Mientras que se puede incrustar el contenido dentro del método 'run()', ponerlo dentro de una [vista](structure-views.md) y llamar [[yii\base\Widget::render()]] para representarla, es un mejor enfoque. Por ejemplo:
A veces, un widget puede necesitar representar una gran cantidad de contenido. Mientras que se puede incrustar el
contenido dentro del método 'run()', ponerlo dentro de una [vista](structure-views.md) y llamar
[[yii\base\Widget::render()]] para representarla, es un mejor enfoque. Por ejemplo:
```php
publicfunctionrun()
...
...
@@ -143,14 +170,24 @@ public function run()
}
```
Por defecto, las vistas para un widget deberían encontrarse en ficheros dentro del directorio 'WidgetPath/views', donde 'WidgetPath' representa el directorio que contiene el fichero de clase del widget. Por lo tanto, el anterior ejemplo representará el fichero de la vista `@app/components/views/hello.php`, asumiendo que la clase del widget se encuentre en `@app/components`. Se puede sobrescribir el método [[yii\base\Widget::getViewPath()]] para personalizar el directorio que contenga los ficheros de la vista del widget.
Por defecto, las vistas para un widget deberían encontrarse en ficheros dentro del directorio 'WidgetPath/views',
donde 'WidgetPath' representa el directorio que contiene el fichero de clase del widget. Por lo tanto, el anterior
ejemplo representará el fichero de la vista `@app/components/views/hello.php`, asumiendo que la clase del widget se
encuentre en `@app/components`. Se puede sobrescribir el método [[yii\base\Widget::getViewPath()]] para personalizar
el directorio que contenga los ficheros de la vista del widget.
Los widgets son una manera orientada a objetos de reutilizar código de las vistas.
Cuando se crean widgets, se debería continuar manteniendo el patrón MVC. En general, se debería mantener la lógica en las clases del widget y mantener la presentación en las [vistas](structure-views.md).
Cuando se crean widgets, se debería continuar manteniendo el patrón MVC. En general, se debería mantener la lógica en
las clases del widget y mantener la presentación en las [vistas](structure-views.md).
Los widgets deberían ser diseñados para ser autónomos. Es decir, cuando se usa un widget, se debería poder poner en una vista sin hacer nada más. Esto puede resultar complicado si un widget requiere recursos externos, tales como CSS, JavaScript, imágenes, etc. Afortunadamente Yii proporciona soporte para [paquetes de recursos](structure-asset-bundles.md) que pueden ser utilizados para resolver el problema.
Los widgets deberían ser diseñados para ser autónomos. Es decir, cuando se usa un widget, se debería poder poner en
una vista sin hacer nada más. Esto puede resultar complicado si un widget requiere recursos externos, tales como CSS,
JavaScript, imágenes, etc. Afortunadamente Yii proporciona soporte para
[asset bundles](structure-asset-bundles.md) que pueden ser utilizados para resolver el problema.
Cuando un widget sólo contiene código de vista, este es muy similar a una [vista](structure-views.md). De hecho, en este caso, su única diferencia es que un widget es una clase redistribuible, mientras que una vista es sólo un script PHP llano que prefiere mantenerse dentro de su aplicación.
Cuando un widget sólo contiene código de vista, este es muy similar a una [vista](structure-views.md). De hecho, en
este caso, su única diferencia es que un widget es una clase redistribuible, mientras que una vista es sólo un script
PHP llano que prefiere mantenerse dentro de su aplicación.
Yii incluye soporta las marcas y componentes del framework [Bootstrap 3](http://getbootstrap.com/)(también conocido como "Twitter Bootstrap"). Bootstrap es un excelente, adaptable framework que puede aumentar la velocidad de desarrollo de los procesos del lado del cliente.
El núcleo de Bootstrap está represntado en dos partes:
El núcleo de Bootstrap está representado en dos partes:
- Elementos básicos de CSS, como son un sistema de diseño en formato cuadrícula , tipografía, clases de ayuda (helpers), y utilidades adapatables(responsive).
- Elementos básicos de CSS, como son un sistema de diseño en formato cuadrícula , tipografía, clases de ayuda (helpers), y utilidades adaptables(responsive).
- Componentes preparados para su uso, tales como formularios, menús, paginación, cajas modales, pestañas, etc
Elementos básicos
------
-----------------
Yii no hace uso de elementos básicos de boostrap en el código PHP ya que HTML es muy simple por sí mismo, en este caso. Puedes encontrar detalle del uso de estos elementos básicos en [sitio web de la documentación de bootstrap](http://getbootstrap.com/css/). Aún así Yii provee una manera conveniente de incluir los elementos básicos de los recursos de bootstrap en tus páginas con una simple línea añadida a `AppAsset.php` localizada en tu directorio `@app/assets` :
...
...
@@ -26,7 +26,7 @@ public $depends = [
Usar bootstrap a través de el gestor de recursos Yii te permite minimizar estos recursos y combinar con tus propios recursos cuando sea necesario..
Widgets de Yii
-----------
--------------
Componentes más complejos de bootstrap components están envueltos dentro de widgets de Yii para permitir una sintaxis más robusta e integrar con las posibilidades y características del framework. Todos los widgets pertenecen al espacio de nombres `\yii\bootstrap` :
...
...
@@ -46,9 +46,9 @@ Componentes más complejos de bootstrap components están envueltos dentro de wi
Usando los ficheros .less de Bootstrap directamente
Si quieres incluir el [Css Bootstrap directamente en tus ficheros less](http://getbootstrap.com/getting-started/#customizing) puedes necesitar desactivar la carga los ficheros css originales de bootstrap.
Si quieres incluir el [CSS Bootstrap directamente en tus ficheros less](http://getbootstrap.com/getting-started/#customizing) puedes necesitar desactivar la carga los ficheros css originales de bootstrap.
Esto lo puedes hacer poniendo la propiedad css de [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] vacía.
Para esto necesitas configurar el `assetManager`[componente de la aplicación](structure-application-components.md) como sigue: