Commit d8ae74ee by Antonio Ramirez

Merge remote-tracking branch 'upstream/master' into upstream

* upstream/master: gridview and listview use widget ID in base tag typo fix [skip ci] Update CHANGELOG.md made elasticsearch error messages more readable Spanish structure-views [skip ci] Fix filename Update README.md https://github.com/yiisoft/yii2/pull/4091#discussion_r14296860 Fix possibility of non-removed symlinked directory. Fixed typo. [skip ci] changed default for rotateByCopy of FileTarget
parents 392f2910 085f2c01
......@@ -20,10 +20,10 @@ which is the latest stable release of Yii.
[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2/v/stable.png)](https://packagist.org/packages/yiisoft/yii2)
[![Total Downloads](https://poser.pugx.org/yiisoft/yii2/downloads.png)](https://packagist.org/packages/yiisoft/yii2)
[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master)
[![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2)
[![HHVM Status](http://hhvm.h4cc.de/badge/yiisoft/yii2-dev.png)](http://hhvm.h4cc.de/package/yiisoft/yii2-dev)
[![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/coverage.png?s=31d80f1036099e9d6a3e4d7738f6b000b3c3d10e)](https://scrutinizer-ci.com/g/yiisoft/yii2/)
[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/quality-score.png?s=b1074a1ff6d0b214d54fa5ab7abbb90fc092471d)](https://scrutinizer-ci.com/g/yiisoft/yii2/)
[![Code Climate](https://codeclimate.com/github/yiisoft/yii2.png)](https://codeclimate.com/github/yiisoft/yii2)
......
......@@ -24,7 +24,7 @@ Einstieg
* [Arbeiten mit Formularen](start-forms.md)
* [Arbeiten mit Datenbanken](start-databases.md)
* [Code generieren mit Gii](start-gii.md)
* [Ausblick](start-looking-head.md)
* [Ausblick](start-looking-ahead.md)
Application Struktur
......
......@@ -24,7 +24,7 @@ Primeros pasos
* [Trabajar con formularios](start-forms.md)
* [Trabajar con bases de datos](start-databases.md)
* [Generar códigos con Gii](start-gii.md)
* [Adentrarse en Yii](start-looking-head.md)
* [Adentrarse en Yii](start-looking-ahead.md)
Estructura de una aplicación
......
Vistas
======
Las Vistas (views) son una parte de la arquitectura [MVC](http://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador).
Estas son el código responsable de presentar los datos al usuario final. En una aplicación Web, las vistas son usualmente creadas
en términos de *templates* que son archivos PHP que contienen principalmente HTML y PHP.
Son manejadas por el componente de la aplicación [[yii\web\View|view]], el cual provee métodos comúnmente utilizados
para facilitar la composición y el renderizado de las mismas. Por simplicidad, a menudo las llamamos *templates* o *archivos de templates*.
## Creando Vistas <a name="creating-views"></a>
Como fue mencionado, una vista es simplemente un archivo PHP que mezcla código PHP y HTML. La siguiente es una vista
que muestra un formulario de login. Como puedes ver, el código PHP utilizado es para generar contenido dinámico, como el
título de la página y el formulario mismo, mientras que el código HTML organiza estos elementos en una página HTML mostrable.
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $form yii\widgets\ActiveForm */
/* @var $model app\models\LoginForm */
$this->title = 'Login';
?>
<h1><?= Html::encode($this->title) ?></h1>
<p>Por favor completa los siguientes campos para loguearte:</p>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= Html::submitButton('Login') ?>
<?php ActiveForm::end(); ?>
```
Dentro de una vista, puedes acceder a la variable `$this` referida al [[yii\web\View|componente view]] que maneja
y renderiza la vista actual.
Además de `$this`, puede haber otras variables predefinidas en una vista, como `$form` y `$model` en el ejemplo
anterior. Estas variables representan los datos que son *inyectados* a la vista desde el [controlador](structure-controllers.md)
o algún otro objeto que dispara la [renderización de la vista](#rendering-views).
> Tip: La lista de variables predefinidas están listadas en un bloque de comentario al principio de la vista así pueden ser
reconocidas por las IDEs. Esto es también una buena manera de documentar tus propias vistas.
### Seguridad <a name="security"></a>
Al crear vistas que generan páginas HTML, es importante que codifiques (encode) y/o filtres los datos provenientes
de los usuarios antes de mostrarlos. De otro modo, tu aplicación puede estar expuesta a
ataques tipo [cross-site scripting](http://es.wikipedia.org/wiki/Cross-site_scripting).
Para mostrar un texto plano, codifícalos previamente utilizando [[yii\helpers\Html::encode()]]. Por ejemplo, el siguiente código
aplica una codificación del nombre de usuario antes de mostrarlo:
```php
<?php
use yii\helpers\Html;
?>
<div class="username">
<?= Html::encode($user->name) ?>
</div>
```
Para mostrar contenido HTML, utiliza [[yii\helpers\HtmlPurifier]] para filtrarlo antes. Por ejemplo, el siguiente
código filtra el contenido del post antes de mostrarlo en pantalla:
```php
<?php
use yii\helpers\HtmlPurifier;
?>
<div class="post">
<?= HtmlPurifier::process($post->text) ?>
</div>
```
> Tip: Aunque HTMLPurifier hace un excelente trabajo al hacer la salida más segura, no es rápido. Deberías considerar
utilizar [caching](caching-overview.md) al resultado de aplicar el filtro si tu aplicación requiere un gran desempeño (performance).
### Organizando Vistas <a name="organizing-views"></a>
Así como en [controladores](structure-controllers.md) y [modelos](structure-models.md), existen convenciones para organizar las vistas.
* Para vistas renderizadas por controladores, deberían colocarse en un directorio tipo `@app/views/ControllerID` por defecto,
donde `ControllerID` se refiere al [ID del controlador](structure-controllers.md#routes). Por ejemplo, si
la clase del controlador es `PostController`, el directorio sería `@app/views/post`; Si fuera `PostCommentController`,
el directorio sería `@app/views/post-comment`. En caso de que el controlador pertenezca a un módulo, el directorio
sería `views/ControllerID` bajo el [[yii\base\Module::basePath|directorio del módulo]].
* Para vistas renderizadas por un [widget](structure-widgets.md), deberían ser puestas en un directorio tipo `WidgetPath/views` por defecto,
donde `WidgetPath` se refiere al directorio que contiene a la clase del widget.
* Para vistas renderizadas por otros objetos, se recomienda seguir una convención similar a la utilizada con los widgets.
Puedes personalizar estos directorios por defecto sobrescribiendo el método [[yii\base\ViewContextInterface::getViewPath()]]
en el controlador o widget necesario.
## Renderizando Vistas <a name="rendering-views"></a>
Puedes renderizar vistas desde [controllers](structure-controllers.md), [widgets](structure-widgets.md), o cualquier
otro lugar llamando a los métodos de renderización de vistas. Estos métodos comparten una firma similar, como se muestra a continuación:
```
/**
* @param string $view nombre de la vista o ruta al archivo, dependiendo del método de renderización utilizado
* @param array $params los datos pasados a la vista
* @return string el resultado de la renderización
*/
methodName($view, $params = [])
```
### Renderizando en Controladores <a name="rendering-in-controllers"></a>
Dentro de los [controladores](structure-controllers.md), puedes llamar al siguiente método del controlador para renderizar una vista:
* [[yii\base\Controller::render()|render()]]: renderiza la [vista nombrada](#named-views) y aplica un [layout](#layouts)
al resultado de la renderización.
* [[yii\base\Controller::renderPartial()|renderPartial()]]: renderiza la [vista nombrada](#named-views) sin ningún layout aplicado.
* [[yii\web\Controller::renderAjax()|renderAjax()]]: renderiza la [vista nombrada](#named-views) sin layout,
e inyecta todos los scripts y archivos JS/CSS registrados. Esto sucede usualmente en respuestas a llamadas a AJAX `requests`.
* [[yii\base\Controller::renderFile()|renderFile()]]: renderiza la vista especificada en términos de la ruta al archivo o
[alias](concept-aliases.md).
Por ejemplo:
```php
namespace app\controllers;
use Yii;
use app\models\Post;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
// renderiza una vista llamada "view" y le aplica el layout
return $this->render('view', [
'model' => $model,
]);
}
}
```
### Renderizando en Widgets <a name="rendering-in-widgets"></a>
Dentro de [widgets](structure-widgets.md), puedes llamar a cualquier de los siguientes métodos de widget para renderizar una vista.
* [[yii\base\Widget::render()|render()]]: renderiza la [vista nombrada](#named-views).
* [[yii\base\Widget::renderFile()|renderFile()]]: renderiza la vista especificada en términos de ruta al archivo o
[alias](concept-aliases.md).
Por ejemplo:
```php
namespace app\components;
use yii\base\Widget;
use yii\helpers\Html;
class ListWidget extends Widget
{
public $items = [];
public function run()
{
// renderiza una vista llamada "list"
return $this->render('list', [
'items' => $this->items,
]);
}
}
```
### Renderizando en Vistas <a name="rendering-in-views"></a>
Puedes renderizar una vista dentro de otra vista llamando a algunos de los siguientes métodos provistos por el [[yii\base\View|componente view]]:
* [[yii\base\View::render()|render()]]: renderiza la [vista nombrada](#named-views).
* [[yii\web\View::renderAjax()|renderAjax()]]: renderiza la [vista nombrada](#named-views) e inyecta todos los
archivos y scripts JS/CSS. Esto sucede usualmente en respuestas a llamadas a AJAX `requests`.
* [[yii\base\View::renderFile()|renderFile()]]: renderiza la vista especificada en términos de ruta al archivo o
[alias](concept-aliases.md).
Por ejemplo, el siguiente código en una vista renderiza el template `_overview.php` encontrado en el mismo directorio
de la vista renderizada actualmente. Recuerda que la variable `$this` en una vista se refiere al componente [[yii\base\View|view]]:
```php
<?= $this->render('_overview') ?>
```
### Renderizando en Otros Lugares <a name="rendering-in-other-places"></a>
En cualquier lugar, puedes tener acceso al componente [[yii\base\View|view]] utilizando la expresión
`Yii::$app->view` y entonces llamar a los métodos previamente mencionados para renderizar una vista. Por ejemplo:
```php
// muestra el template "@app/views/site/license.php"
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
```
### Vistas Nombradas <a name="named-views"></a>
Cuando renderizas una vista, puedes especificar el template utilizando tanto el nombre de la vista o la ruta/alias al archivo. En la mayoría de los casos,
utilizarías la primera porque es más concisa y flexible. *Vistas nombradas* son vistas especificadas mediante un nombre en vez de una ruta al archivo o alias.
Un nombre de vista es resuelto a su correspondiente ruta de archivo siguiendo las siguientes reglas:
* Un nombre de vista puede omitir la extensión del archivo. En estos casos se utilizará `.php` como extensión del archivo. Por ejemplo,
el nombre de vista `about` corresponde al archivo `about.php`.
* Si el nombre de la vista comienza con doble barra (`//`), la ruta al archivo correspondiente será `@app/views/ViewName`.
Esto quiere decir que la vista es buscada bajo el [[yii\base\Application::viewPath|view path de la aplicación]].
Por ejemplo, `//site/about` será resuelto como `@app/views/site/about.php`.
* Si el nombre de la vista comienza con una barra simple `/`, la ruta al archivo de la vista utilizará como prefijo el nombre de la vista
con el [[yii\base\Module::viewPath|view path]] del [módulo](structure-modules.md) utilizado actualmente.
Si no hubiera módulo activo se utilizará `@app/views/ViewName`. Por ejemplo, `/user/create` será resuelto a
`@app/modules/user/views/user/create.php` si el módulo activo es `user`. Si no hubiera módulo activo,
la ruta al archivo será `@app/views/user/create.php`.
* Si la vista es renderizada con un [[yii\base\View::context|context]] y dicho contexto implementa [[yii\base\ViewContextInterface]],
la ruta al archivo se forma utilizando como prefijo el [[yii\base\ViewContextInterface::getViewPath()|view path]]
del contexto de la vista. Esto principalmente aplica a vistas renderizadas en controladores y widgets. Por ejemplo,
`site/about` será resuelto a `@app/views/site/about.php` si el contexto es el controlador `SiteController`.
* Si la vista es renderizada dentro de otra vista, el directorio que contiene la otra vista será prefijado
al nuevo nombre de la vista para formar la ruta a la vista. Por ejemplo, `item` sera resuelto a `@app/views/post/item`
si está siendo renderizado desde la vista `@app/views/post/index.php`.
De acuerdo a las reglas mencionadas, al llamar a `$this->render('view')` en el controlador `app\controllers\PostController`
se renderizará el template `@app/views/post/view.php`, mientras que llamando a `$this->render('_overview')` en la vista
renderizará el template `@app/views/post/_overview.php`.
### Accediendo a Datos en la Vista <a name="accessing-data-in-views"></a>
Hay dos modos posibles de acceder a los datos en la vista: push (inyectar) y pull (traer).
Al pasar los datos como segundo parámetro en algún método de renderización, estás utilizando el modo push.
Los datos deberían ser representados como un array de pares clave-valor. Cuando la vista está siendo renderizada, la función PHP
`extract()` será llamada sobre este array así se extraen las variables que contiene a la vista actual .
Por ejemplo, el siguiente código de renderización en un controlador inyectará dos variables a la vista `report`:
`$foo = 1` and `$bar = 2`.
```php
echo $this->render('report', [
'foo' => 1,
'bar' => 2,
]);
```
El modo pull obtiene los datos del [[yii\base\View|componente view]] u otros objetos accesibles
en las vistas (ej. `Yii::$app`). Utilizando el código anterior como ejemplo, dentro de una vista puedes acceder al objeto del controlador
a través de la expresión `$this->context`. Como resultado, te es posible acceder a cualquier propiedad o método
del controlador en la vista `report`, tal como el ID del controlador como se muestra a continuación:
```php
El ID del controlador es: <?= $this->context->id ?>
?>
```
Para acceder a datos en la vista, normalmente se prefiere el modo push, ya que hace a la vista menos dependiente
de los objetos del contexto. La contra es que tienes que construir el array manualmente cada vez, lo que podría
volverse tedioso y propenso al error si la misma vista es compartida y renderizada desde diferentes lugares.
### Compartiendo Datos Entre las Vistas <a name="sharing-data-among-views"></a>
El [[yii\base\View|componente view]] provee la propiedad [[yii\base\View::params|params]] para que puedas compartir
datos entre diferentes vistas.
Por ejemplo, en una vista `about`, podrías tener el siguiente código que especifica el segmento actual
del breadcrumbs (migas de pan).
```php
$this->params['breadcrumbs'][] = 'Acerca de Nosotros';
```
Entonces, en el archivo del [layout](#layouts), que es también una vista, puedes mostrar el breadcrumbs utilizando los datos
pasados a través de [[yii\base\View::params|params]]:
```php
<?= yii\widgets\Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
```
## Layouts <a name="layouts"></a>
Los layouts son un tipo especial de vista que representan partes comunes de otras múltiples vistas. Por ejemplo, las páginas
de la mayoría de las aplicaciones Web comparten el mismo encabezado y pie de página. Aunque puedes repetirlos en todas y cada una
de las vistas, una mejor forma es hacerlo sólo en el layout e incrustar el resultado de la renderización de la vista en
un lugar apropiado del mismo.
### Creando Layouts <a name="creating-layouts"></a>
Dado que los layouts son también vistas, pueden ser creados de manera similar a las vistas comunes. Por defecto, los layouts
son guardados en el directorio `@app/views/layouts`. Para layouts utilizados dentro de un [módulo](structure-modules.md),
deberían ser guardados en el directorio `views/layouts` bajo el [[yii\base\Module::basePath|directorio del módulo]].
Puedes personalizar el directorio de layouts por defecto configurando la propiedad [[yii\base\Module::layoutPath]] de
la aplicación o módulos.
El siguiente ejemplo muestra cómo debe verse un layout. Ten en cuenta que por motivos ilustrativos, hemos simplificado bastante
el código del layout. En la práctica, probablemente le agregues más contenido, como tags en el `head`, un menú principal, etc.
```php
<?php
use yii\helpers\Html;
/* @var $this yii\web\View */
/* @var $content string */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<?= Html::csrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<header>Mi Compañía</header>
<?= $content ?>
<footer>&copy; 2014 - Mi Compañía</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
```
Como puedes ver, el layout genera los tags HTML comunes a todas las páginas. Dentro de la sección `<body>`,
el layout imprime la variable `$content`, que representa el resultado de la renderización del contenido de cada vista y es incrustado
dentro del layout cuando se llama al método [[yii\base\Controller::render()]].
La mayoría de layouts deberían llamar a los siguientes métodos (como fue mostrado recién). Estos métodos principalmente disparan eventos
acerca del proceso de renderizado así los scripts y tags registrados en otros lugares pueden ser propiamente inyectados en
los lugares donde los métodos son llamados.
- [[yii\base\View::beginPage()|beginPage()]]: Este método debería ser llamado bien al principio del layout.
Esto dispara el evento [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]], el cual indica el comienzo de la página.
- [[yii\base\View::endPage()|endPage()]]: Este método debería ser llamado al final del layout.
Esto dispara el evento [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]], indicando el final de la página.
- [[yii\web\View::head()|head()]]: Este método debería llamarse dentro de la sección `<head>` de una página HTML.
Esto genera un espacio vacío que será reemplazado con el código del head HTML registrado (ej. link tags, meta tags)
cuando una página finaliza el renderizado.
- [[yii\base\View::beginBody()|beginBody()]]: Este método debería llamarse al principio de la sección `<body>`.
Esto dispara el evento [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] y genera un espacio vacío que será
reemplazado con el código HTML registrado (ej. JavaScript) que apunta al principio del body.
- [[yii\base\View::endBody()|endBody()]]: Este método debería llamarse al final de la sección `<body>`.
Esto dispara el evento [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]], que genera un espacio vacío a ser reemplazado
por el código HTML registrado (ej. JavaScript) que apunta al final del body.
### Accediendo a Datos en Layouts <a name="accessing-data-in-layouts"></a>
Dentro de un layout, tienes acceso a dos variables predefinidas: `$this` y `$content`. La primera se refiere
al componente [[yii\base\View|view]], como en cualquier vista, mientras que la última contiene el resultado de la renderización del contenido
de la vista que está siendo renderizada all llamar al método [[yii\base\Controller::render()|render()]] en los controladores.
Si quieres acceder a otros datos en los layouts, debes utilizar el modo pull que fue descrito en la sub-sección
[Accediendo a Datos en la Vista](#accessing-data-in-views). Si quieres pasar datos desde al contenido de la vista
a un layout, puedes utilizar el método descrito en la sub-sección [Compartiendo Datos Entre las Vistas](#sharing-data-among-views).
### Utilizando Layouts <a name="using-layouts"></a>
Como se describe en la sub-sección [Renderizando en Controllers](#rendering-in-controllers), cuando renderizas una vista
llamando al método [[yii\base\Controller::render()|render()]] en un controlador, al resultado de dicha renderización
le será aplicado un layout. Por defecto, el layout `@app/views/layouts/main.php` será el utilizado.
Puedes utilizar un layout diferente configurando la propiedad [[yii\base\Application::layout]] o [[yii\base\Controller::layout]].
El primero se refiere al layout utilizado por todos los controladores, mientras que el último sobrescribe el layout en controladores individuales.
Por ejemplo, el siguiente código hace que el controlador `post` utilice `@app/views/layouts/post.php` como layout
al renderizar sus vistas. Otros controladores, asumiendo que su propiedad `layout` no fue modificada, utilizarán
`@app/views/layouts/main.php` como layout.
```php
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public $layout = 'post';
// ...
}
```
Para controladores que pertencen a un módulo, puedes también configurar la propiedad [[yii\base\Module::layout|layout]] y así
utilizar un layout en particular para esos controladores.
Dado que la propiedad `layout` puede ser configurada en diferentes niveles (controladores, módulos, aplicación),
detrás de escena Yii realiza dos pasos para determinar cuál es el archivo de layout siendo utilizado para un controlador en particular.
En el primer paso, determina el valor del layout y el módulo de contexto:
- Si la propiedad [[yii\base\Controller::layout]] no es `null`, la utiliza como valor del layout y
el [[yii\base\Controller::module|módulo]] del controlador como el módulo de contexto.
- Si [[yii\base\Controller::layout|layout]] es `null`, busca a través de todos los módulos ancestros del controlador y
encuentra el primer módulo cuya propiedad [[yii\base\Module::layout|layout]] no es `null`. Utiliza ese módulo y
su valor de [[yii\base\Module::layout|layout]] como módulo de contexto y como layout seleccionado.
Si tal módulo no puede ser encontrado, significa que no se aplicará ningún layout.
En el segundo paso, se determina el archivo de layout actual de acuerdo al valor de layout y el módulo de contexto
determinado en el primer paso. El valor de layout puede ser:
- un alias de ruta (ej. `@app/views/layouts/main`).
- una ruta absoluta (ej. `/main`): el valor del layout comienza con una barra. El archivo de layout actual será
buscado bajo el [[yii\base\Application::layoutPath|layout path]] de la aplicación, que es por defecto
`@app/views/layouts`.
- una ruta relativa (ej. `main`): El archivo de layout actual será buscado bajo el
[[yii\base\Module::layoutPath|layout path]] del módulo de contexto, que es por defecto el directorio `views/layouts`
bajo el [[yii\base\Module::basePath|directorio del módulo]].
- el valor booleano `false`: no se aplicará ningún layout.
Si el valor de layout no contiene una extensión de tipo de archivo, utilizará por defecto `.php`.
### Layouts Anidados <a name="nested-layouts"></a>
A veces podrías querer anidar un layout dentro de otro. Por ejemplo, en diferentes secciones de un sitio Web, podrías
querer utilizar layouts diferentes, mientras que todos esos layouts comparten el mismo layout básico que genera la
estructura general de la página en HTML5. Esto es posible llamando a los métodos [[yii\base\View::beginContent()|beginContent()]] y
[[yii\base\View::endContent()|endContent()]] en los layouts hijos como se muestra a continuación:
```php
<?php $this->beginContent('@app/views/layouts/base.php'); ?>
...contenido del layout hijo aquí...
<?php $this->endContent(); ?>
```
Como se acaba de mostrar, el contenido del layout hijo debe ser encerrado dentro de [[yii\base\View::beginContent()|beginContent()]] y
[[yii\base\View::endContent()|endContent()]]. El parámetro pasado a [[yii\base\View::beginContent()|beginContent()]]
especifica cuál es el módulo padre. Este puede ser tanto un archivo layout como un alias.
Utilizando la forma recién mencionada, puedes anidar layouts en más de un nivel.
## Utilizando Componentes de Vista <a name="using-view-components"></a>
Los [[yii\base\View|componentes de vista]] proveen características relacionadas a las vistas. Aunque puedes obtener componentes de vista
creando instancias individuales de [[yii\base\View]] o sus clases hijas, en la mayoría de los casos utilizarías el
componente `view` del a aplicación. Puedes configurar este componente en la [configuración de la aplicación](structure-applications.md#application-configurations)
como a continuación:
```php
[
// ...
'components' => [
'view' => [
'class' => 'app\components\View',
],
// ...
],
]
```
Los componentes de vista proveen las siguientes características útiles, cada una descrita en mayor detalle en su propia sección:
* [temas](output-theming.md): te permite desarrollar y cambiar el tema (theme) de tu sitio Web.
* [caché de fragmentos](caching-fragment.md): te permite guardar en cache un fragmento de una página Web.
* [manejo de scripts del cliente](output-client-scripts.md): soporte para registro y renderización de CSS y JavaScript.
* [manejo de asset bundle](structure-assets.md): soporte de registro y renderización de [asset bundles](structure-assets.md).
* [motores de template alternativos](tutorial-template-engines.md): te permite utilizar otros motores de templates, como
[Twig](http://twig.sensiolabs.org/) o [Smarty](http://www.smarty.net/).
Puedes también utilizar frecuentemente el siguiente menor pero útil grupo de características al desarrollar páginas Web.
### Definiendo Títulos de Página <a name="setting-page-titles"></a>
Toda página Web debería tener un título. Normalmente el tag de título es generado en [layout](#layouts). De todos modos, en la práctica
el título es determinado en el contenido de las vistas más que en layouts. Para resolver este problema, [[yii\web\View]] provee
la propiedad [[yii\web\View::title|title]] para que puedas pasar información del título desde el contenido de la vista a los layouts.
Para utilizar esta característica, en cada contenido de la vista, puedes definir el título de la siguiente manera:
```php
<?php
$this->title = 'Mi título de página';
?>
```
Entonces en el layout, asegúrate de tener el siguiente código en la sección `<head>` de la página:
```php
<title><?= Html::encode($this->title) ?></title>
```
### Registrando Meta Tags <a name="registering-meta-tags"></a>
Las páginas Web usualmente necesitan generar varios meta tags necesarios por diferentes grupos (ej. Facebook, motores de búsqueda, etc).
Cómo los títulos de página, los meta tags aparecen en la sección `<head>` y son usualmente generado en los layouts.
Si quieres especificar cuáles meta tags generar en las vistas, puedes llamar a [[yii\web\View::registerMetaTag()]]
dentro de una de ellas, como se muestra a continuación:
```php
<?php
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);
?>
```
El código anterior registrará el meta tag "keywords" a través del componente view. El meta tag registrado no
se renderiza hasta que finaliza el renderizado del layout. Para entonces, el siguiente código HTML será insertado
en el lugar donde llamas a [[yii\web\View::head()]] en el layout, generando el siguiente HTML:
```php
<meta name="keywords" content="yii, framework, php">
```
Ten en cuenta que si llamas a [[yii\web\View::registerMetaTag()]] varias veces, esto registrará varios meta tags,
sin tener en cuenta si los meta tags son los mismo o no.
Para asegurarte de que sólo haya una instancia de cierto tipo de meta tag, puedes especificar una clave al llamar al método.
Por ejemplo, el siguiente código registra dos meta tags "description", aunque sólo el segundo será renderizado.
```html
$this->registerMetaTag(['name' => 'description', 'content' => 'Este es mi sitio Web cool hecho con Yii!'], 'description');
$this->registerMetaTag(['name' => 'description', 'content' => 'Este sitio Web es sobre mapaches graciosos.'], 'description');
```
### Registrando Link Tags <a name="registering-link-tags"></a>
Tal como los [meta tags](#adding-meta-tags), los link tags son útiles en muchos casos, como personalizar el ícono (favicon) del sitio, apuntar a
una fuente de RSS o delegar OpenID a otro servidor. Puedes trabajar con link tags, al igual que con meta tags,
utilizando [[yii\web\View::registerLinkTag()]]. Por ejemplo, en el contenido de una vista, puedes registrar un link tag como se muestra a continuación:
```php
$this->registerLinkTag([
'title' => 'Noticias en Vivo de Yii',
'rel' => 'alternate',
'type' => 'application/rss+xml',
'href' => 'http://www.yiiframework.com/rss.xml/',
]);
```
El resultado del código es el siguiente:
```html
<link title="Noticias en Vivo de Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
```
Al igual que con [[yii\web\View::registerMetaTag()|registerMetaTags()]], puedes especificar una clave al llamar a
[[yii\web\View::registerLinkTag()|registerLinkTag()]] para evitar registrar link tags repetidos.
## Eventos de Vistas <a name="view-events"></a>
Los [[yii\base\View|componentes de vistas]] disparan varios eventos durante el proceso de renderizado de la vista. Puedes responder
a estos eventos para inyectar contenido a la vista o procesar el resultado de la renderización antes de que sea enviada al usuario final.
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: disparado al principio del renderizado de un archivo
en un controlador. Los manejadores de este evento pueden definir [[yii\base\ViewEvent::isValid]] como `false` para cancelar el proceso de renderizado.
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: disparado por la llamada a [[yii\base\View::beginPage()]] en layouts.
Los manejadores de este evento pueden obtener el resultado de la renderización a través de [[yii\base\ViewEvent::output]] y entonces modificar
esta propiedad para así cambiar el mismo.
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: disparado por la llamada a [[yii\base\View::beginPage()]] en layouts.
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: disparado por la llamada a [[yii\base\View::endPage()]] en layouts.
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: disparado por la llamada a [[yii\web\View::beginBody()]] en layouts.
- [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]]: disparado por la llamada a [[yii\web\View::endBody()]] en layouts.
Por ejemplo, el siguiente código inyecta la fecha actual al final del body de la página:
```php
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
echo date('Y-m-d');
});
```
## Renderizando Página Estáticas <a name="rendering-static-pages"></a>
Con páginas estáticas nos referimos a esas páginas cuyo contenido es mayormente estático y sin necesidad de acceso
a datos dinámicos enviados desde los controladores.
Puedes generar páginas estáticas utilizando un código como el que sigue dentro de un controlador:
```php
public function actionAbout()
{
return $this->render('about');
}
```
Si un sitio Web contiene muchas páginas estáticas, resultaría tedioso repetir el mismo código en muchos lados.
Para resolver este problema, puedes introducir una [acción independiente](structure-controllers.md#standalone-actions)
llamada [[yii\web\ViewAction]] en el controlador. Por ejemplo,
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actions()
{
return [
'page' => [
'class' => 'yii\web\ViewAction',
],
];
}
}
```
Ahora, si creamos una vista llamada `about` bajo el directorio `@app/views/site/pages`, serás capáz
de mostrarla en la siguiente URL:
```
http://localhost/index.php?r=site/page&view=about
```
El parámetro `GET` `view` le comunica a [[yii\web\ViewAction]] cuál es la vista solicitada. La acción entonces buscará
esta vista dentro de `@app/views/site/pages`. Puedes configurar la propiedad [[yii\web\ViewAction::viewPrefix]]
para cambiar el directorio en el que se buscarán dichas páginas.
## Buenas Prácticas <a name="best-practices"></a>
Las vistas son responsables de la presentación de modelos en el formato que el usuario final desea. En general, las vistas
* deberían contener principalmente sólo código de presentación, como HTML, y PHP simple para recorrer, dar formato y renderizar datos.
* no deberían contener código que realiza consultas a la base de datos. Ese tipo de código debe ir en los modelos.
* deberían evitar el acceso directo a datos del `request`, como `$_GET` y/o `$_POST`. Esto es una responsabilidad de los controladores.
Si se necesitan datos del `request`, deben ser inyectados a la vista desde el controlador.
* pueden leer propiedades del modelo, pero no debería modificarlas.
Para hacer las vistas más manejables, evita crear vistas que son demasiado complejas o que contengan código redundante.
Puedes utilizar estas técnicas para alcanzar dicha meta:
* utiliza [layouts](#layouts) para representar secciones comunes (ej. encabezado y footer de la página).
* divide una vista compleja en varias más simples. Las vistas pequeñas pueden ser renderizadas y unidas una mayor
utilizando los métodos de renderización antes descritos.
* crea y utiliza [widgets](structure-widgets.md) como bloques de construcción de la vista.
* crea y utilizar helpers para transformar y dar formato a los datos en la vista.
......@@ -24,7 +24,7 @@ Mise en Route
* [Travailler avec les formulaires](start-forms.md)
* [Travailler avec les bases de données](start-databases.md)
* [Générer du code avec Gii](start-gii.md)
* [En savoir plus](start-looking-head.md)
* [En savoir plus](start-looking-ahead.md)
Structure Application
......
......@@ -24,7 +24,7 @@ Primeiros Passos
* [Trabalhando com Formulários](start-forms.md)
* [Trabalhando com Banco de Dados](start-databases.md)
* [Gerando Código com Gii](start-gii.md)
* [Visão Geral](start-looking-head.md)
* [Visão Geral](start-looking-ahead.md)
Estrutura de uma Aplicação
......
......@@ -24,7 +24,7 @@ All Rights Reserved.
* [Работа с формами](start-forms.md)
* [Работа с базами данных](start-databases.md)
* [Генерация кода при помощи Gii](start-gii.md)
* [Что дальше?](start-looking-head.md)
* [Что дальше?](start-looking-ahead.md)
Структура приложения
......
......@@ -24,7 +24,7 @@ All Rights Reserved.
* [Робота з формами](start-forms.md)
* [Робота з базами даних](start-databases.md)
* [Генерація коду за допомогою Gii](start-gii.md)
* [Що далі?](start-looking-head.md)
* [Що далі?](start-looking-ahead.md)
Структура додатка
......
......@@ -23,7 +23,7 @@ Yii 2.0 权威指南
* **已定稿** [使用 Forms](start-forms.md)
* **已定稿** [玩转 Databases](start-databases.md)
* **已定稿** [用 Gii 生成代码](start-gii.md)
* **已定稿** [更上一层楼](start-looking-head.md)
* **已定稿** [更上一层楼](start-looking-ahead.md)
应用结构
--------
......
......@@ -24,7 +24,7 @@ Getting Started
* [Working with Forms](start-forms.md)
* [Working with Databases](start-databases.md)
* [Generating Code with Gii](start-gii.md)
* [Looking Ahead](start-looking-head.md)
* [Looking Ahead](start-looking-ahead.md)
Application Structure
......
......@@ -12,7 +12,7 @@ start-hello.md | Yes
start-forms.md | Yes
start-databases.md | Yes
start-gii.md | Yes
start-looking-head.md | Yes
start-looking-ahead.md | Yes
structure-overview.md | Yes
structure-entry-scripts.md | Yes
structure-applications.md | Yes
......@@ -102,8 +102,8 @@ tutorial-performance-tuning.md |
tutorial-shared-hosting.md |
tutorial-template-engines.md |
tutorial-core-validators.md | Yes
bootstrap-widgets.md |
jui-widgets.md |
widget-bootstrap.md |
widget-jui.md |
helper-overview.md |
helper-array.md |
helper-html.md |
......
......@@ -7,6 +7,7 @@ Yii Framework 2 elasticsearch extension Change Log
- Bug #3587: Fixed an issue with storing empty records (cebe)
- Enh #3520: Added `unlinkAll()`-method to active record to remove all records of a model relation (NmDimas, samdark, cebe)
- Enh #3527: Added `highlight` property to Query and ActiveRecord. (Borales)
- Enh: Make error messages more readable in HTML output (cebe)
- Chg: asArray in ActiveQuery is now equal to using the normal Query. This means, that the output structure has changed and `with` is supported anymore. (cebe)
- Chg: Deletion of a record is now also considered successful if the record did not exist. (cebe)
- Chg: Requirement changes: Yii now requires elasticsearch version 1.0 or higher (cebe)
......
......@@ -10,6 +10,7 @@ namespace yii\elasticsearch;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\helpers\Json;
/**
......@@ -381,7 +382,7 @@ class Connection extends Component
'requestUrl' => $url,
'requestBody' => $requestBody,
'responseHeaders' => $headers,
'responseBody' => $body,
'responseBody' => $this->decodeErrorBody($body),
]);
}
......@@ -403,7 +404,7 @@ class Connection extends Component
'requestBody' => $requestBody,
'responseCode' => $responseCode,
'responseHeaders' => $headers,
'responseBody' => $body,
'responseBody' => $this->decodeErrorBody($body),
]);
}
if (isset($headers['content-type']) && !strncmp($headers['content-type'], 'application/json', 16)) {
......@@ -415,7 +416,7 @@ class Connection extends Component
'requestBody' => $requestBody,
'responseCode' => $responseCode,
'responseHeaders' => $headers,
'responseBody' => $body,
'responseBody' => $this->decodeErrorBody($body),
]);
}
} elseif ($responseCode == 404) {
......@@ -427,11 +428,29 @@ class Connection extends Component
'requestBody' => $requestBody,
'responseCode' => $responseCode,
'responseHeaders' => $headers,
'responseBody' => $body,
'responseBody' => $this->decodeErrorBody($body),
]);
}
}
/**
* Try to decode error information if it is valid json, return it if not.
* @param $body
* @return mixed
*/
protected function decodeErrorBody($body)
{
try {
$decoded = Json::decode($body);
if (isset($decoded['error'])) {
$decoded['error'] = preg_replace('/\b\w+?Exception\[/', "<span style=\"color: red;\">\\0</span>\n ", $decoded['error']);
}
return $decoded;
} catch(InvalidParamException $e) {
return $body;
}
}
public function getNodeInfo()
{
return $this->get([]);
......
......@@ -134,6 +134,7 @@ Yii Framework 2 Change Log
- Enh: Added param `hideOnSinglePage` to `yii\widgets\LinkPager` (arturf)
- Enh: Added support for array attributes in `in` validator (creocoder)
- Enh: Improved `yii\helpers\Inflector::slug` to support more cases for Russian, Hebrew and special characters (samdark)
- Enh: ListView now uses the widget ID in the base tag, consistent to gridview (cebe)
- Chg #2287: Split `yii\db\ColumnSchema::typecast()` into two methods `phpTypecast()` and `dbTypecast()` to allow specifying PDO type explicitly (cebe)
- Chg #2898: `yii\console\controllers\AssetController` is now using hashes instead of timestamps (samdark)
- Chg #2913: RBAC `DbManager` is now initialized via migration (samdark)
......@@ -150,6 +151,7 @@ Yii Framework 2 Change Log
- Chg #3897: Raised visibility of `yii\web\View::registerAssetFiles()` to protected (samdark)
- Chg #3899: Moved `MailEvent` class to `yii\mail` namespace (cebe)
- Chg #3956: Flash messages set via `Yii::$app->session->setFlash()` will be removed only if they are accessed (qiangxue)
- Chg #3989: The default value for `yii\log\FileTarget::$rotateByCopy` now defaults to true to work on windows by default (cebe)
- Chg #4071: `mail` component renamed to `mailer`, `yii\log\EmailTarget::$mail` renamed to `yii\log\EmailTarget::$mailer` (samdark)
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
- Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue)
......
......@@ -160,7 +160,7 @@ class Module extends ServiceLocator
public static function setInstance($instance)
{
if ($instance === null) {
unset(self::$_instances[get_class()]);
unset(self::$_instances[get_called_class()]);
} else {
self::$_instances[get_class($instance)] = $instance;
}
......
......@@ -219,9 +219,6 @@ class GridView extends BaseListView
if (!$this->formatter instanceof Formatter) {
throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.');
}
if (!isset($this->options['id'])) {
$this->options['id'] = $this->getId();
}
if (!isset($this->filterRowOptions['id'])) {
$this->filterRowOptions['id'] = $this->options['id'] . '-filters';
}
......
......@@ -277,10 +277,11 @@ class BaseFileHelper
*/
public static function removeDirectory($dir, $options = [])
{
if (!isset($options['traverseSymlinks'])) {
$options['traverseSymlinks'] = false;
if (!is_dir($dir)) {
return;
}
if (!is_dir($dir) || !($handle = opendir($dir))) {
if (!is_link($dir) || isset($options['traverseSymlinks']) && $options['traverseSymlinks']) {
if (!($handle = opendir($dir))) {
return;
}
while (($file = readdir($handle)) !== false) {
......@@ -288,21 +289,17 @@ class BaseFileHelper
continue;
}
$path = $dir . DIRECTORY_SEPARATOR . $file;
if (is_link($path)) {
if ($options['traverseSymlinks'] && is_dir($path)) {
if (is_dir($path)) {
static::removeDirectory($path, $options);
}
unlink($path);
} else {
if (is_file($path)) {
unlink($path);
} else {
static::removeDirectory($path, $options);
}
}
}
closedir($handle);
if (!is_link($dir)) {
}
if (is_link($dir)) {
unlink($dir);
} else {
rmdir($dir);
}
}
......
......@@ -52,16 +52,18 @@ class FileTarget extends Target
*/
public $dirMode = 0775;
/**
* @var boolean Whether to rotate primary log by copy and truncate
* which is more compatible with log tailers. Defaults to `false`.
* @var boolean Whether to rotate log files by copy and truncate in contrast to rotation by
* renaming files. Defaults to `true` to be more compatible with log tailers and is windows
* systems which do not play well with rename on open files. Rotation by renaming however is
* a bit faster.
*
* This property can also be useful on windows systems where the
* [rename()](http://www.php.net/manual/en/function.rename.php) function has some problems.
* See the [comment by Martin Pelletier](http://www.php.net/manual/en/function.rename.php#102274) in
* the PHP documentation for details. By setting rotateByCopy to `true` you can work
* The problem with windows systems where the [rename()](http://www.php.net/manual/en/function.rename.php)
* function does not work with files that are opened by some process is described in a
* [comment by Martin Pelletier](http://www.php.net/manual/en/function.rename.php#102274) in
* the PHP documentation. By setting rotateByCopy to `true` you can work
* around this problem.
*/
public $rotateByCopy = false;
public $rotateByCopy = true;
/**
......
......@@ -101,6 +101,9 @@ abstract class BaseListView extends Widget
if ($this->emptyText === null) {
$this->emptyText = Yii::t('yii', 'No results found.');
}
if (!isset($this->options['id'])) {
$this->options['id'] = $this->getId();
}
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment