Nas seções Paginação e Ordenação, descrevemos como os usuários finais podem escolher uma determinada página de dados para exibir e ordená-los por determinadas colunas. Uma vez que esta tarefa de paginação e ordenação de dados é muito comum, o Yii fornece um conjunto de classes data provider para encapsular estes recursos.
Um data provider é uma classe que implementa yii\data\DataProviderInterface. Ele suporta principalmente a recuperação de dados paginados e ordenados. Geralmente é usado para trabalhar com widgets de dados de modo que os usuários finais possam interativamente paginar e ordenar dados.
O Yii fornece as seguintes classes de data provider:
O uso de todos estes data providers compartilham o seguinte padrão comum:
// cria o data provider configurando suas propriedades de paginação e ordenação
$provider = new XyzDataProvider([
'pagination' => [...],
'sort' => [...],
]);
// recupera dados paginados e ordenados
$models = $provider->getModels();
// obtém o número de itens de dados na página atual
$count = $provider->getCount();
// obtém o número total de itens de dados de todas as páginas
$totalCount = $provider->getTotalCount();
Você define o comportamento da paginação e da ordenação do data provider configurando suas propriedades pagination e sort que correspondem às configurações yii\data\Pagination e yii\data\Sort respectivamente. Você também pode configurá-los como false
para desativar os recursos de paginação e/ou ordenação.
Os widgets de dados, assim como yii\grid\GridView, tem uma propriedade chamada dataProvider
que pode receber uma instância de data provider e exibir os dados que ele fornece. Por exemplo:
echo yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
]);
Estes data providers variam principalmente conforme a fonte de dados é especificada. Nas subseções seguintes, vamos explicar o uso detalhado de cada um dos data providers.
Para usar yii\data\ActiveDataProvider, você deve configurar sua propriedade query. Ele pode receber qualquer um dos objetos yii\db\Query ou yii\db\ActiveQuery. Se for o primeiro, os dados serão retornados em array; se for o último, os dados podem ser retornados em array ou uma instância de Active Record. Por exemplo:
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);
// retorna um array de objetos Post
$posts = $provider->getModels();
Se $query
no exemplo acima fosse criada usando o código a seguir, então o data provider retornaria um array.
use yii\db\Query;
$query = (new Query())->from('post')->where(['status' => 1]);
Observação: Se uma query já especificou a cláusula
orderBy, as novas instruções de ordenação dadas por usuários finais (através da configuração
sort) será acrescentada a cláusula
orderByexistente. Existindo qualquer uma das cláusulas
limite
offsetserá substituído pelo request de paginação dos usuários finais (através da configuração
pagination`).
Por padrão, yii\data\ActiveDataProvider utiliza o componente da aplicação db
como a conexão de banco de dados. Você pode usar uma conexão de banco de dados diferente, configurando a propriedade yii\data\ActiveDataProvider::$db.
O yii\data\SqlDataProvider trabalha com uma instrução SQL, que é usado para obter os dados necessários. Com base nas especificações de sort e
pagination, o provider ajustará as cláusulas ORDER BY
e LIMIT
da instrução SQL em conformidade para buscar somente a página de dados solicitada na ordem desejada.
Para usar yii\data\SqlDataProvider, você deve especificar a propriedade sql bem como a propriedade totalCount. Por exemplo:
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',
],
],
]);
// retorna um array de linha de dados
$models = $provider->getModels();
Observação: A propriedade totalCount é requerida somente se você precisar paginar os dados. Isto porque a instrução SQL definida por sql será modificada pelo provider para retornar somente a página atual de dados solicitada. O provider ainda precisa saber o número total de dados a fim de calcular corretamente o número de páginas disponíveis.
O yii\data\ArrayDataProvider é melhor usado quando se trabalha com um grande array. O provider permite-lhe retornar uma página dos dados do array ordenados por uma ou várias colunas. Para usar yii\data\ArrayDataProvider, você precisa especificar a propriedade allModels como um grande array. Elementos deste array podem ser outros arrays associados (por exemplo, resultados de uma query do DAO) ou objetos (por exemplo, uma instância do Active Record). Por exemplo:
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'],
],
]);
// obter as linhas na página corrente
$rows = $provider->getModels();
Observação: Comparando o Active Data Provider com o SQL Data Provider, o array data provider é menos eficiente porque requer o carregamento de todo os dados na memória.
Ao usar os itens de dados retornados por um data provider, muitas vezes você precisa identificar cada item de dados com uma chave única. Por exemplo, se os itens de dados representam as informações do cliente, você pode querer usar o ID do cliente como a chave para cada dado do cliente. Data providers podem retornar uma lista das tais chaves correspondentes aos itens de dados retornados por yii\data\DataProviderInterface::getModels(). Por exemplo:
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
]);
// retorna uma array de objetos Post
$posts = $provider->getModels();
// retorna os valores de chave primária correspondente a $posts
$ids = $provider->getKeys();
No exemplo abaixo, como você fornece um objeto yii\db\ActiveQuery para o yii\data\ActiveDataProvider, ele é inteligente o suficiente para retornar os valores de chave primária como chaves no resultado. Você também pode especificar explicitamente como os valores das chaves devem ser calculados configurando a propriedade yii\data\ActiveDataProvider::$key com um nome de coluna ou com uma função callback que retorna os valores das chaves. Por exemplo:
// usa a coluna "slug" como valor da chave
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => 'slug',
]);
// usa o resultados do md5(id) como valor da chave
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => function ($model) {
return md5($model->id);
}
]);
Para criar sua própria classe de data provider personalizada, você deve implementar o yii\data\DataProviderInterface. Um caminho fácil é estender de yii\data\BaseDataProvider, o que lhe permite concentrar-se na lógica principal do data provider. Em particular, você precisa principalmente implementar os seguintes métodos:
Abaixo está um exemplo de um data provider que lê dados em CSV eficientemente:
<?php
use yii\data\BaseDataProvider;
class CsvDataProvider extends BaseDataProvider
{
/**
* @var string nome do arquivo CSV que será lido
*/
public $filename;
/**
* @var string|nome da coluna chave ou função que a retorne
*/
public $key;
/**
* @var SplFileObject
*/
protected $fileObject; // SplFileObject é muito conveniente para procurar uma linha específica em um arquivo
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
// abre o arquivo
$this->fileObject = new SplFileObject($this->filename);
}
/**
* {@inheritdoc}
*/
protected function prepareModels()
{
$models = [];
$pagination = $this->getPagination();
if ($pagination === false) {
// no caso não há paginação, lê todas as linhas
while (!$this->fileObject->eof()) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
} else {
// no caso existe paginação, lê somente uma 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;
} else {
return array_keys($models);
}
}
/**
* {@inheritdoc}
*/
protected function prepareTotalCount()
{
$count = 0;
while (!$this->fileObject->eof()) {
$this->fileObject->next();
++$count;
}
return $count;
}
}
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.