Issues (75)

app/Http/Rest/ActiveController.php (2 issues)

1
<?php
2
namespace App\Http\Rest;
3
4
use yii\data\ActiveDataFilter;
5
use yii\data\ActiveDataProvider;
6
use yii\data\DataFilter;
7
use yii\data\Pagination;
8
use yii\data\Sort;
9
use yii\db\ActiveQuery;
10
use yii\rest\ActiveController as BaseActiveController;
11
use yii\rest\IndexAction;
12
use yii\rest\Action;
13
use yii\web\ForbiddenHttpException;
14
use yii\rest\ViewAction;
15
use yii\web\NotFoundHttpException;
16
use Yii;
17
18
class ActiveController extends BaseActiveController
19
{
20
    public $serializer = Serializer::class;
21
22
    public function actions()
23
    {
24
        return [
25
            'index' => [
26
                'class' => IndexAction::class,
27
                'modelClass' => $this->modelClass,
28
                'checkAccess' => [$this, 'checkAccess'],
29
                'dataFilter' => $this->dataFilter(),
30
                'prepareDataProvider' => [$this, 'prepareDataProvider'],
31
            ],
32
            'view' => [
33
                'class' => ViewAction::class,
34
                'modelClass' => $this->modelClass,
35
                'findModel' => [$this, 'findModel'],
36
                'checkAccess' => [$this, 'checkAccess'],
37
            ],
38
            'create' => [
39
                'class' => CreateAction::class,
40
                'modelClass' => $this->modelClass,
41
                'checkAccess' => [$this, 'checkAccess'],
42
                'scenario' => $this->createScenario,
43
            ],
44
            'update' => [
45
                'class' => UpdateAction::class,
46
                'modelClass' => $this->modelClass,
47
                'checkAccess' => [$this, 'checkAccess'],
48
                'scenario' => $this->updateScenario,
49
                'findModel' => [$this, 'findModel'],
50
            ],
51
            'delete' => [
52
                'class' => DeleteAction::class,
53
                'modelClass' => $this->modelClass,
54
                'checkAccess' => [$this, 'checkAccess'],
55
                'findModel' => [$this, 'findModel'],
56
            ],
57
            'options' => [
58
                'class' => OptionsAction::class,
59
            ],
60
        ];
61
    }
62
63
    /**
64
     * @param string $id
65
     * @param Action $action
66
     */
67
    public function findModel($id, $action)
68
    {
69
        $model = $this->findModelById($id, $action);
70
71
        if (isset($model)) {
72
            return $model;
73
        }
74
75
        throw new NotFoundHttpException("Object not found: $id");
76
    }
77
78
    /**
79
     * @param string $id
80
     * @param Action $action
81
     */
82
    protected function findModelById($id, $action)
83
    {
84
        /* @var yii\db\ActiveRecordInterface $modelClass */
85
        $modelClass = $action->modelClass;
86
        $keys = $modelClass::primaryKey();
87
        if (count($keys) > 1) {
88
            $values = explode(',', $id);
89
            if (count($keys) === count($values)) {
90
                return $modelClass::findOne(array_combine($keys, $values));
91
            }
92
        } elseif ($id !== null) {
93
            return $modelClass::findOne($id);
94
        }
95
    }
96
97
    /**
98
     * Returns data filter.
99
     *
100
     * @return null|DataFilter
101
     */
102
    public function dataFilter()
103
    {
104
        $searchModel = $this->searchModel();
105
        if ($searchModel === null) {
106
            return null;
107
        }
108
109
        return [
110
            'class' => ActiveDataFilter::class,
111
            'filterAttributeName' => 'filter',
112
            'searchModel' => $searchModel,
113
        ];
114
    }
115
116
    /**
117
     * Returns search model.
118
     *
119
     * @return null|array|callable
120
     */
121
    protected function searchModel()
122
    {
123
        return null;
124
    }
125
126
    /**
127
     * Gets data provider.
128
     *
129
     * @param IndexAction $action
130
     * @param null|DataFilter $filter
131
     *
132
     * @return mixed
133
     */
134
    public function prepareDataProvider(IndexAction $action, $filter)
135
    {
136
        $requestParams = Yii::$app->getRequest()->getBodyParams();
137
        if (empty($requestParams)) {
138
            $requestParams = Yii::$app->getRequest()->getQueryParams();
139
        }
140
141
        $query = $this->getQuery($action);
142
        if (!empty($filter)) {
143
            $this->applyFilter($query, $action->dataFilter->searchModel, $filter);
144
        }
145
146
        return Yii::createObject([
147
            'class' => ActiveDataProvider::class,
148
            'query' => $query,
149
            'pagination' => [
150
                'class' => Pagination::class,
151
                'pageParam' => 'page',
152
                'pageSizeParam' => 'limit',
153
                'pageSizeLimit' => [1, 100],
154
                'defaultPageSize' => 20,
155
                'params' => $requestParams,
156
            ],
157
            'sort' => [
158
                'class' => Sort::class,
159
                'sortParam' => 'sort',
160
                'params' => $requestParams,
161
            ],
162
        ]);
163
    }
164
165
    /**
166
     * Returns active query instance.
167
     *
168
     * @param Action $action
169
     *
170
     * @return ActiveQuery
171
     */
172
    protected function getQuery($action)
173
    {
174
        /* @var $modelClass \yii\db\BaseActiveRecord */
175
        $modelClass = $action->modelClass;
176
        $query = $modelClass::find();
177
178
        return $query;
179
    }
180
181
    /**
182
     * Applies filter on query.
183
     *
184
     * @param ActiveQuery $query
185
     * @param \yii\base\Model
186
     * @param DataFilter $filter
187
     */
188
    protected function applyFilter($query, $model, $filter)
0 ignored issues
show
The parameter $model is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

188
    protected function applyFilter($query, /** @scrutinizer ignore-unused */ $model, $filter)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
189
    {
190
        $query->andWhere($filter);
191
    }
192
193
    public function checkAccess($action, $model = null, $params = [])
194
    {
195
        $permission = $this->getPermission($action);
196
        if ($permission === null) {
197
            return;
198
        }
199
200
        Yii::info('Checking permission: ' . $permission, __METHOD__);
201
        $user = Yii::$app->getUser();
202
        if (!$user->can($permission, ['model' => $model])) {
203
            Yii::error(sprintf("User #%d doesn't have permission: %s", $user->getId(), $permission), __METHOD__);
204
            throw new ForbiddenHttpException();
205
        }
206
    }
207
208
    /**
209
     * @return string|null
210
     */
211
    protected function getPermission($action)
0 ignored issues
show
The parameter $action is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

211
    protected function getPermission(/** @scrutinizer ignore-unused */ $action)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
212
    {
213
        return null;
214
    }
215
}
216