diff --git a/docs/guide/output-data-providers.md b/docs/guide/output-data-providers.md index 5d9351d..843bc69 100644 --- a/docs/guide/output-data-providers.md +++ b/docs/guide/output-data-providers.md @@ -36,8 +36,10 @@ $count = $provider->getCount(); $totalCount = $provider->getTotalCount(); ``` -The `pagination` and `sort` properties of data providers correspond to the configurations for -[[yii\data\Pagination]] and [[yii\data\Sort]], respectively. +You specify the pagination and sorting behaviors of a data provider by configuring its +[[yii\data\BaseDataProvider::pagination|pagination]] and [[yii\data\BaseDataProvider::sort|sort]] properties +which correspond to the configurations for [[yii\data\Pagination]] and [[yii\data\Sort]], respectively. +You may also configure them to be false to disable pagination and/or sorting features. [Data widgets](output-data-widgets.md), such as [[yii\grid\GridView]], have a property named `dataProvider` which can take a data provider instance and display the data it provides. For example, @@ -67,7 +69,7 @@ $query = Post::find()->where(['status' => 1]); $provider = new ActiveDataProvider([ 'query' => Post::find(), 'pagination' => [ - 'pageSize' => 20, + 'pageSize' => 10, ], 'sort' => [ 'defaultOrder' => [ @@ -99,104 +101,152 @@ use a different database connection by configuring the [[yii\data\ActiveDataProv ## SQL Data Provider -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. +[[yii\data\SqlDataProvider]] works with a raw SQL statement which is used to fetch the needed +data. Based on the specifications of [[yii\data\SqlDataProvider::sort|sort]] and +[[yii\data\SqlDataProvider::pagination|pagination]], the provider will adjust the `ORDER BY` and `LIMIT` +clauses of the SQL statement accordingly to fetch only the requested page of data in the desired order. -`SqlDataProvider` may be used in the following way: +To use [[yii\data\SqlDataProvider]], you should specify the [[yii\data\SqlDataProvider::sql|sql]] property as well +as the [[yii\data\SqlDataProvider::totalCount|totalCount]] property. For example, ```php +use yii\data\SqlDataProvider; + $count = Yii::$app->db->createCommand(' - SELECT COUNT(*) FROM user WHERE status=:status + SELECT COUNT(*) FROM post WHERE status=:status ', [':status' => 1])->queryScalar(); -$dataProvider = new SqlDataProvider([ - 'sql' => 'SELECT * FROM user WHERE status=:status', +$provider = new SqlDataProvider([ + 'sql' => 'SELECT * FROM post WHERE status=:status', 'params' => [':status' => 1], 'totalCount' => $count, + 'pagination' => [ + 'pageSize' => 10, + ], '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', - ], + 'title', + 'view_count', + 'created_at', ], ], - 'pagination' => [ - 'pageSize' => 20, - ], ]); -// get the user records in the current page -$models = $dataProvider->getModels(); +// returns an array of data rows +$models = $provider->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. +> Info: The [[yii\data\SqlDataProvider::totalCount|totalCount]] property is required only if you need to + paginate the data. This is because the SQL statement specified via [[yii\data\SqlDataProvider::sql|sql]] + will be modified by the provider to return only the currently requested page of data. The provider still + needs to know the total number of data items in order to correctly calculate the number of pages available. ## 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. +[[yii\data\ArrayDataProvider]] is best used when working with a big array. The provider allows you to return +a page of the array data sorted by one or multiple columns. To use [[yii\data\ArrayDataProvider]], you should +specify the [[yii\data\ArrayDataProvider::allModels|allModels]] property as the big array. +Elements in the big array can be either associative arrays +(e.g. query results of [DAO](db-dao.md)) or objects (e.g. [Active Record](db-active-record.md) instances). +For example, -Compared to `ActiveDataProvider`, `ArrayDataProvider` could be less efficient -because it needs to have [[yii\data\ArrayDataProvider::$allModels]] ready. +```php +use yii\data\ArrayDataProvider; -ArrayDataProvider may be used in the following way: +$data = [ + ['id' => 1, 'name' => 'name 1', ...], + ['id' => 2, 'name' => 'name 2', ...], + ... + ['id' => 100, 'name' => 'name 100', ...], +]; -```php -$query = new Query(); $provider = new ArrayDataProvider([ - 'allModels' => $query->from('post')->all(), - 'sort' => [ - 'attributes' => ['id', 'username', 'email'], - ], + 'allModels' => $data, 'pagination' => [ 'pageSize' => 10, ], + 'sort' => [ + 'attributes' => ['id', 'name'], + ], ]); -// get the posts in the current page + +// get the rows in the currently requested page +$rows = $provider->getModels(); +``` + +> Note: Compared to [Active Data Provider](#active-data-provider) and [SQL Data Provider](#sql-data-provider), + array data provider is less efficient because it requires loading *all* data into the memory. + + +## Working with Data Keys + +When using the data items returned by a data provider, you often need to identify each data item with a unique key. +For example, if the data items represent customer information, you may want to use the customer ID as the key +for each customer data. Data providers can return a list of such keys corresponding with the data items returned +by [[yii\data\DataProviderInterface::getModels()]]. For example, + +```php +use yii\data\ActiveDataProvider; + +$query = Post::find()->where(['status' => 1]); + +$provider = new ActiveDataProvider([ + 'query' => Post::find(), +]); + +// returns an array of Post objects $posts = $provider->getModels(); + +// returns the primary key values corresponding to $posts +$ids = $provider->getKeys(); ``` -> 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. +In the above example, because you provide to [[yii\data\ActiveDataProvider]] an [[yii\db\ActiveQuery]] object, +it is intelligent enough to return primary key values as the keys. You may also explicitly specify how the key +values should be calculated by configuring [[yii\data\ActiveDataProvider::key]] with a column name or +a callable calculating key values. For example, +```php +// use "slug" column as key values +$provider = new ActiveDataProvider([ + 'query' => Post::find(), + 'key' => 'slug', +]); -Implementing your own custom data provider ------------------------------------------- +// use the result of md5(id) as key values +$provider = new ActiveDataProvider([ + 'query' => Post::find(), + 'key' => function ($model) { + return md5($model->id); + } +]); +``` + + +## Creating 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: +To create your own custom data provider classes, you should implement [[yii\data\DataProviderInterface]]. +An easier way is to extend from [[yii\data\BaseDataProvider]] which allows you to focus on the core data provider +logic. In particular, you mainly need to implement the following 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. +- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]: prepares the data models that will be made + available in the current page and returns them as an array. +- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]: accepts an array of currently available data models + and returns keys associated with them. +- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]: 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: +Below is an example of a data provider that reads CSV data efficiently: ```php