diff --git a/docs/guide-es/output-data-providers.md b/docs/guide-es/output-data-providers.md new file mode 100644 index 0000000000..324613743e --- /dev/null +++ b/docs/guide-es/output-data-providers.md @@ -0,0 +1,421 @@ +Proveedores de datos +==================== + +En las secciones sobre [paginación](output-pagination.md) y [ordenación](output-sorting.md) se +describe como permitir a los usuarios finales elegir que se muestre una página de datos en +particular, y ordenar los datos por algunas columnas. Como la tarea de paginar y ordenar datos +es muy común, Yii proporciona un conjunto de clases *proveedoras de datos* para encapsularla. + +Un proveedor de datos es una clase que implementa la interfaz [[yii\data\DataProviderInterface]]. +Básicamente se encarga de obtener datos paginados y ordenados. Normalmente se usa junto con +[_widgets_ de datos](output-data-widgets.md) para que los usuarios finales puedan paginar y +ordenar datos de forma interactiva. + +Yii incluye las siguientes clases proveedoras de datos: + +* [[yii\data\ActiveDataProvider]]: usa [[yii\db\Query]] o [[yii\db\ActiveQuery]] para consultar datos de bases de datos y devolverlos como _arrays_ o instancias [Active Record](db-active-record.md). +* [[yii\data\SqlDataProvider]]: ejecuta una sentencia SQL y devuelve los datos de la base de datos como _arrays_. +* [[yii\data\ArrayDataProvider]]: toma un _array_ grande y devuelve una rodaja de él basándose en las especificaciones de paginación y ordenación. + +El uso de todos estos proveedores de datos comparte el siguiente patrón común: + +```php +// Crear el proveedor de datos configurando sus propiedades de paginación y ordenación +$provider = new XyzDataProvider([ + 'pagination' => [...], + 'sort' => [...], +]); + +// Obtener los datos paginados y ordenados +$models = $provider->getModels(); + +// Obtener el número de elementos de la página actual +$count = $provider->getCount(); + +// Obtener el número total de elementos entre todas las páginas +$totalCount = $provider->getTotalCount(); +``` + +Se puede especificar los comportamientos de paginación y ordenación de un proveedor de datos +configurando sus propiedades [[yii\data\BaseDataProvider::pagination|pagination]] y +[[yii\data\BaseDataProvider::sort|sort]], que corresponden a las configuraciones para +[[yii\data\Pagination]] y [[yii\data\Sort]] respectivamente. También se pueden configurar a +`false` para inhabilitar las funciones de paginación y/u ordenación. + +Los [_widgets_ de datos](output-data-widgets.md), como [[yii\grid\GridView]], tienen una +propiedad llamada `dataProvider` que puede tomar una instancia de un proveedor de datos y +mostrar los datos que proporciona. Por ejemplo, + +```php +echo yii\grid\GridView::widget([ + 'dataProvider' => $dataProvider, +]); +``` + +Estos proveedores de datos varían principalmente en la manera en que se especifica la fuente de +datos. En las siguientes secciones se explica el uso detallado de cada uno de estos proveedores +de datos. + + +## Proveedor de datos activo + +Para usar [[yii\data\ActiveDataProvider]], hay que configurar su propiedad +[[yii\data\ActiveDataProvider::query|query]]. +Puede tomar un objeto [[yii\db\Query] o [[yii\db\ActiveQuery]]. En el primer caso, los datos +devueltos serán _arrays_. En el segundo, los datos devueltos pueden ser _arrays_ o instancias de +[Active Record](db-active-record.md). Por ejemplo: + + +```php +use yii\data\ActiveDataProvider; + +$query = Post::find()->where(['state_id' => 1]); + +$provider = new ActiveDataProvider([ + 'query' => $query, + 'pagination' => [ + 'pageSize' => 10, + ], + 'sort' => [ + 'defaultOrder' => [ + 'created_at' => SORT_DESC, + 'title' => SORT_ASC, + ] + ], +]); + +// Devuelve un array de objetos Post +$posts = $provider->getModels(); +``` + +En el ejemplo anterior, si `$query` se crea el siguiente código, el proveedor de datos +devolverá _arrays_ en bruto. + +```php +use yii\db\Query; + +$query = (new Query())->from('post')->where(['state' => 1]); +``` + +> Note: Si una consulta ya tiene la cláusula `orderBy`, las nuevas instrucciones de ordenación + dadas por los usuarios finales (mediante la configuración de `sort`) se añadirán a la cláusula + `orderBy` previa. Las cláusulas `limit` y `offset` que pueda haber se sobrescribirán por la + petición de paginación de los usuarios finales (mediante la configuración de `pagination`). + +Por omisión, [[yii\data\ActiveDataProvider]] usa el componente `db` de la aplicación como +conexión con la base de datos. Se puede indicar una conexión con base de datos diferente +configurando la propiedad [[yii\data\ActiveDataProvider::db]]. + + +## Proveedor de datos SQL + +[[yii\data\SqlDataProvider]] funciona con una sentencia SQL en bruto, que se usa para obtener +los datos requeridos. +Basándose en las especificaciones de [[yii\data\SqlDataProvider::sort|sort]] y +[[yii\data\SqlDataProvider::pagination|pagination]], el proveedor ajustará las cláusulas +`ORDER BY` y `LIMIT` de la sentencia SQL acordemente para obtener sólo la página de datos +solicitados en el orden deseado. + +Para usar [[yii\data\SqlDataProvider]], hay que especificar las propiedades +[[yii\data\SqlDataProvider::sql|sql]] y [yii\data\SqlDataProvider::totalCount|totalCount]]. +Por ejemplo: + +```php +use yii\data\SqlDataProvider; + +$count = Yii::$app->db->createCommand(' + SELECT COUNT(*) FROM post WHERE status=:status +', [':status' => 1])->queryScalar(); + +$provider = new SqlDataProvider([ + 'sql' => 'SELECT * FROM post WHERE status=:status', + 'params' => [':status' => 1], + 'totalCount' => $count, + 'pagination' => [ + 'pageSize' => 10, + ], + 'sort' => [ + 'attributes' => [ + 'title', + 'view_count', + 'created_at', + ], + ], +]); + +// Devuelve un array de filas de datos +$models = $provider->getModels(); +``` + +> Info: La propiedad [[yii\data\SqlDataProvider::totalCount|totalCount]] se requiere sólo si se + necesita paginar los datos. Esto es porque el proveedor modificará la sentencia SQL + especificada vía [[yii\data\SqlDataProvider::sql|sql]] para que devuelva sólo la pagina de + datos solicitada. El proveedor sigue necesitando saber el número total de elementos de datos + para calcular correctamente el número de páginas. + + +## Proveedor de datos de _arrays_ + +Se recomienda usar [[yii\data\ArrayDataProvider]] cuando se trabaja con un _array_ grande. +El proveedor permite devolver una página de los datos del _array_ ordenados por una o varias +columnas. Para usar [[yii\data\ArrayDataProvider]], hay que especificar la propiedad +[[yii\data\ArrayDataProvider::allModels|allModels]] como el _array_ grande. Los elementos +del _array_ grande pueden ser _arrays_ asociativos (por ejemplo resultados de consultas de +[DAO](db-dao.md) u objetos (por ejemplo instancias de [Active Record](db-active-record.md). +Por ejemplo: + +```php +use yii\data\ArrayDataProvider; + +$data = [ + ['id' => 1, 'name' => 'name 1', ...], + ['id' => 2, 'name' => 'name 2', ...], + ... + ['id' => 100, 'name' => 'name 100', ...], +]; + +$provider = new ArrayDataProvider([ + 'allModels' => $data, + 'pagination' => [ + 'pageSize' => 10, + ], + 'sort' => [ + 'attributes' => ['id', 'name'], + ], +]); + +// Obtener las filas de la página solicitada +$rows = $provider->getModels(); +``` + +> Note: En comparación con [Active Data Provider](#active-data-provider) y + [SQL Data Provider](#sql-data-provider), Array Data Provider es menos eficiente porque + requiere cargar *todos* los datos en memoria. + + +## Trabajar con las claves de los datos + +Al utilizar los elementos de datos devueltos por un proveedor de datos, con frecuencia +necesita identificar cada elemento de datos con una clave única. +Por ejemplo, si los elementos de datos representan información de los clientes, puede querer +usar el ID de cliente como la clave de cada conjunto de datos de un cliente. +Los proveedores de datos pueden devolver una lista de estas claves correspondientes a los +elementos de datos devueltos por [[yii\data\DataProviderInterface::getModels()]]. +Por ejemplo: + +```php +use yii\data\ActiveDataProvider; + +$query = Post::find()->where(['status' => 1]); + +$provider = new ActiveDataProvider([ + 'query' => $query, +]); + +// Devuelve un array de objetos Post +$posts = $provider->getModels(); + +// Devuelve los valores de las claves primarias correspondientes a $posts +$ids = $provider->getKeys(); +``` + +En el ejemplo superior, como se le proporciona a [[yii\data\ActiveDataProvider]] un objeto +[[yii\db\ActiveQuery]], es lo suficientemente inteligente como para devolver los valores de +las claves primarias como las claves. También puede indicar explícitamente cómo se deben +calcular los valores de la clave configurando [[yii\data\ActiveDataProvider::key]] con un +nombre de columna o un invocable que calcule los valores de la clave. Por ejemplo: + +```php +// Utiliza la columna «slug» como valores de la clave +$provider = new ActiveDataProvider([ + 'query' => Post::find(), + 'key' => 'slug', +]); + +// Utiliza el resultado de md5(id) como valores de la clave +$provider = new ActiveDataProvider([ + 'query' => Post::find(), + 'key' => function ($model) { + return md5($model->id); + } +]); +``` + + +## Creación de un proveedor de datos personalizado + +Para crear su propio proveedor de datos personalizado, debe implementar +[[yii\data\DataProviderInterface]]. +Una manera más fácil es extender [[yii\data\BaseDataProvider]], que le permite centrarse +en la lógica central del proveedor de datos. En particular, esencialmente necesita +implementar los siguientes métodos: + +- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]: prepara los modelos + de datos que estarán disponibles en la página actual y los devuelve como un _array_. +- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]: acepta un _array_ de + modelos de datos disponibles actualmente y devuelve las claves asociadas a ellos. +- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]: devuelve un valor + que indica el número total de modelos de datos en el proveedor de datos. + +Debajo se muestra un ejemplo de un proveedor de datos que lee datos CSV eficientemente: + +```php +fileObject = new SplFileObject($this->filename); + } + + /** + * {@inheritdoc} + */ + protected function prepareModels() + { + $models = []; + $pagination = $this->getPagination(); + + if ($pagination === false) { + // En caso de que no haya paginación, leer todas las líneas + while (!$this->fileObject->eof()) { + $models[] = $this->fileObject->fgetcsv(); + $this->fileObject->next(); + } + } else { + // En caso de que haya paginación, leer sólo una única página + $pagination->totalCount = $this->getTotalCount(); + $this->fileObject->seek($pagination->getOffset()); + $limit = $pagination->getLimit(); + + for ($count = 0; $count < $limit; ++$count) { + $models[] = $this->fileObject->fgetcsv(); + $this->fileObject->next(); + } + } + + return $models; + } + + /** + * {@inheritdoc} + */ + protected function prepareKeys($models) + { + if ($this->key !== null) { + $keys = []; + + foreach ($models as $model) { + if (is_string($this->key)) { + $keys[] = $model[$this->key]; + } else { + $keys[] = call_user_func($this->key, $model); + } + } + + return $keys; + } + + return array_keys($models); + } + + /** + * {@inheritdoc} + */ + protected function prepareTotalCount() + { + $count = 0; + + while (!$this->fileObject->eof()) { + $this->fileObject->next(); + ++$count; + } + + return $count; + } +} +``` + +## Filtrar proveedores de datos usando filtros de datos + +Si bien puede construir condiciones para un proveedor de datos activo manualmente tal +y como se describe en las secciones [Filtering Data](output-data-widgets.md#filtering-data) +y [Separate Filter Form](output-data-widgets.md#separate-filter-form) de la guía de +_widgets_ de datos, Yii tiene filtros de datos que son muy útiles si necesita +condiciones de filtro flexibles. Los filtros de datos se pueden usar así: + +```php +$filter = new ActiveDataFilter([ + 'searchModel' => 'app\models\PostSearch' +]); + +$filterCondition = null; + +// Puede cargar los filtros de datos de cualquier fuente. +// Por ejemplo, si prefiere JSON en el cuerpo de la petición, +// use Yii::$app->request->getBodyParams() aquí abajo: +if ($filter->load(\Yii::$app->request->get())) { + $filterCondition = $filter->build(); + if ($filterCondition === false) { + // Serializer recibiría errores + return $filter; + } +} + +$query = Post::find(); +if ($filterCondition !== null) { + $query->andWhere($filterCondition); +} + +return new ActiveDataProvider([ + 'query' => $query, +]); +``` + +El propósito del modelo `PostSearch` es definir por qué propiedades y valores se permite filtrar: + +```php +use yii\base\Model; + +class PostSearch extends Model +{ + public $id; + public $title; + + public function rules() + { + return [ + ['id', 'integer'], + ['title', 'string', 'min' => 2, 'max' => 200], + ]; + } +} +``` + +Los filtros de datos son bastante flexibles. Puede personalizar cómo se construyen +las condiciones y qué operadores se permiten. +Para más detalles consulte la documentación de la API en [[\yii\data\DataFilter]]. diff --git a/docs/guide-es/translators.json b/docs/guide-es/translators.json index e5431ad8ea..ab94ea2b10 100644 --- a/docs/guide-es/translators.json +++ b/docs/guide-es/translators.json @@ -1,6 +1,7 @@ [ "Antonio Ramirez", "Daniel Gómez Pan", + "Enrique Matías Sánchez (Quique)", "'larnu'", "Luciano Baraglia" -] \ No newline at end of file +]