Completed
Push — master ( f68af4...4d981c )
by Andrii
11:40
created

Action::thoroughTrigger()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * HiPanel core package
4
 *
5
 * @link      https://hipanel.com/
6
 * @package   hipanel-core
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2014-2019, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\actions;
12
13
use Closure;
14
use hipanel\base\Controller;
15
use hiqdev\hiart\Collection;
16
use hiqdev\hiart\ResponseErrorException;
17
use Yii;
18
use yii\base\InvalidCallException;
19
use yii\helpers\ArrayHelper;
20
21
/**
22
 * HiPanel basic action.
23
 * Holds scenario and collection. Displays flash.
24
 *
25
 * @property Collection collection
26
 */
27
class Action extends \yii\base\Action
28
{
29
    const EVENT_BEFORE_RUN = 'beforeRun';
30
    const EVENT_BEFORE_SAVE = 'beforeSave';
31
    const EVENT_BEFORE_LOAD = 'beforeLoad';
32
    const EVENT_BEFORE_PERFORM = 'beforePerform';
33
    const EVENT_AFTER_PERFORM = 'afterPerform';
34
35
    /**
36
     * @var Controller the controller that owns this action
37
     */
38
    public $controller;
39
40
    /**
41
     * @var Action|SwitchAction parent called action
42
     */
43
    public $parent;
44
45
    /**
46
     * @var string scenario to be used when save
47
     */
48
    public $_scenario;
49
50
    /**
51
     * Perform query options.
52
     * @var array
53
     */
54
    public $queryOptions = [];
55
56
    /**
57
     * @var array|Closure additional data passed when rendering
58
     */
59
    public $data = [];
60
61
    /**
62
     * @param string $scenario
63
     */
64
    public function setScenario($scenario)
65
    {
66
        $this->_scenario = $scenario;
67
    }
68
69
    /**
70
     * @return string
71
     */
72
    public function getScenario()
73
    {
74
        return $this->_scenario ?: ($this->parent ? $this->parent->getScenario() : $this->id);
75
    }
76
77
    /**
78
     * @var Collection|array the options that will be used to create the collection.
79
     * Stores collection after creating
80
     */
81
    protected $_collection;
82
83
    /**
84
     * Setter for the collection.
85
     *
86
     * @param array $collection config for the collection
87
     */
88
    public function setCollection($collection)
89
    {
90
        $this->_collection = $collection;
91
    }
92
93
    /**
94
     * Gets the instance of the collection.
95
     *
96
     * @return Collection
97
     */
98
    public function getCollection()
99
    {
100
        if ($this->parent) {
101
            return $this->parent->getCollection();
102
        }
103
104
        if (!is_object($this->_collection)) {
105
            $action = $this->controller->action;
106
            if ($action instanceof self) {
107
                $scenario = $action->getScenario();
108
            } else {
109
                $scenario = $action->id;
110
            }
111
112
            $this->_collection = Yii::createObject(ArrayHelper::merge([
113
                'class' => Collection::class,
114
                'model' => $this->controller->newModel(['scenario' => $scenario]),
115
                'scenario' => $scenario,
116
                'queryOptions' => $this->queryOptions,
117
            ], (array) $this->_collection));
118
        }
119
120
        return $this->_collection;
121
    }
122
123
    /**
124
     * @var callable the custom callback to load data into the collection. Gets [[$this]] as the only argument
125
     * Should call `$this->collection->load()`
126
     */
127
    public $collectionLoader;
128
129
    protected function beforeRun()
130
    {
131
        $this->thoroughTrigger(static::EVENT_BEFORE_RUN);
132
133
        return parent::beforeRun();
134
    }
135
136
    public function beforeLoad()
137
    {
138
        $this->thoroughTrigger(static::EVENT_BEFORE_LOAD);
139
    }
140
141
    /**
142
     * Loads data to the [[collection]].
143
     *
144
     * @param array $data
145
     */
146
    public function loadCollection($data = null)
147
    {
148
        $this->beforeLoad();
149
150
        if ($this->collectionLoader instanceof Closure) {
151
            call_user_func($this->collectionLoader, $this, $data);
152
        } else {
153
            $this->collection->load($data);
154
        }
155
    }
156
157
    public function beforeSave()
158
    {
159
        $this->thoroughTrigger(static::EVENT_BEFORE_SAVE);
160
    }
161
162
    /**
163
     * Saves stored [[collection]].
164
     *
165
     * @return bool
166
     */
167
    public function saveCollection()
168
    {
169
        $this->beforeSave();
170
171
        return $this->collection->save();
172
    }
173
174
    public function beforePerform()
175
    {
176
        $this->thoroughTrigger(static::EVENT_BEFORE_PERFORM);
177
    }
178
179
    protected function thoroughTrigger($event)
180
    {
181
        if (isset($this->parent)) {
182
            $this->parent->trigger($event);
183
        }
184
185
        $this->trigger($event);
186
    }
187
188
    public function afterPerform()
189
    {
190
        $this->thoroughTrigger(static::EVENT_AFTER_PERFORM);
191
    }
192
193
    /**
194
     * Performs action.
195
     *
196
     * @return boolean|string Whether save is success
197
     *  - boolean true or sting - an error
198
     *  - false - no errors
199
     */
200
    public function perform()
201
    {
202
        $this->beforePerform();
203
204
        $this->loadCollection();
205
206
        try {
207
            $error = !$this->saveCollection();
208
209
            if ($error === true && $this->collection->hasErrors()) {
210
                $error = $this->collection->getFirstError();
211
            }
212
        } catch (ResponseErrorException $e) {
213
            $error = $e->getMessage();
214
        } catch (InvalidCallException $e) {
215
            $error = $e->getMessage();
216
        }
217
218
        $this->afterPerform();
219
220
        return $error;
221
    }
222
223
    /**
224
     * @return \hiqdev\hiart\ActiveRecord
225
     */
226
    public function getModel()
227
    {
228
        return $this->parent ? $this->parent->getModel() : $this->getCollection()->first;
229
    }
230
231
    /**
232
     * Return the model class name.
233
     *
234
     * @return string
235
     */
236
    public function getModelClass()
237
    {
238
        if (isset($this->parent)) {
239
            return $this->parent->getModelClass();
240
        }
241
242
        if (isset($this->getCollection()->first)) {
243
            return $this->getCollection()->first->class;
244
        }
245
246
        return get_class($this->getCollection()->getModel());
247
    }
248
249
    /**
250
     * @return \hiqdev\hiart\ActiveRecord[]
251
     */
252
    public function getModels()
253
    {
254
        return $this->parent ? $this->parent->getModels() : $this->getCollection()->models;
255
    }
256
257
    /**
258
     * Prepares additional data for render.
259
     *
260
     * @param $data array Additional data, prepared by other classes. Optional.
261
     * @return array
262
     */
263
    public function prepareData($data = [])
264
    {
265
        return (array) ($this->data instanceof Closure ? call_user_func($this->data, $this, $data) : $this->data);
266
    }
267
268
    /**
269
     * {@inheritdoc}
270
     */
271
    public function getUniqueId()
272
    {
273
        return $this->parent !== null ? $this->parent->getUniqueId() : $this->controller->getUniqueId() . '/' . $this->id;
274
    }
275
276
    /**
277
     * Returns text for flash messages, search in parent actions.
278
     * Used by [[addFlash()]].
279
     *
280
     * @param $type string
281
     * @return string
282
     */
283
    public function getFlashText($type)
284
    {
285
        if ($this->{$type}) {
286
            return $this->{$type};
287
        } elseif ($this->parent) {
288
            return $this->parent->getFlashText($type);
289
        }
290
291
        return $type;
292
    }
293
294
    /**
295
     * Adds flash message.
296
     *
297
     * @param string $type the type of flash
298
     * @param string $error the text of error
299
     */
300
    public function addFlash($type, $error = null)
301
    {
302
        if ($type === 'error' && is_string($error) && !empty($error)) {
303
            $text = Yii::t('hipanel', $error);
304
        } else {
305
            $text = $this->getFlashText($type);
306
        }
307
308
        if ($type instanceof Closure) {
309
            $text = call_user_func($text, $text, $this);
310
        }
311
312
        Yii::$app->session->addFlash($type, [
313
            'text' => $text,
314
        ]);
315
    }
316
}
317