1 | <?php |
||||||
2 | |||||||
3 | namespace Itstructure\AdminModule\models; |
||||||
4 | |||||||
5 | use yii\db\ActiveRecord as BaseActiveRecord; |
||||||
6 | use yii\base\Model; |
||||||
7 | use yii\helpers\ArrayHelper; |
||||||
8 | use Itstructure\AdminModule\interfaces\ModelInterface; |
||||||
9 | |||||||
10 | /** |
||||||
11 | * Class MultilanguageValidateModel |
||||||
12 | * General validation model together with multilingual fields. |
||||||
13 | * |
||||||
14 | * @property array $dynamicFields Dynamic fields from which the translated fields are formed. |
||||||
15 | * @property BaseActiveRecord|MultilanguageTrait $mainModel Basic data model. |
||||||
16 | * |
||||||
17 | * @package Itstructure\AdminModule\models |
||||||
18 | * |
||||||
19 | * @author Andrey Girnik <[email protected]> |
||||||
20 | */ |
||||||
21 | class MultilanguageValidateModel extends Model implements ModelInterface |
||||||
22 | { |
||||||
23 | /** |
||||||
24 | * Dynamic fields from which the translated fields are formed. |
||||||
25 | * |
||||||
26 | * @var array |
||||||
27 | */ |
||||||
28 | public $dynamicFields = []; |
||||||
29 | |||||||
30 | /** |
||||||
31 | * Basic data model. |
||||||
32 | * |
||||||
33 | * @var BaseActiveRecord|MultilanguageTrait |
||||||
34 | */ |
||||||
35 | private $mainModel; |
||||||
36 | |||||||
37 | /** |
||||||
38 | * Validation rules for all fields together with dynamic. |
||||||
39 | * |
||||||
40 | * @return array |
||||||
41 | */ |
||||||
42 | public function rules(): array |
||||||
43 | { |
||||||
44 | return ArrayHelper::merge( |
||||||
45 | $this->getDynamicValidationRules(), |
||||||
46 | $this->mainModel->rules() |
||||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
47 | ); |
||||||
48 | } |
||||||
49 | |||||||
50 | /** |
||||||
51 | * Scenarios. |
||||||
52 | * |
||||||
53 | * @return array |
||||||
54 | */ |
||||||
55 | public function scenarios(): array |
||||||
56 | { |
||||||
57 | return [ |
||||||
58 | ModelInterface::SCENARIO_CREATE => $this->attributes(), |
||||||
59 | ModelInterface::SCENARIO_UPDATE => $this->attributes(), |
||||||
60 | self::SCENARIO_DEFAULT => $this->attributes(), |
||||||
61 | ]; |
||||||
62 | } |
||||||
63 | |||||||
64 | /** |
||||||
65 | * Labels of all fields. |
||||||
66 | * |
||||||
67 | * @inheritdoc |
||||||
68 | */ |
||||||
69 | public function attributeLabels() |
||||||
70 | { |
||||||
71 | $dynamicAttributeLabels = []; |
||||||
72 | $staticAttributeLabels = []; |
||||||
73 | $translateAttributeLabels = []; |
||||||
74 | |||||||
75 | $translateModelName = $this->mainModel->getTranslateModelName(); |
||||||
76 | |||||||
77 | if (method_exists($translateModelName, 'attributeLabels')) { |
||||||
78 | /** @var Model $abstractTranslateModel */ |
||||||
79 | $abstractTranslateModel = new $translateModelName(); |
||||||
80 | $translateAttributeLabels = $abstractTranslateModel->attributeLabels(); |
||||||
81 | } |
||||||
82 | |||||||
83 | foreach ($this->dynamicFields as $fieldConditions) { |
||||||
84 | |||||||
85 | $fieldName = $fieldConditions['name']; |
||||||
86 | |||||||
87 | if (array_key_exists($fieldName, $translateAttributeLabels)) { |
||||||
88 | |||||||
89 | $staticAttributeLabels[$fieldName] = $translateAttributeLabels[$fieldName]; |
||||||
90 | |||||||
91 | foreach ($this->getShortLanguageList() as $language) { |
||||||
92 | $dynamicAttributeLabels[$fieldName.'_'.$language] = $translateAttributeLabels[$fieldName]; |
||||||
93 | } |
||||||
94 | } |
||||||
95 | } |
||||||
96 | |||||||
97 | return ArrayHelper::merge( |
||||||
98 | ArrayHelper::merge( |
||||||
99 | $dynamicAttributeLabels, |
||||||
100 | $staticAttributeLabels |
||||||
101 | ), |
||||||
102 | $this->mainModel->attributeLabels() |
||||||
0 ignored issues
–
show
It seems like
attributeLabels() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
103 | ); |
||||||
104 | } |
||||||
105 | |||||||
106 | /** |
||||||
107 | * Specifies the value of the field. |
||||||
108 | * |
||||||
109 | * @param string $name - name of field. |
||||||
110 | * @param mixed $value - value to be stored in field. |
||||||
111 | * |
||||||
112 | * @return void |
||||||
113 | */ |
||||||
114 | public function __set($name, $value) |
||||||
115 | { |
||||||
116 | $setter = 'set' . $name; |
||||||
117 | if (method_exists($this, $setter)) { |
||||||
118 | $this->$setter($value); |
||||||
119 | } else { |
||||||
120 | $this->{$name} = $value; |
||||||
121 | } |
||||||
122 | } |
||||||
123 | |||||||
124 | /** |
||||||
125 | * Gets the value of the field. |
||||||
126 | * |
||||||
127 | * @param string $name - field name. |
||||||
128 | * |
||||||
129 | * @return mixed |
||||||
130 | */ |
||||||
131 | public function __get($name) |
||||||
132 | { |
||||||
133 | $getter = 'get' . $name; |
||||||
134 | if (method_exists($this, $getter)) { |
||||||
135 | return $this->$getter(); |
||||||
136 | } |
||||||
137 | |||||||
138 | if ($this->mainModel->isNewRecord) { |
||||||
0 ignored issues
–
show
The property
isNewRecord does not exist on Itstructure\AdminModule\models\MultilanguageTrait . Since you implemented __get , consider adding a @property annotation.
Loading history...
|
|||||||
139 | return $this->{$name} ?? ''; |
||||||
140 | } else { |
||||||
141 | return $this->mainModel->{$name} ?? ''; |
||||||
142 | } |
||||||
143 | } |
||||||
144 | |||||||
145 | /** |
||||||
146 | * Setter for main model. |
||||||
147 | * |
||||||
148 | * @param BaseActiveRecord $mainModel |
||||||
149 | */ |
||||||
150 | public function setMainModel(BaseActiveRecord $mainModel) |
||||||
151 | { |
||||||
152 | $this->mainModel = $mainModel; |
||||||
153 | } |
||||||
154 | |||||||
155 | /** |
||||||
156 | * Getter for main model. |
||||||
157 | * |
||||||
158 | * @return mixed |
||||||
159 | */ |
||||||
160 | public function getMainModel() |
||||||
161 | { |
||||||
162 | return $this->mainModel; |
||||||
163 | } |
||||||
164 | |||||||
165 | /** |
||||||
166 | * Attributes along with dynamic and from the basic model. |
||||||
167 | * |
||||||
168 | * @return array |
||||||
169 | */ |
||||||
170 | public function attributes(): array |
||||||
171 | { |
||||||
172 | if (method_exists($this->mainModel, 'mainModelAttributes')) { |
||||||
173 | $mainModelAttributes = call_user_func([ |
||||||
174 | $this->mainModel, |
||||||
175 | 'mainModelAttributes' |
||||||
176 | ]); |
||||||
177 | } else { |
||||||
178 | $mainModelAttributes = $this->mainModel->attributes(); |
||||||
0 ignored issues
–
show
It seems like
attributes() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
179 | } |
||||||
180 | |||||||
181 | return ArrayHelper::merge( |
||||||
182 | $this->getDynamicAttributes(), |
||||||
183 | $mainModelAttributes |
||||||
184 | ); |
||||||
185 | } |
||||||
186 | |||||||
187 | /** |
||||||
188 | * Saves data in the main model. |
||||||
189 | * |
||||||
190 | * @return bool |
||||||
191 | */ |
||||||
192 | public function save(): bool |
||||||
193 | { |
||||||
194 | if ($this->mainModel->isNewRecord) { |
||||||
0 ignored issues
–
show
The property
isNewRecord does not exist on Itstructure\AdminModule\models\MultilanguageTrait . Since you implemented __get , consider adding a @property annotation.
Loading history...
|
|||||||
195 | $this->setScenario(ModelInterface::SCENARIO_CREATE); |
||||||
196 | } else { |
||||||
197 | $this->setScenario(ModelInterface::SCENARIO_UPDATE); |
||||||
198 | } |
||||||
199 | |||||||
200 | if (!$this->validate()){ |
||||||
201 | return false; |
||||||
202 | } |
||||||
203 | |||||||
204 | // Transferring attribute values from this model to the main. |
||||||
205 | foreach ($this->attributes() as $attribute) { |
||||||
206 | |||||||
207 | $this->mainModel->{$attribute} = $this->{$attribute}; |
||||||
208 | } |
||||||
209 | |||||||
210 | return $this->mainModel->save(); |
||||||
0 ignored issues
–
show
It seems like
save() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
211 | } |
||||||
212 | |||||||
213 | /** |
||||||
214 | * Returns the id of the current model. |
||||||
215 | * |
||||||
216 | * @return int |
||||||
217 | */ |
||||||
218 | public function getId() |
||||||
219 | { |
||||||
220 | return $this->mainModel->id; |
||||||
0 ignored issues
–
show
The property
id does not exist on Itstructure\AdminModule\models\MultilanguageTrait . Since you implemented __get , consider adding a @property annotation.
Loading history...
|
|||||||
221 | } |
||||||
222 | |||||||
223 | /** |
||||||
224 | * Returns an array of all multilanguage attributes. |
||||||
225 | * |
||||||
226 | * @return array |
||||||
227 | */ |
||||||
228 | private function getDynamicAttributes(): array |
||||||
229 | { |
||||||
230 | $languageList = $this->getShortLanguageList(); |
||||||
231 | $dynamicAttributes = []; |
||||||
232 | foreach ($languageList as $language) { |
||||||
233 | foreach ($this->dynamicFields as $fieldConditions) { |
||||||
234 | $dynamicAttributes[] = $fieldConditions['name'] . '_' . $language; |
||||||
235 | } |
||||||
236 | } |
||||||
237 | return array_values($dynamicAttributes); |
||||||
238 | } |
||||||
239 | |||||||
240 | /** |
||||||
241 | * Creates validation rules for dynamic fields for all languages. |
||||||
242 | * |
||||||
243 | * @return array |
||||||
244 | */ |
||||||
245 | private function getDynamicValidationRules(): array |
||||||
246 | { |
||||||
247 | $rules = []; |
||||||
248 | foreach ($this->getShortLanguageList() as $language) { |
||||||
249 | foreach ($this->dynamicFields as $fieldConditions) { |
||||||
250 | |||||||
251 | $fieldName = $fieldConditions['name']; |
||||||
252 | $fieldRules = isset($fieldConditions['rules']) ? $fieldConditions['rules'] : []; |
||||||
253 | |||||||
254 | foreach ($fieldRules as $fieldRule) { |
||||||
255 | |||||||
256 | if (in_array('required', $fieldRule) && $language != Language::getDefaultLanguage()->shortName) { |
||||||
257 | continue; |
||||||
258 | } |
||||||
259 | |||||||
260 | if (in_array('unique', $fieldRule)) { |
||||||
261 | $fieldRule = ArrayHelper::merge( |
||||||
262 | $fieldRule, |
||||||
263 | [ |
||||||
264 | 'skipOnError' => true, |
||||||
265 | 'targetClass' => $this->mainModel->getTranslateModelName(), |
||||||
266 | 'targetAttribute' => [$fieldName . '_' . $language => $fieldName], |
||||||
267 | |||||||
268 | 'filter' => $this->getScenario() == ModelInterface::SCENARIO_UPDATE ? |
||||||
269 | $this->mainModel->getKeyToMainModel().' != '.$this->id : '', |
||||||
0 ignored issues
–
show
The property
id does not exist on Itstructure\AdminModule\...tilanguageValidateModel . Since you implemented __get , consider adding a @property annotation.
Loading history...
|
|||||||
270 | |||||||
271 | 'message' => isset($fieldRule['message']) ? |
||||||
272 | $fieldRule['message'] : 'Record with such attribute "{attribute}" already exists' |
||||||
273 | ] |
||||||
274 | ); |
||||||
275 | } |
||||||
276 | |||||||
277 | $rules[] = ArrayHelper::merge( |
||||||
278 | [$fieldName . '_' . $language], |
||||||
279 | $fieldRule |
||||||
280 | ); |
||||||
281 | } |
||||||
282 | } |
||||||
283 | } |
||||||
284 | |||||||
285 | return $rules; |
||||||
286 | } |
||||||
287 | |||||||
288 | /** |
||||||
289 | * Returns the list of available languages in the short name format. |
||||||
290 | * |
||||||
291 | * @return array |
||||||
292 | */ |
||||||
293 | private function getShortLanguageList(): array |
||||||
294 | { |
||||||
295 | return Language::getShortLanguageList(); |
||||||
296 | } |
||||||
297 | } |
||||||
298 |