1 | <?php |
||||||
2 | /** |
||||||
3 | * Created by PhpStorm. |
||||||
4 | * User: floor12 |
||||||
5 | * Date: 31.12.2017 |
||||||
6 | * Time: 15:14 |
||||||
7 | */ |
||||||
8 | |||||||
9 | namespace floor12\files\components; |
||||||
10 | |||||||
11 | |||||||
12 | use floor12\files\models\File; |
||||||
13 | use Yii; |
||||||
14 | use yii\base\Behavior; |
||||||
15 | use yii\base\ErrorException; |
||||||
16 | use yii\db\ActiveRecord; |
||||||
17 | use yii\db\Expression; |
||||||
18 | use yii\validators\Validator; |
||||||
19 | |||||||
20 | class FileBehaviour extends Behavior |
||||||
21 | { |
||||||
22 | /** Массив для хранения файловых атрибутов и их параметров. |
||||||
23 | * Задается через Behaviors в моделе |
||||||
24 | * @var array |
||||||
25 | */ |
||||||
26 | public $attributes = []; |
||||||
27 | |||||||
28 | /** В этот массив помещаются id связанных файлов с текущей моделью для последующейго сохранения. |
||||||
29 | * @var array |
||||||
30 | */ |
||||||
31 | private $_values = []; |
||||||
32 | |||||||
33 | /** |
||||||
34 | * Вещаем сохранение данных на события. |
||||||
35 | */ |
||||||
36 | public function events() |
||||||
37 | { |
||||||
38 | return [ |
||||||
39 | ActiveRecord::EVENT_AFTER_INSERT => 'filesSave', |
||||||
40 | ActiveRecord::EVENT_AFTER_UPDATE => 'filesSave', |
||||||
41 | ActiveRecord::EVENT_AFTER_DELETE => 'filesDelete', |
||||||
42 | ActiveRecord::EVENT_BEFORE_VALIDATE => 'validateRequiredFields' |
||||||
43 | ]; |
||||||
44 | } |
||||||
45 | |||||||
46 | protected $cachedFiles = []; |
||||||
47 | |||||||
48 | |||||||
49 | /** |
||||||
50 | * Метод сохранения в базу связей с файлами. Вызывается после сохранения основной модели AR. |
||||||
51 | * @throws ErrorException |
||||||
52 | * @throws \yii\db\Exception |
||||||
53 | */ |
||||||
54 | |||||||
55 | public function filesSave() |
||||||
56 | { |
||||||
57 | $order = 0; |
||||||
58 | if ($this->_values) { |
||||||
0 ignored issues
–
show
|
|||||||
59 | |||||||
60 | foreach ($this->_values as $field => $ids) { |
||||||
61 | |||||||
62 | Yii::$app->db->createCommand()->update( |
||||||
63 | "{{%file}}", |
||||||
64 | ['object_id' => 0], |
||||||
65 | [ |
||||||
66 | 'class' => $this->owner->className(), |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() The method
className() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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. ![]() |
|||||||
67 | 'object_id' => $this->owner->id, |
||||||
68 | 'field' => $field, |
||||||
69 | ] |
||||||
70 | )->execute(); |
||||||
71 | |||||||
72 | if ($ids) foreach ($ids as $id) { |
||||||
73 | if (empty($id)) |
||||||
74 | continue; |
||||||
75 | $file = File::findOne($id); |
||||||
76 | if ($file) { |
||||||
77 | $file->object_id = $this->owner->id; |
||||||
78 | $file->ordering = $order++; |
||||||
79 | $file->save(); |
||||||
80 | if (!$file->save()) { |
||||||
81 | throw new ErrorException('Невозможно обновить объект File.'); |
||||||
82 | } |
||||||
83 | } |
||||||
84 | |||||||
85 | } |
||||||
86 | } |
||||||
87 | } |
||||||
88 | } |
||||||
89 | |||||||
90 | public function filesDelete() |
||||||
91 | { |
||||||
92 | File::deleteAll([ |
||||||
93 | 'class' => $this->owner->className(), |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
94 | 'object_id' => $this->owner->id, |
||||||
95 | ]); |
||||||
96 | } |
||||||
97 | |||||||
98 | public function validateRequiredFields() |
||||||
99 | { |
||||||
100 | foreach ($this->attributes as $attributeName => $params) { |
||||||
101 | $attributeIds = $this->getRealAttributeName($attributeName); |
||||||
102 | |||||||
103 | if ( |
||||||
104 | isset($params['required']) && |
||||||
105 | $params['required'] && |
||||||
106 | in_array($this->owner->scenario, $params['requiredOn']) && |
||||||
107 | !in_array($this->owner->scenario, $params['requiredExcept']) && |
||||||
108 | !isset($this->_values[$attributeIds][1]) |
||||||
109 | ) |
||||||
110 | $this->owner->addError($attributeName, $params['requiredMessage']); |
||||||
111 | } |
||||||
112 | } |
||||||
113 | |||||||
114 | /** |
||||||
115 | * Устанавливаем валидаторы. |
||||||
116 | * @param ActiveRecord $owner |
||||||
117 | */ |
||||||
118 | public |
||||||
119 | function attach($owner) |
||||||
120 | { |
||||||
121 | parent::attach($owner); |
||||||
122 | |||||||
123 | // Получаем валидаторы AR |
||||||
124 | $validators = $owner->validators; |
||||||
125 | |||||||
126 | // Пробегаемся по валидаторам и вычисляем, какие из них касаются наших файл-полей |
||||||
127 | if ($validators) |
||||||
128 | foreach ($validators as $key => $validator) { |
||||||
129 | |||||||
130 | // Сначала пробегаемся по файловым валидаторам |
||||||
131 | if ($validator::className() == 'yii\validators\FileValidator' || $validator::className() == 'floor12\files\components\ReformatValidator') { |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
132 | foreach ($this->attributes as $field => $params) { |
||||||
133 | |||||||
134 | if (is_string($params)) { |
||||||
135 | $field = $params; |
||||||
136 | $params = []; |
||||||
0 ignored issues
–
show
|
|||||||
137 | } |
||||||
138 | |||||||
139 | $index = array_search($field, $validator->attributes); |
||||||
0 ignored issues
–
show
It seems like
$validator->attributes can also be of type string ; however, parameter $haystack of array_search() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
140 | if ($index !== false) { |
||||||
141 | $this->attributes[$field]['validator'][$validator::className()] = $validator; |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
142 | unset($validator->attributes[$index]); |
||||||
143 | } |
||||||
144 | } |
||||||
145 | } |
||||||
146 | |||||||
147 | |||||||
148 | if ($validator::className() == 'yii\validators\RequiredValidator') { |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
149 | foreach ($this->attributes as $field => $params) { |
||||||
150 | |||||||
151 | if (is_string($params)) { |
||||||
152 | $field = $params; |
||||||
153 | $params = []; |
||||||
154 | } |
||||||
155 | |||||||
156 | $index = array_search($field, $validator->attributes); |
||||||
157 | if ($index !== false) { |
||||||
158 | unset($validator->attributes[$index]); |
||||||
159 | $this->attributes[$field]['required'] = true; |
||||||
160 | $this->attributes[$field]['requiredExcept'] = $validator->except; |
||||||
161 | $this->attributes[$field]['requiredOn'] = sizeof($validator->on) ? $validator->on : [ActiveRecord::SCENARIO_DEFAULT]; |
||||||
0 ignored issues
–
show
It seems like
$validator->on can also be of type string ; however, parameter $value of sizeof() does only seem to accept Countable|array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
162 | $this->attributes[$field]['requiredMessage'] = str_replace("{attribute}", $this->owner->getAttributeLabel($field), $validator->message); |
||||||
163 | } |
||||||
164 | } |
||||||
165 | } |
||||||
166 | |||||||
167 | |||||||
168 | } |
||||||
169 | |||||||
170 | // Добавляем дефолтный валидатор для прилетающих айдишников |
||||||
171 | if ($this->attributes) foreach ($this->attributes as $fieldName => $fieldParams) { |
||||||
0 ignored issues
–
show
The expression
$this->attributes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
172 | $validator = Validator::createValidator('safe', $owner, ["{$fieldName}_ids"]); |
||||||
173 | $validators->append($validator); |
||||||
174 | } |
||||||
175 | } |
||||||
176 | |||||||
177 | |||||||
178 | /** |
||||||
179 | * @inheritdoc |
||||||
180 | */ |
||||||
181 | public function canGetProperty($name, $checkVars = true) |
||||||
182 | { |
||||||
183 | return array_key_exists($name, $this->attributes) ? |
||||||
184 | true : parent::canGetProperty($name, $checkVars); |
||||||
185 | } |
||||||
186 | |||||||
187 | |||||||
188 | /** |
||||||
189 | * @inheritdoc |
||||||
190 | */ |
||||||
191 | public function canSetProperty($name, $checkVars = true) |
||||||
192 | { |
||||||
193 | if (array_key_exists($this->getRealAttributeName($name), $this->attributes)) |
||||||
194 | return true; |
||||||
195 | |||||||
196 | return parent::canSetProperty($name, $checkVars = true); |
||||||
197 | } |
||||||
198 | |||||||
199 | |||||||
200 | /** |
||||||
201 | * @inheritdoc |
||||||
202 | */ |
||||||
203 | public function __get($att_name) |
||||||
204 | { |
||||||
205 | if (isset($this->_values[$att_name])) { |
||||||
206 | unset($this->_values[$att_name][0]); |
||||||
207 | if (sizeof($this->_values[$att_name])) |
||||||
208 | return array_map(function ($fileId) { |
||||||
209 | return File::findOne($fileId); |
||||||
210 | }, $this->_values[$att_name]); |
||||||
211 | } else { |
||||||
212 | if (!isset($this->cachedFiles[$att_name])) { |
||||||
213 | if ( |
||||||
214 | isset($this->attributes[$att_name]['validator']) && |
||||||
215 | isset($this->attributes[$att_name]['validator']['yii\validators\FileValidator']) && |
||||||
216 | $this->attributes[$att_name]['validator']['yii\validators\FileValidator']->maxFiles > 1 |
||||||
217 | ) |
||||||
218 | $this->cachedFiles[$att_name] = File::find() |
||||||
219 | ->where( |
||||||
220 | [ |
||||||
221 | 'object_id' => $this->owner->id, |
||||||
222 | 'field' => $att_name, |
||||||
223 | 'class' => $this->owner->className() |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
224 | ]) |
||||||
225 | ->orderBy('ordering ASC') |
||||||
226 | ->all(); |
||||||
227 | else { |
||||||
228 | $this->cachedFiles[$att_name] = File::find() |
||||||
229 | ->where( |
||||||
230 | [ |
||||||
231 | 'object_id' => $this->owner->id, |
||||||
232 | 'field' => $att_name, |
||||||
233 | 'class' => $this->owner->className() |
||||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
234 | ]) |
||||||
235 | ->orderBy('ordering ASC') |
||||||
236 | ->one(); |
||||||
237 | } |
||||||
238 | } |
||||||
239 | return $this->cachedFiles[$att_name]; |
||||||
240 | } |
||||||
241 | } |
||||||
242 | |||||||
243 | |||||||
244 | /** |
||||||
245 | * @inheritdoc |
||||||
246 | */ |
||||||
247 | public |
||||||
248 | function __set($name, $value) |
||||||
249 | { |
||||||
250 | $attribute = $this->getRealAttributeName($name); |
||||||
251 | |||||||
252 | if (array_key_exists($attribute, $this->attributes)) |
||||||
253 | $this->_values[$attribute] = $value; |
||||||
254 | } |
||||||
255 | |||||||
256 | |||||||
257 | /** Отбрасываем постфикс _ids |
||||||
258 | * @param $attribute string |
||||||
259 | * @return string |
||||||
260 | */ |
||||||
261 | private |
||||||
262 | function getRealAttributeName($attribute) |
||||||
263 | { |
||||||
264 | return str_replace("_ids", "", $attribute); |
||||||
265 | } |
||||||
266 | } |
||||||
267 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.