Issues (13)

src/CrudController.php (1 issue)

1
<?php
2
3
4
namespace carono\yii2crud;
5
6
7
use carono\yii2crud\actions\CreateAction;
8
use carono\yii2crud\actions\DeleteAction;
9
use carono\yii2crud\actions\DeleteBatch;
10
use carono\yii2crud\actions\IndexAction;
11
use carono\yii2crud\actions\UpdateAction;
12
use carono\yii2crud\actions\ViewAction;
13
use carono\yii2helpers\QueryHelper;
14
use Yii;
15
use yii\data\ActiveDataProvider;
16
use yii\data\BaseDataProvider;
17
use yii\db\ActiveQuery;
18
use yii\db\ActiveRecord;
19
use yii\filters\VerbFilter;
20
use yii\web\Controller;
21
use yii\web\NotFoundHttpException;
22
23
abstract class CrudController extends Controller
24
{
25
    public const SCENARIO_CREATE = 'create';
26
27
    /**
28
     * @var ActiveRecord
29
     */
30
    public $modelClass;
31
    /**
32
     * @var ActiveRecord
33
     */
34
    public $modelSearchClass;
35
    public $createClass;
36
    public $updateClass;
37
    public $viewClass;
38
39
    public $updateView = 'update';
40
    public $indexView = 'index';
41
    public $viewView = 'view';
42
    public $createView = 'create';
43
44
    public $breadcrumbsAppdend = true;
45
    public $breadcrumbsNamespace = 'app\breadcrumbs';
46
    public $breadcrumbsParam = 'breadcrumbs';
47
48
    protected $params = [];
49
50
    public $primaryKey = ['id'];
51
52
    const EVENT_BEFORE_CREATE = 'beforeCreate';
53
    const EVENT_AFTER_CREATE = 'afterCreate';
54
    const EVENT_ERROR_CREATE = 'errorCreate';
55
56
    const EVENT_BEFORE_UPDATE_LOAD = 'beforeUpdateLoad';
57
    const EVENT_AFTER_UPDATE_LOAD = 'afterUpdateLoad';
58
    const EVENT_AFTER_UPDATE = 'afterUpdate';
59
    const EVENT_ERROR_UPDATE = 'errorUpdate';
60
61
    /**
62
     * @param ActiveRecord|string $class
63
     * @return ActiveQuery
64
     */
65
    public function getModelQuery($class)
66
    {
67
        return $class::find();
68
    }
69
70
    /**
71
     * @param $id
72
     * @param null $class
73
     * @return ActiveRecord
74
     * @throws NotFoundHttpException
75
     */
76
    public function findModel($id, $class = null): ActiveRecord
77
    {
78
        /**
79
         * @var ActiveRecord $class
80
         */
81
        $class = $class ?? $this->modelClass;
82
        $query = $this->getModelQuery($class);
83
        foreach ($this->primaryKey as $key) {
84
            $query->andWhere([$key => $id[$key] ?? null]);
85
        }
86
        $query = $this->findModelCondition($query);
87
        if (($model = $query->one()) !== null) {
88
            return $model;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $model could return the type array which is incompatible with the type-hinted return yii\db\ActiveRecord. Consider adding an additional type-check to rule them out.
Loading history...
89
        }
90
91
        throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
92
    }
93
94
    /**
95
     * @param ActiveQuery $query
96
     * @return ActiveDataProvider
97
     */
98
    public function queryToDataProvider($query): ActiveDataProvider
99
    {
100
        /**
101
         * @var ActiveRecord $modelClass
102
         */
103
        $modelClass = $query->modelClass;
104
        $table = $modelClass::tableName();
105
        $options = [
106
            'sort' => [
107
                'defaultOrder' => [
108
                    current($modelClass::getDb()->getTableSchema($table)->primaryKey) => SORT_ASC
109
                ]
110
            ],
111
        ];
112
        return new ActiveDataProvider(array_merge(['query' => $query], $options));
113
    }
114
115
    public function render($view, $params = [])
116
    {
117
        if (\Yii::$app->request->isAjax) {
118
            return parent::renderAjax($view, $params);
119
        }
120
        if ($this->breadcrumbsAppdend) {
121
            Breadcrumbs::$crumbsNamespace = $this->breadcrumbsNamespace;
122
            \Yii::$app->view->params[$this->breadcrumbsParam] = Breadcrumbs::formCrumbs($this->action, $params);
123
        }
124
        return parent::render($view, $params);
125
    }
126
127
    /**
128
     * @inheritdoc
129
     */
130
    public function behaviors()
131
    {
132
        return array_merge(parent::behaviors(), [
133
            'verbs' => [
134
                'class' => VerbFilter::class,
135
                'actions' => [
136
                    'delete' => ['POST'],
137
                    'delete-batch' => ['POST']
138
                ],
139
            ],
140
        ]);
141
    }
142
143
    /**
144
     * @param ActiveQuery $query
145
     * @param BaseDataProvider $dataProvider
146
     * @param $searchModel
147
     */
148
    public function applySearch(ActiveQuery $query, BaseDataProvider $dataProvider, $searchModel): void
149
    {
150
        if (method_exists($searchModel, 'updateQuery')) {
151
            $searchModel->updateQuery($query);
152
        } else {
153
            QueryHelper::regular($searchModel, $query);
154
        }
155
        if (method_exists($searchModel, 'updateDataProvider')) {
156
            $searchModel->updateDataProvider($dataProvider);
157
        }
158
    }
159
160
    /**
161
     * @param ActiveQuery $query
162
     * @return ActiveQuery
163
     */
164
    public function findModelCondition($query): ActiveQuery
165
    {
166
        return $query;
167
    }
168
169
    /**
170
     * @param ActiveQuery $query
171
     * @return ActiveQuery
172
     */
173
    public function indexCondition($query): ActiveQuery
174
    {
175
        return $query;
176
    }
177
178
    /**
179
     * @param $params
180
     * @return array
181
     */
182
    public function indexParams($params): array
183
    {
184
        return $params;
185
    }
186
187
    /**
188
     * @param $model
189
     */
190
    public function beforeCreate($model): void
191
    {
192
    }
193
194
    /**
195
     * @param $model
196
     * @return array|string
197
     */
198
    public function createRedirect($model)
199
    {
200
        return ['index'];
201
    }
202
203
    /**
204
     * @param $model
205
     * @return array|string
206
     */
207
    public function updateRedirect($model)
208
    {
209
        return ['index'];
210
    }
211
212
    /**
213
     * @param $model
214
     * @return array|string
215
     */
216
    public function deleteRedirect($model)
217
    {
218
        return ['index'];
219
    }
220
221
    /**
222
     * @param $model
223
     * @return array|string
224
     */
225
    public function deleteBatchRedirect()
226
    {
227
        return ['index'];
228
    }
229
230
    /**
231
     * @return array
232
     */
233
    public function actions()
234
    {
235
        return [
236
            'update' => [
237
                'class' => UpdateAction::class,
238
                'view' => $this->updateView,
239
                'primaryKeyParam' => $this->primaryKey,
240
                'redirect' => function ($model) {
241
                    return $this->updateRedirect($model);
242
                }
243
            ],
244
            'index' => [
245
                'class' => IndexAction::class,
246
                'view' => $this->indexView,
247
                'modelClass' => $this->modelClass,
248
                'modelSearchClass' => $this->modelSearchClass,
249
                'query' => function ($class, $action) {
250
                    return $this->getModelQuery($action->modelClass);
251
                },
252
                'dataProvider' => function ($query, IndexAction $action) {
253
                    $searchModel = $action->getSearchModel();
254
                    $dataProvider = $this->queryToDataProvider($query);
255
                    $this->applySearch($query, $dataProvider, $searchModel);
256
                    return $dataProvider;
257
                },
258
                'condition' => function ($query, IndexAction $action) {
259
                    $this->indexCondition($query);
260
                },
261
                'renderParams' => function ($params) {
262
                    return $this->indexParams($params);
263
                }
264
            ],
265
            'view' => [
266
                'class' => ViewAction::class,
267
                'primaryKeyParam' => $this->primaryKey,
268
                'view' => $this->viewView
269
            ],
270
            'create' => [
271
                'class' => CreateAction::class,
272
                'view' => $this->createView
273
            ],
274
            'delete' => [
275
                'class' => DeleteAction::class,
276
                'primaryKeyParam' => $this->primaryKey,
277
            ],
278
            'delete-batch' => [
279
                'class' => DeleteBatch::class
280
            ]
281
        ];
282
    }
283
}