BaseController::setModelByConditions()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 4
nop 1
1
<?php
2
3
namespace Itstructure\UsersModule\controllers;
4
5
use Yii;
6
use yii\db\ActiveRecordInterface;
7
use yii\helpers\ArrayHelper;
8
use yii\filters\{VerbFilter, AccessControl};
9
use yii\base\UnknownMethodException;
10
use yii\web\{IdentityInterface, ConflictHttpException, BadRequestHttpException, NotFoundHttpException, Controller};
11
use Itstructure\UsersModule\Module;
12
use Itstructure\UsersModule\interfaces\{ModelInterface, ValidateComponentInterface};
13
14
/**
15
 * Class BaseController
16
 * Base controller class for the `users` module.
17
 *
18
 * @property Module $module
19
 * @property bool $viewCreated
20
 * @property array $additionFields
21
 * @property array $additionAttributes
22
 * @property string $urlPrefix Url prefix for redirect and view links.
23
 * @property ModelInterface $model
24
 * @property ActiveRecordInterface $searchModel
25
 * @property ValidateComponentInterface $validateComponent
26
 *
27
 * @package Itstructure\UsersModule\controllers
28
 */
29
abstract class BaseController extends Controller
30
{
31
    /**
32
     * Watch or not created record.
33
     *
34
     * @var bool
35
     */
36
    protected $viewCreated = false;
37
38
    /**
39
     * Addition fields for the template.
40
     *
41
     * @var array
42
     */
43
    protected $additionFields = [];
44
45
    /**
46
     * Addition attributes with values for the model.
47
     * [
48
     *    'key1' => 'value1',
49
     *    'key2' => 'value2',
50
     * ]
51
     *
52
     * @var array
53
     */
54
    protected $additionAttributes = [];
55
56
    /**
57
     * Url prefix for redirect and view links.
58
     * @var string
59
     */
60
    protected $urlPrefix = '';
61
62
    /**
63
     * Model object record.
64
     *
65
     * @var ModelInterface
66
     */
67
    private $model;
68
69
    /**
70
     * Search new model object.
71
     *
72
     * @var ActiveRecordInterface
73
     */
74
    private $searchModel;
75
76
    /**
77
     * Validate component.
78
     *
79
     * @var ValidateComponentInterface
80
     */
81
    private $validateComponent = null;
82
83
    /**
84
     * Returns the name of the base model.
85
     *
86
     * @return string
87
     */
88
    abstract protected function getModelName():string;
89
90
    /**
91
     * Returns the name of the model to search it.
92
     *
93
     * @return string
94
     */
95
    abstract protected function getSearchModelName():string;
96
97
    /**
98
     * @inheritdoc
99
     */
100
    public function behaviors()
101
    {
102
        return [
103
            'access' => [
104
                'class' => AccessControl::class,
105
                'rules' => [
106
                    [
107
                        'allow' => true,
108
                        'roles' => $this->module->accessRoles,
109
                    ],
110
                ],
111
            ],
112
            'verbs' => [
113
                'class' => VerbFilter::class,
114
                'actions' => [
115
                    'delete' => [
116
                        'POST',
117
                    ],
118
                ],
119
            ],
120
        ];
121
    }
122
123
    /**
124
     * Initializer.
125
     */
126
    public function init()
127
    {
128
        $this->view->params['user'] = Yii::$app->user->identity;
129
    }
130
131
    /**
132
     * @param \yii\base\Action $action
133
     * @return bool
134
     */
135
    public function beforeAction($action)
136
    {
137
        $this->view->params['urlPrefix'] = $this->urlPrefix;
138
139
        return parent::beforeAction($action);
140
    }
141
142
    /**
143
     * Give ability of configure view to the module class.
144
     *
145
     * @return \yii\base\View|\yii\web\View
146
     */
147
    public function getView()
148
    {
149
        if (method_exists($this->module, 'getView')) {
150
            return $this->module->getView();
151
        }
152
153
        return parent::getView();
154
    }
155
156
    /**
157
     * Set model.
158
     *
159
     * @param $model ModelInterface
160
     */
161
    public function setModel(ModelInterface $model): void
162
    {
163
        $this->model = $model;
0 ignored issues
show
Documentation Bug introduced by
It seems like $model of type object<Itstructure\Users...erfaces\ModelInterface> is incompatible with the declared type object<ModelInterface> of property $model.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
164
    }
165
166
    /**
167
     * Set search model.
168
     *
169
     * @param $model ActiveRecordInterface
170
     */
171
    public function setSearchModel(ActiveRecordInterface $model): void
172
    {
173
        $this->searchModel = $model;
174
    }
175
176
    /**
177
     * Set validate component for main model.
178
     *
179
     * @param $component ValidateComponentInterface
180
     */
181
    public function setValidateComponent(ValidateComponentInterface $component): void
182
    {
183
        $this->validateComponent = $component;
0 ignored issues
show
Documentation Bug introduced by
It seems like $component of type object<Itstructure\Users...dateComponentInterface> is incompatible with the declared type object<ValidateComponentInterface> of property $validateComponent.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
184
    }
185
186
    /**
187
     * Returns model.
188
     *
189
     * @return ModelInterface
190
     */
191
    public function getModel(): ModelInterface
192
    {
193
        return $this->model;
194
    }
195
196
    /**
197
     * Returns search model.
198
     *
199
     * @return ActiveRecordInterface
200
     */
201
    public function getSearchModel(): ActiveRecordInterface
202
    {
203
        return $this->searchModel;
204
    }
205
206
    /**
207
     * Get validate component for main model.
208
     *
209
     * @return ValidateComponentInterface
210
     */
211
    public function getValidateComponent(): ValidateComponentInterface
212
    {
213
        return $this->validateComponent;
214
    }
215
216
    /**
217
     * List of records.
218
     *
219
     * @return string
220
     */
221
    public function actionIndex()
222
    {
223
        $this->setSearchModel(
224
            $this->getNewSearchModel()
225
        );
226
227
        return $this->render('index',
228
            ArrayHelper::merge(
229
                [
230
                    'searchModel' => $this->searchModel,
231
                    'dataProvider' => $this->searchModel->search(Yii::$app->request->queryParams),
0 ignored issues
show
Bug introduced by
The method search() does not seem to exist on object<yii\db\ActiveRecordInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
232
                ],
233
                $this->getAdditionFields()
234
            )
235
        );
236
    }
237
238
    /**
239
     * Displays one model entry.
240
     *
241
     * @param int|string $id
242
     *
243
     * @return mixed
244
     */
245
    public function actionView($id)
246
    {
247
        return $this->render('view',
248
            ArrayHelper::merge(
249
                [
250
                    'model' => $this->findModel($id),
251
                ],
252
                $this->getAdditionFields()
253
            )
254
        );
255
    }
256
257
    /**
258
     * Creates a new model record.
259
     * If the result of creation is successful, there will be a redirect to the 'view' or 'index' page.
260
     *
261
     * @return string|\yii\web\Response
262
     */
263
    public function actionCreate()
264
    {
265
        $this->setModelByConditions();
266
267
        if (Yii::$app->request->isPost &&
268
            $this->model->load(Yii::$app->request->post()) &&
269
            $this->setAdditionAttributes() &&
270
            $this->model->save()) {
271
272
            if ($this->viewCreated) {
273
                $redirectParams = [
274
                    $this->urlPrefix.'view',
275
                    'id' => $this->model->getId(),
276
                ];
277
            } else {
278
                $redirectParams = [
279
                    $this->urlPrefix.'index',
280
                ];
281
            }
282
283
            return $this->redirect($redirectParams);
284
        }
285
286
        return $this->render('create',
287
            ArrayHelper::merge(
288
                [
289
                    'model' => $this->model,
290
                ],
291
                $this->getAdditionFields()
292
            )
293
        );
294
    }
295
296
    /**
297
     * Updates the current model entry.
298
     * If the result of creation is successful, there will be a redirect to the 'view' or 'index' page.
299
     *
300
     * @param int|string $id
301
     *
302
     * @return string|\yii\web\Response
303
     */
304
    public function actionUpdate($id)
305
    {
306
        $this->setModelByConditions($id);
307
308
        if (Yii::$app->request->isPost &&
309
            $this->model->load(Yii::$app->request->post()) &&
310
            $this->setAdditionAttributes() &&
311
            $this->model->save()) {
312
313
            return $this->redirect([
314
                $this->urlPrefix.'view',
315
                'id' => $this->model->getId(),
316
            ]);
317
        }
318
319
        return $this->render('update',
320
            ArrayHelper::merge(
321
                [
322
                    'model' => $this->model,
323
                ],
324
                $this->getAdditionFields()
325
            )
326
        );
327
    }
328
329
    /**
330
     * Deletes the current model entry.
331
     * If the result of the deletion is successful, there will be a redirect to the 'index' page.
332
     *
333
     * @param int|string $id
334
     *
335
     * @return \yii\web\Response
336
     *
337
     * @throws ConflictHttpException
338
     */
339
    public function actionDelete($id)
340
    {
341
        $model = $this->findModel($id);
342
343
        if ($model instanceof IdentityInterface && $id == Yii::$app->user->identity->getId()) {
344
            throw new ConflictHttpException('You can not delete yourself.');
345
        };
346
347
        $model->delete();
348
349
        return $this->redirect(['index']);
350
    }
351
352
    /**
353
     * Set addition attributes for model.
354
     *
355
     * @return bool
356
     */
357
    protected function setAdditionAttributes(): bool
358
    {
359
        $this->model->setAttributes($this->additionAttributes, false);
360
361
        return true;
362
    }
363
364
    /**
365
     * Get addition fields for the view template.
366
     * @return array
367
     */
368
    protected function getAdditionFields(): array
369
    {
370
        return $this->additionFields;
371
    }
372
373
    /**
374
     * Returns new object of main model.
375
     *
376
     * @return mixed
377
     */
378
    protected function getNewModel()
379
    {
380
        $modelName = $this->getModelName();
381
        return new $modelName;
382
    }
383
384
    /**
385
     * Returns new object of search main model.
386
     *
387
     * @return mixed
388
     */
389
    protected function getNewSearchModel()
390
    {
391
        $searchModelName = $this->getSearchModelName();
392
        return new $searchModelName;
393
    }
394
395
    /**
396
     * Find model record.
397
     * If the model is not found, a 404 HTTP exception will be displayed.
398
     *
399
     * @param int|string $key
400
     *
401
     *
402
     * @throws BadRequestHttpException
403
     * @throws UnknownMethodException
404
     * @throws NotFoundHttpException
405
     *
406
     * @return mixed
407
     */
408
    private function findModel($key)
409
    {
410
        if (null === $key){
411
            throw new BadRequestHttpException('Key parameter is not defined in findModel method.');
412
        }
413
414
        $modelObject = $this->getNewModel();
415
416 View Code Duplication
        if (!method_exists($modelObject, 'findOne')){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
417
            $class = (new\ReflectionClass($modelObject));
418
            throw new UnknownMethodException('Method findOne does not exists in ' . $class->getNamespaceName() . '\\' . $class->getShortName().' class.');
419
        }
420
421
        $result = call_user_func([
422
            $modelObject,
423
            'findOne',
424
        ], $key);
425
426
        if ($result !== null) {
427
            return $result;
428
        }
429
430
        throw new NotFoundHttpException('The requested page does not exist.');
431
    }
432
433
    /**
434
     * Returns an intermediate model for working with the main.
435
     *
436
     * @param int|string|null $key
437
     *
438
     * @return void
439
     */
440
    private function setModelByConditions($key = null): void
441
    {
442
        $model = null === $key ? $this->getNewModel() : $this->findModel($key);
443
444
        if (null === $this->validateComponent){
445
            $this->setModel($model);
446
        } else {
447
            $this->setModel(
448
                $this->validateComponent->setModel($model)
449
            );
450
        }
451
    }
452
}