Skip to content

Commit f763caf

Browse files
authored
Merge pull request #51 from tuyakhov/filtering
Introduce IndexAction with filtering and sorting
2 parents a462324 + b3667c8 commit f763caf

File tree

5 files changed

+311
-47
lines changed

5 files changed

+311
-47
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
}
1818
],
1919
"require": {
20-
"yiisoft/yii2": "^2.0.10"
20+
"yiisoft/yii2": "^2.0.13"
2121
},
2222
"require-dev": {
2323
"phpunit/phpunit": "5.5.*"

composer.lock

Lines changed: 111 additions & 46 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/actions/IndexAction.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
/**
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
4+
*/
5+
6+
namespace tuyakhov\jsonapi\actions;
7+
8+
9+
use tuyakhov\jsonapi\Inflector;
10+
use yii\data\ActiveDataProvider;
11+
use yii\data\DataFilter;
12+
use Yii;
13+
14+
class IndexAction extends Action
15+
{
16+
/**
17+
* @var callable a PHP callable that will be called to prepare a data provider that
18+
* should return a collection of the models. If not set, [[prepareDataProvider()]] will be used instead.
19+
* The signature of the callable should be:
20+
*
21+
* ```php
22+
* function (IndexAction $action) {
23+
* // $action is the action object currently running
24+
* }
25+
* ```
26+
*
27+
* The callable should return an instance of [[ActiveDataProvider]].
28+
*
29+
* If [[dataFilter]] is set the result of [[DataFilter::build()]] will be passed to the callable as a second parameter.
30+
* In this case the signature of the callable should be the following:
31+
*
32+
* ```php
33+
* function (IndexAction $action, mixed $filter) {
34+
* // $action is the action object currently running
35+
* // $filter the built filter condition
36+
* }
37+
* ```
38+
*/
39+
public $prepareDataProvider;
40+
/**
41+
* @var DataFilter|null data filter to be used for the search filter composition.
42+
* You must setup this field explicitly in order to enable filter processing.
43+
* For example:
44+
*
45+
* ```php
46+
* [
47+
* 'class' => 'yii\data\ActiveDataFilter',
48+
* 'searchModel' => function () {
49+
* return (new \yii\base\DynamicModel(['id' => null, 'name' => null, 'price' => null]))
50+
* ->addRule('id', 'integer')
51+
* ->addRule('name', 'trim')
52+
* ->addRule('name', 'string')
53+
* ->addRule('price', 'number');
54+
* },
55+
* ]
56+
* ```
57+
*
58+
* @see DataFilter
59+
*
60+
* @since 2.0.13
61+
*/
62+
public $dataFilter;
63+
64+
65+
/**
66+
* @return ActiveDataProvider
67+
* @throws \yii\base\InvalidConfigException
68+
*/
69+
public function run()
70+
{
71+
if ($this->checkAccess) {
72+
call_user_func($this->checkAccess, $this->id);
73+
}
74+
75+
return $this->prepareDataProvider();
76+
}
77+
78+
/**
79+
* Prepares the data provider that should return the requested collection of the models.
80+
* @return mixed|null|object|DataFilter|ActiveDataProvider
81+
* @throws \yii\base\InvalidConfigException
82+
*/
83+
protected function prepareDataProvider()
84+
{
85+
$filter = $this->getFilter();
86+
87+
if ($this->prepareDataProvider !== null) {
88+
return call_user_func($this->prepareDataProvider, $this, $filter);
89+
}
90+
91+
/* @var $modelClass \yii\db\BaseActiveRecord */
92+
$modelClass = $this->modelClass;
93+
94+
$query = $modelClass::find();
95+
if (!empty($filter)) {
96+
$query->andWhere($filter);
97+
}
98+
99+
return Yii::createObject([
100+
'class' => ActiveDataProvider::className(),
101+
'query' => $query,
102+
'pagination' => [
103+
'params' => Yii::$app->getRequest()->getQueryParam('page', []),
104+
'pageSizeParam' => 'size'
105+
],
106+
'sort' => [
107+
'enableMultiSort' => true
108+
]
109+
]);
110+
}
111+
112+
protected function getFilter()
113+
{
114+
if ($this->dataFilter === null) {
115+
return null;
116+
}
117+
$requestParams = Yii::$app->getRequest()->getQueryParam('filter', []);
118+
$attributeMap = [];
119+
foreach ($requestParams as $attribute => $value) {
120+
$attributeMap[$attribute] = Inflector::camel2id(Inflector::variablize($attribute), '_');
121+
if (strpos($value, ',') !== false) {
122+
$requestParams[$attribute] = ['in' => explode(',', $value)];
123+
}
124+
}
125+
$config = array_merge(['attributeMap' => $attributeMap], $this->dataFilter);
126+
/** @var DataFilter $dataFilter */
127+
$dataFilter = Yii::createObject($config);
128+
if ($dataFilter->load(['filter' => $requestParams])) {
129+
return $dataFilter->build();
130+
}
131+
return null;
132+
}
133+
}

0 commit comments

Comments
 (0)