Action::getUniqueId()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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