Yii2 framework backup
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

7.4 KiB

Data providers

Note: This section is under development.

Data provider abstracts data set via yii\data\DataProviderInterface and handles pagination and sorting. It can be used by grids, lists and other data widgets.

In Yii there are three built-in data providers: yii\data\ActiveDataProvider, yii\data\ArrayDataProvider and yii\data\SqlDataProvider.

Active data provider

ActiveDataProvider provides data by performing DB queries using yii\db\Query and yii\db\ActiveQuery.

The following is an example of using it to provide ActiveRecord instances:

$provider = new ActiveDataProvider([
    'query' => Post::find(),
    'pagination' => [
        'pageSize' => 20,
    ],
]);

// get the posts in the current page
$posts = $provider->getModels();

And the following example shows how to use ActiveDataProvider without ActiveRecord:

$query = new Query();
$provider = new ActiveDataProvider([
    'query' => $query->from('post'),
    'sort' => [
        // Set the default sort by name ASC and created_at DESC.
        'defaultOrder' => [
            'name' => SORT_ASC, 
            'created_at' => SORT_DESC
        ]
    ],
    'pagination' => [
        'pageSize' => 20,
    ],
]);

// get the posts in the current page
$posts = $provider->getModels();

Array data provider

ArrayDataProvider implements a data provider based on a data array.

The yii\data\ArrayDataProvider::$allModels property contains all data models that may be sorted and/or paginated. ArrayDataProvider will provide the data after sorting and/or pagination. You may configure the yii\data\ArrayDataProvider::$sort and yii\data\ArrayDataProvider::$pagination properties to customize the sorting and pagination behaviors.

Elements in the yii\data\ArrayDataProvider::$allModels array may be either objects (e.g. model objects) or associative arrays (e.g. query results of DAO). Make sure to set the yii\data\ArrayDataProvider::$key property to the name of the field that uniquely identifies a data record or false if you do not have such a field.

Compared to ActiveDataProvider, ArrayDataProvider could be less efficient because it needs to have yii\data\ArrayDataProvider::$allModels ready.

ArrayDataProvider may be used in the following way:

$query = new Query();
$provider = new ArrayDataProvider([
    'allModels' => $query->from('post')->all(),
    'sort' => [
        'attributes' => ['id', 'username', 'email'],
    ],
    'pagination' => [
        'pageSize' => 10,
    ],
]);
// get the posts in the current page
$posts = $provider->getModels();

Note: if you want to use the sorting feature, you must configure the sort property so that the provider knows which columns can be sorted.

SQL data provider

SqlDataProvider implements a data provider based on a plain SQL statement. It provides data in terms of arrays, each representing a row of query result.

Like other data providers, SqlDataProvider also supports sorting and pagination. It does so by modifying the given yii\data\SqlDataProvider::$sql statement with "ORDER BY" and "LIMIT" clauses. You may configure the yii\data\SqlDataProvider::$sort and yii\data\SqlDataProvider::$pagination properties to customize sorting and pagination behaviors.

SqlDataProvider may be used in the following way:

$count = Yii::$app->db->createCommand('
    SELECT COUNT(*) FROM user WHERE status=:status
', [':status' => 1])->queryScalar();

$dataProvider = new SqlDataProvider([
    'sql' => 'SELECT * FROM user WHERE status=:status',
    'params' => [':status' => 1],
    'totalCount' => $count,
    'sort' => [
        'attributes' => [
            'age',
            'name' => [
                'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
                'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
                'default' => SORT_DESC,
                'label' => 'Name',
            ],
        ],
    ],
    'pagination' => [
        'pageSize' => 20,
    ],
]);

// get the user records in the current page
$models = $dataProvider->getModels();

Note: if you want to use the pagination feature, you must configure the yii\data\SqlDataProvider::$totalCount property to be the total number of rows (without pagination). And if you want to use the sorting feature, you must configure the yii\data\SqlDataProvider::$sort property so that the provider knows which columns can be sorted.

Implementing your own custom data provider

Yii allows you to introduce your own custom data providers. In order to do it you need to implement the following protected methods:

  • prepareModels that prepares the data models that will be made available in the current page and returns them as an array.
  • prepareKeys that accepts an array of currently available data models and returns keys associated with them.
  • prepareTotalCount that returns a value indicating the total number of data models in the data provider.

Below is an example of a data provider that reads CSV efficiently:

<?php
class CsvDataProvider extends \yii\data\BaseDataProvider
{
    /**
     * @var string name of the file to read
     */
    public $filename;
    
    /**
     * @var string|callable name of the key column or a callable returning it
     */
    public $key;
    
    /**
     * @var SplFileObject
     */
    protected $fileObject; // SplFileObject is very convenient for seeking to particular line in a file
    
 
    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        
        // open file
        $this->fileObject = new SplFileObject($this->filename);
    }
 
    /**
     * @inheritdoc
     */
    protected function prepareModels()
    {
        $models = [];
        $pagination = $this->getPagination();
 
        if ($pagination === false) {
            // in case there's no pagination, read all lines
            while (!$this->fileObject->eof()) {
                $models[] = $this->fileObject->fgetcsv();
                $this->fileObject->next();
            }
        } else {
            // in case there's pagination, read only a single page
            $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;
    }
}