Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Model often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Model, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class Model { |
||
12 | |||
13 | public static $loaded = []; |
||
14 | |||
15 | /** |
||
16 | * Object storage type |
||
17 | * |
||
18 | * @var array |
||
19 | */ |
||
20 | public static $storage = ['type' => 'db']; |
||
21 | |||
22 | /** |
||
23 | * Object name |
||
24 | * |
||
25 | * @var string |
||
26 | */ |
||
27 | public static $objectName = ''; |
||
28 | |||
29 | /** |
||
30 | * App type for separate data storage |
||
31 | * |
||
32 | * @var string |
||
33 | */ |
||
34 | public $appType = 'app'; |
||
35 | |||
36 | /** |
||
37 | * Object current params |
||
38 | * |
||
39 | * @var array |
||
40 | */ |
||
41 | public $_params = []; |
||
42 | |||
43 | /** |
||
44 | * List of changed params in current instance |
||
45 | * |
||
46 | * @var array |
||
47 | */ |
||
48 | public $_changedParams = []; |
||
49 | |||
50 | /** |
||
51 | * Loaded relations |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | public $loadedRelations = []; |
||
56 | |||
57 | /** |
||
58 | * Model name where this model uses as category |
||
59 | * |
||
60 | * @var string |
||
61 | */ |
||
62 | public static $treeCategory = ''; |
||
63 | |||
64 | /** |
||
65 | * Model name who uses as category in this model |
||
66 | * |
||
67 | * @var string |
||
68 | */ |
||
69 | public static $categoryModel = ''; |
||
70 | |||
71 | /** |
||
72 | * Col labels |
||
73 | * |
||
74 | * @var array |
||
75 | */ |
||
76 | public static $labels = []; |
||
77 | |||
78 | /** |
||
79 | * Model forms |
||
80 | * |
||
81 | * @var array |
||
82 | */ |
||
83 | public static $forms = []; |
||
84 | |||
85 | /** |
||
86 | * Model cols |
||
87 | * |
||
88 | * @var array |
||
89 | */ |
||
90 | public static $cols = []; |
||
91 | |||
92 | /** |
||
93 | * Options group for display inforamtion from model |
||
94 | * |
||
95 | * @var array |
||
96 | */ |
||
97 | public static $view = []; |
||
98 | |||
99 | /** |
||
100 | * List of relations need loaded with item |
||
101 | * |
||
102 | * @var array |
||
103 | */ |
||
104 | public static $needJoin = []; |
||
105 | |||
106 | /** |
||
107 | * List of joins who need to laod |
||
108 | * |
||
109 | * @var array |
||
110 | */ |
||
111 | public static $relJoins = []; |
||
112 | |||
113 | /** |
||
114 | * Set params when model create |
||
115 | * |
||
116 | 4 | * @param array $params |
|
117 | 4 | */ |
|
118 | 4 | public function __construct($params = []) { |
|
119 | $this->setParams($params); |
||
120 | } |
||
121 | |||
122 | public static $logging = true; |
||
123 | |||
124 | /** |
||
125 | * return object name |
||
126 | * |
||
127 | * @return string |
||
128 | */ |
||
129 | public static function objectName() { |
||
130 | return static::$objectName; |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * Retrn col value with col params and relations path |
||
135 | * |
||
136 | * @param Model $object |
||
137 | * @param string $valuePath |
||
138 | * @param boolean $convert |
||
139 | * @param boolean $manageHref |
||
140 | * @return string |
||
141 | */ |
||
142 | public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) { |
||
143 | if (is_array($object)) { |
||
144 | $object = array_shift($object); |
||
145 | } |
||
146 | if (strpos($valuePath, ':')) { |
||
147 | $rel = substr($valuePath, 0, strpos($valuePath, ':')); |
||
148 | $param = substr($valuePath, strpos($valuePath, ':') + 1); |
||
149 | if (!$object->$rel) { |
||
150 | $modelName = get_class($object); |
||
151 | $relations = $modelName::relations(); |
||
152 | if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') { |
||
153 | return $object->{$relations[$rel]['col']}; |
||
154 | } |
||
155 | return 0; |
||
156 | } |
||
157 | if (strpos($valuePath, ':')) { |
||
158 | return self::getColValue($object->$rel, $param, $convert, $manageHref); |
||
159 | } else { |
||
160 | return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param; |
||
161 | } |
||
162 | } else { |
||
163 | return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath; |
||
164 | } |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Retrun value for view |
||
169 | * |
||
170 | * @param Model $item |
||
171 | * @param string $colName |
||
172 | * @param boolean $manageHref |
||
173 | * @param array $params |
||
|
|||
174 | * @return string |
||
175 | */ |
||
176 | public static function resloveTypeValue($item, $colName, $manageHref = false, $colInfo = []) { |
||
177 | $modelName = get_class($item); |
||
178 | if (!$colInfo) { |
||
179 | $colInfo = $modelName::getColInfo($colName); |
||
180 | } |
||
181 | $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string'; |
||
182 | $value = ''; |
||
183 | switch ($type) { |
||
184 | case 'autocomplete': |
||
185 | $options = $colInfo['colParams']['options']; |
||
186 | View Code Duplication | if (isset($options['snippet']) && is_string($options['snippet'])) { |
|
187 | $snippets = \App::$cur->Ui->getSnippets('autocomplete'); |
||
188 | if (isset($snippets[$options['snippet']])) { |
||
189 | $value = $snippets[$options['snippet']]['getValueText']($item->$colName, $options['snippetParams']); |
||
190 | } |
||
191 | } |
||
192 | break; |
||
193 | case 'select': |
||
194 | switch ($colInfo['colParams']['source']) { |
||
195 | case 'model': |
||
196 | $sourceValue = ''; |
||
197 | if ($item->$colName) { |
||
198 | $sourceValue = $colInfo['colParams']['model']::get($item->$colName); |
||
199 | } |
||
200 | $value = $sourceValue ? $sourceValue->name() : 'Не задано'; |
||
201 | break; |
||
202 | case 'array': |
||
203 | $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано'; |
||
204 | if (is_array($value) && $value['text']) { |
||
205 | $value = $value['text']; |
||
206 | } |
||
207 | break; |
||
208 | case 'bool': |
||
209 | return $item->$colName ? 'Да' : 'Нет'; |
||
210 | case 'method': |
||
211 | View Code Duplication | if (!empty($colInfo['colParams']['params'])) { |
|
212 | $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']); |
||
213 | } else { |
||
214 | $values = \App::$cur->{$colInfo['colParams']['module']}->$colInfo['colParams']['method'](); |
||
215 | } |
||
216 | $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано'; |
||
217 | break; |
||
218 | case 'void': |
||
219 | if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') { |
||
220 | return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]); |
||
221 | } |
||
222 | break; |
||
223 | case 'relation': |
||
224 | if (strpos($colInfo['colParams']['relation'], ':')) { |
||
225 | $relationPath = explode(':', $colInfo['colParams']['relation']); |
||
226 | $relationName = array_pop($relationPath); |
||
227 | $curItem = $item; |
||
228 | foreach ($relationPath as $path) { |
||
229 | $curItem = $curItem->$path; |
||
230 | } |
||
231 | $itemModel = get_class($curItem); |
||
232 | $relation = $itemModel::getRelation($relationName); |
||
233 | $relModel = $relation['model']; |
||
234 | } else { |
||
235 | $itemModel = get_class($item); |
||
236 | $relation = $itemModel::getRelation($colInfo['colParams']['relation']); |
||
237 | $relModel = $relation['model']; |
||
238 | } |
||
239 | $relValue = $relModel::get($item->$colName); |
||
240 | $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel; |
||
241 | if ($manageHref) { |
||
242 | $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано'; |
||
243 | } else { |
||
244 | $value = $relValue ? $relValue->name() : 'Не задано'; |
||
245 | } |
||
246 | break; |
||
247 | } |
||
248 | break; |
||
249 | case 'image': |
||
250 | $file = Files\File::get($item->$colName); |
||
251 | if ($file) { |
||
252 | $photoId = Tools::randomString(); |
||
253 | $value = '<a href = "' . $file->path . '" id="' . $photoId . '" rel="fgall[allimg]"><img src="' . $file->path . '?resize=60x120" /></a>'; |
||
254 | $value .= '<script>inji.onLoad(function(){$("[rel]").fancybox();});</script>'; |
||
255 | } else { |
||
256 | $value = '<img src="/static/system/images/no-image.png?resize=60x120" />'; |
||
257 | } |
||
258 | break; |
||
259 | case 'file': |
||
260 | $file = Files\File::get($item->$colName); |
||
261 | if ($file) { |
||
262 | $value = '<a href="' . $file->path . '">' . $file->name . '.' . $file->type->ext . '</a>'; |
||
263 | } else { |
||
264 | $value = 'Файл не загружен'; |
||
265 | } |
||
266 | break; |
||
267 | case 'bool': |
||
268 | $value = $item->$colName ? 'Да' : 'Нет'; |
||
269 | break; |
||
270 | case 'void': |
||
271 | if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') { |
||
272 | return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']); |
||
273 | } |
||
274 | break; |
||
275 | case 'map': |
||
276 | if ($item->$colName && json_decode($item->$colName, true)) { |
||
277 | $addres = json_decode($item->$colName, true); |
||
278 | $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng']; |
||
279 | \App::$cur->libs->loadLib('yandexMap'); |
||
280 | ob_start(); |
||
281 | $uid = Tools::randomString(); |
||
282 | ?> |
||
283 | <div id='map<?= $uid; ?>_container' style="display:none;"> |
||
284 | <script>/* |
||
285 | <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div> |
||
286 | <script> |
||
287 | var myMap<?= $uid; ?>; |
||
288 | var myMap<?= $uid; ?>CurPin; |
||
289 | inji.onLoad(function () { |
||
290 | ymaps.ready(init<?= $uid; ?>); |
||
291 | function init<?= $uid; ?>() { |
||
292 | var myPlacemark; |
||
293 | myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", { |
||
294 | center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"], |
||
295 | zoom: 13 |
||
296 | }); |
||
297 | myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"]; |
||
298 | myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords, |
||
299 | {iconContent: "<?= $addres['address']; ?>"}, |
||
300 | {preset: 'islands#greenStretchyIcon'} |
||
301 | ); |
||
302 | myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0); |
||
303 | } |
||
304 | window['init<?= $uid; ?>'] = init<?= $uid; ?>; |
||
305 | }); |
||
306 | */</script> |
||
307 | </div> |
||
308 | <?php |
||
309 | $content = ob_get_contents(); |
||
310 | ob_end_clean(); |
||
311 | $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");'; |
||
312 | $onclick .= 'return false;'; |
||
313 | $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>"; |
||
314 | $value .= $content; |
||
315 | } else { |
||
316 | $value = 'Местоположение не заданно'; |
||
317 | } |
||
318 | |||
319 | break; |
||
320 | case 'dynamicType': |
||
321 | switch ($colInfo['colParams']['typeSource']) { |
||
322 | case 'selfMethod': |
||
323 | $type = $item->{$colInfo['colParams']['selfMethod']}(); |
||
324 | if (is_array($type)) { |
||
325 | $value = static::resloveTypeValue($item, $colName, $manageHref, ['colParams' => $type]); |
||
326 | } else { |
||
327 | $value = static::resloveTypeValue($item, $colName, $manageHref, ['colParams' => ['type' => $type]]); |
||
328 | } |
||
329 | break; |
||
330 | } |
||
331 | break; |
||
332 | default: |
||
333 | $value = $item->$colName; |
||
334 | } |
||
335 | return $value; |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * Fix col prefix |
||
340 | * |
||
341 | * @param mixed $array |
||
342 | * @param string $searchtype |
||
343 | * @param string $rootModel |
||
344 | * @return null |
||
345 | */ |
||
346 | public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') { |
||
347 | if (!$rootModel) { |
||
348 | $rootModel = get_called_class(); |
||
349 | } |
||
350 | $cols = static::cols(); |
||
351 | if (!$array) { |
||
352 | return; |
||
353 | } |
||
354 | if (!is_array($array)) { |
||
355 | View Code Duplication | if (!isset($cols[static::colPrefix() . $array]) && isset(static::$cols[$array])) { |
|
356 | static::createCol($array); |
||
357 | $cols = static::cols(); |
||
358 | } |
||
359 | if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) { |
||
360 | $array = static::colPrefix() . $array; |
||
361 | } else { |
||
362 | static::checkForJoin($array, $rootModel); |
||
363 | } |
||
364 | return; |
||
365 | } |
||
366 | switch ($searchtype) { |
||
367 | case 'key': |
||
368 | foreach ($array as $key => $item) { |
||
369 | View Code Duplication | if (!isset($cols[static::colPrefix() . $key]) && isset(static::$cols[$key])) { |
|
370 | static::createCol($key); |
||
371 | $cols = static::cols(true); |
||
372 | } |
||
373 | if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) { |
||
374 | $array[static::colPrefix() . $key] = $item; |
||
375 | unset($array[$key]); |
||
376 | $key = static::colPrefix() . $key; |
||
377 | } |
||
378 | if (is_array($array[$key])) { |
||
379 | static::fixPrefix($array[$key], 'key', $rootModel); |
||
380 | } else { |
||
381 | static::checkForJoin($key, $rootModel); |
||
382 | 4 | } |
|
383 | 4 | } |
|
384 | 4 | break; |
|
385 | 4 | case 'first': |
|
386 | 4 | if (isset($array[0]) && is_string($array[0])) { |
|
387 | 4 | if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) { |
|
388 | static::createCol($array[0]); |
||
389 | $cols = static::cols(); |
||
390 | 4 | } |
|
391 | 4 | View Code Duplication | if (!isset($cols[$array[0]]) && isset($cols[static::colPrefix() . $array[0]])) { |
392 | 2 | $array[0] = static::colPrefix() . $array[0]; |
|
393 | 2 | } else { |
|
394 | 2 | static::checkForJoin($array[0], $rootModel); |
|
395 | 4 | } |
|
396 | 4 | } elseif (isset($array[0]) && is_array($array[0])) { |
|
397 | 4 | foreach ($array as &$item) { |
|
398 | 4 | static::fixPrefix($item, 'first', $rootModel); |
|
399 | } |
||
400 | 4 | } |
|
401 | break; |
||
402 | } |
||
403 | 1 | } |
|
404 | |||
405 | /** |
||
406 | * @param boolean $new |
||
407 | */ |
||
408 | public function logChanges($new) { |
||
409 | if (!App::$cur->db->connect || !App::$cur->dashboard) { |
||
410 | return false; |
||
411 | } |
||
412 | $class = get_class($this); |
||
413 | if (!Model::$logging || !$class::$logging) { |
||
414 | return false; |
||
415 | } |
||
416 | $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0; |
||
417 | if (!$new && !empty($this->_changedParams)) { |
||
418 | $activity = new Dashboard\Activity([ |
||
419 | 'user_id' => $user_id, |
||
420 | 'module' => substr($class, 0, strpos($class, '\\')), |
||
421 | 1 | 'model' => $class, |
|
422 | 1 | 'item_id' => $this->pk(), |
|
423 | 1 | 'type' => 'changes' |
|
424 | ]); |
||
425 | $changes_text = []; |
||
426 | foreach ($this->_changedParams as $fullColName => $oldValue) { |
||
427 | 1 | $colName = substr($fullColName, strlen($class::colPrefix())); |
|
428 | 1 | View Code Duplication | if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) { |
429 | 1 | continue; |
|
430 | } |
||
431 | $oldValueText = $oldValue; |
||
432 | 1 | if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') { |
|
433 | 1 | switch ($class::$cols[$colName]['source']) { |
|
434 | 1 | case 'array': |
|
435 | 1 | $oldValueText = isset($class::$cols[$colName]['sourceArray'][$oldValue]) ? $class::$cols[$colName]['sourceArray'][$oldValue] : $oldValue; |
|
436 | 1 | break; |
|
437 | 1 | View Code Duplication | case 'relation': |
438 | $relation = $class::getRelation($class::$cols[$colName]['relation']); |
||
439 | 1 | $relModel = $relation['model']; |
|
440 | $rel = $relModel::get($oldValue); |
||
441 | if ($rel) { |
||
442 | $oldValueText = $rel->name(); |
||
443 | } |
||
444 | 4 | } |
|
445 | 4 | } |
|
446 | $newValueText = $this->$colName; |
||
447 | if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') { |
||
448 | 4 | switch ($class::$cols[$colName]['source']) { |
|
449 | 4 | case 'array': |
|
450 | 4 | $newValueText = isset($class::$cols[$colName]['sourceArray'][$this->$colName]) ? $class::$cols[$colName]['sourceArray'][$this->$colName] : $this->$colName; |
|
451 | break; |
||
452 | 2 | View Code Duplication | case 'relation': |
453 | 2 | $relation = $class::getRelation($class::$cols[$colName]['relation']); |
|
454 | $relModel = $relation['model']; |
||
455 | $rel = $relModel::get($this->$colName); |
||
456 | if ($rel) { |
||
457 | $newValueText = $rel->name(); |
||
458 | } |
||
459 | } |
||
460 | } |
||
461 | if (strlen($oldValueText) + strlen($newValueText) < 200) { |
||
462 | $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValueText}\" => \"{$newValueText}\""; |
||
463 | } else { |
||
464 | $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName; |
||
465 | } |
||
466 | } |
||
467 | if (!$changes_text) { |
||
468 | return false; |
||
469 | } |
||
470 | $activity->changes_text = implode(', ', $changes_text); |
||
471 | $activity->save(); |
||
472 | foreach ($this->_changedParams as $fullColName => $oldValue) { |
||
473 | $colName = substr($fullColName, strlen($class::colPrefix())); |
||
474 | View Code Duplication | if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) { |
|
475 | continue; |
||
476 | } |
||
477 | $colName = substr($fullColName, strlen($class::colPrefix())); |
||
478 | $change = new Dashboard\Activity\Change([ |
||
479 | 'activity_id' => $activity->id, |
||
480 | 'col' => $colName, |
||
481 | 'old' => $oldValue, |
||
482 | 'new' => $this->$colName |
||
483 | ]); |
||
484 | $change->save(); |
||
485 | } |
||
486 | } elseif ($new) { |
||
487 | $activity = new Dashboard\Activity([ |
||
488 | 'user_id' => $user_id, |
||
489 | 'module' => substr($class, 0, strpos($class, '\\')), |
||
490 | 'model' => $class, |
||
491 | 'item_id' => $this->pk(), |
||
492 | 2 | 'type' => 'new' |
|
493 | 2 | ]); |
|
494 | 2 | $activity->save(); |
|
495 | 2 | } |
|
496 | 2 | return true; |
|
497 | 2 | } |
|
498 | |||
499 | 2 | /** |
|
500 | 2 | * Check model relations path and load need relations |
|
501 | 2 | * |
|
502 | 2 | * @param string $col |
|
503 | * @param string $rootModel |
||
504 | */ |
||
505 | public static function checkForJoin(&$col, $rootModel) { |
||
506 | |||
507 | if (strpos($col, ':') !== false) { |
||
508 | $relations = static::relations(); |
||
509 | if (isset($relations[substr($col, 0, strpos($col, ':'))])) { |
||
510 | $rel = substr($col, 0, strpos($col, ':')); |
||
511 | 4 | $col = substr($col, strpos($col, ':') + 1); |
|
512 | $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type']; |
||
513 | 4 | $joinName = $relations[$rel]['model'] . '_' . $rel; |
|
514 | switch ($type) { |
||
515 | View Code Duplication | case 'to': |
|
516 | $relCol = $relations[$rel]['col']; |
||
517 | static::fixPrefix($relCol); |
||
518 | $rootModel::$relJoins[$joinName] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol, 'left', '']; |
||
519 | break; |
||
520 | case 'one': |
||
521 | View Code Duplication | case 'many': |
|
522 | $relCol = $relations[$rel]['col']; |
||
523 | $relations[$rel]['model']::fixPrefix($relCol); |
||
524 | $rootModel::$relJoins[$joinName] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol, 'left', '']; |
||
525 | break; |
||
526 | } |
||
527 | $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel); |
||
528 | } |
||
529 | } |
||
530 | } |
||
531 | |||
532 | /** |
||
533 | * Return full col information |
||
534 | * |
||
535 | * @param string $col |
||
536 | 4 | * @return array |
|
537 | */ |
||
538 | public static function getColInfo($col) { |
||
539 | return static::parseColRecursion($col); |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * Information extractor for col relations path |
||
544 | * |
||
545 | * @param string $info |
||
546 | * @return array |
||
547 | */ |
||
548 | public static function parseColRecursion($info) { |
||
549 | if (is_string($info)) { |
||
550 | $info = ['col' => $info, 'rawCol' => $info, 'modelName' => get_called_class(), 'label' => $info, 'joins' => []]; |
||
551 | } |
||
552 | if ($info['col'] === 'id') { |
||
553 | $info['colParams'] = [ |
||
554 | 'type' => 'number', |
||
555 | ]; |
||
556 | return $info; |
||
557 | } |
||
558 | if (strpos($info['col'], ':') !== false) { |
||
559 | $relations = static::relations(); |
||
560 | if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) { |
||
561 | $rel = substr($info['col'], 0, strpos($info['col'], ':')); |
||
562 | $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1); |
||
563 | $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type']; |
||
564 | $joinName = $relations[$rel]['model'] . '_' . $rel; |
||
565 | switch ($type) { |
||
566 | View Code Duplication | case 'to': |
|
567 | $relCol = $relations[$rel]['col']; |
||
568 | static::fixPrefix($relCol); |
||
569 | $info['joins'][$joinName] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol]; |
||
570 | break; |
||
571 | View Code Duplication | case 'one': |
|
572 | $relCol = $relations[$rel]['col']; |
||
573 | $relations[$rel]['model']::fixPrefix($relCol); |
||
574 | $info['joins'][$joinName] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol]; |
||
575 | break; |
||
576 | } |
||
577 | $info = $relations[$rel]['model']::parseColRecursion($info); |
||
578 | } |
||
579 | } else { |
||
580 | $cols = static::cols(); |
||
581 | View Code Duplication | if (!empty(static::$labels[$info['col']])) { |
|
582 | $info['label'] = static::$labels[$info['col']]; |
||
583 | } |
||
584 | |||
585 | if (isset(static::$cols[$info['col']])) { |
||
586 | $info['colParams'] = static::$cols[$info['col']]; |
||
587 | } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) { |
||
588 | $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])]; |
||
589 | } else { |
||
590 | $info['colParams'] = []; |
||
591 | } |
||
592 | View Code Duplication | if (!isset($cols[$info['col']]) && isset($cols[static::colPrefix() . $info['col']])) { |
|
593 | $info['col'] = static::colPrefix() . $info['col']; |
||
594 | } |
||
595 | } |
||
596 | View Code Duplication | if (!empty(static::$labels[$info['rawCol']])) { |
|
597 | $info['label'] = static::$labels[$info['rawCol']]; |
||
598 | } |
||
599 | return $info; |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * Return actual cols from data base |
||
604 | * |
||
605 | * @param boolean $refresh |
||
606 | * @return array |
||
607 | */ |
||
608 | 4 | public static function cols($refresh = false) { |
|
621 | |||
622 | /** |
||
623 | * Return cols indexes for create tables |
||
624 | * |
||
625 | * @return array |
||
626 | */ |
||
627 | 3 | public static function indexes() { |
|
630 | |||
631 | /** |
||
632 | * Generate params string for col by name |
||
633 | * |
||
634 | * @param string $colName |
||
635 | * @return false|string |
||
636 | */ |
||
637 | 4 | public static function genColParams($colName) { |
|
638 | 4 | if (empty(static::$cols[$colName]) || static::$storage['type'] == 'moduleConfig') { |
|
639 | 1 | return false; |
|
640 | } |
||
641 | 4 | $null = ' NULL'; |
|
642 | 4 | if (empty(static::$cols[$colName]['null'])) { |
|
643 | 4 | $null = ' NOT NULL'; |
|
644 | 4 | } |
|
645 | |||
646 | 4 | $params = false; |
|
647 | 4 | switch (static::$cols[$colName]['type']) { |
|
648 | 4 | case 'select': |
|
649 | 4 | switch (static::$cols[$colName]['source']) { |
|
650 | 4 | case 'relation': |
|
651 | 4 | $params = 'int(11) UNSIGNED' . $null; |
|
652 | 4 | break; |
|
653 | 1 | default: |
|
654 | 1 | $params = 'varchar(255)' . $null; |
|
655 | 4 | } |
|
656 | 4 | break; |
|
657 | 4 | case 'image': |
|
658 | 4 | case 'file': |
|
659 | 1 | $params = 'int(11) UNSIGNED' . $null; |
|
660 | 1 | break; |
|
661 | 4 | case 'number': |
|
662 | $params = 'int(11)' . $null; |
||
663 | break; |
||
664 | 4 | case 'text': |
|
665 | 4 | case 'email': |
|
666 | 3 | $params = 'varchar(255)' . $null; |
|
667 | 3 | break; |
|
668 | 3 | case 'html': |
|
669 | 3 | case 'textarea': |
|
670 | 3 | case 'json': |
|
671 | 3 | case 'password': |
|
672 | 3 | case 'dynamicType': |
|
673 | 3 | case 'map': |
|
674 | 1 | $params = 'text' . $null; |
|
675 | 1 | break; |
|
676 | 3 | case 'bool': |
|
677 | 1 | $params = 'tinyint(1) UNSIGNED' . $null; |
|
678 | 1 | break; |
|
679 | 3 | case 'decimal': |
|
680 | $params = 'decimal(8, 2)' . $null; |
||
681 | break; |
||
682 | 3 | case 'time': |
|
683 | 1 | $params = 'time' . $null; |
|
684 | 1 | break; |
|
685 | 3 | case 'date': |
|
686 | 2 | $params = 'date' . $null; |
|
687 | 2 | break; |
|
688 | 4 | case 'dateTime': |
|
689 | 4 | $params = 'timestamp' . $null; |
|
690 | break; |
||
691 | } |
||
692 | return $params; |
||
693 | } |
||
694 | |||
695 | /** |
||
696 | * Create new col in data base |
||
697 | * |
||
698 | 2 | * @param string $colName |
|
699 | 2 | * @return boolean|integer |
|
700 | 2 | */ |
|
701 | public static function createCol($colName) { |
||
702 | $cols = static::cols(); |
||
703 | 2 | if (!empty($cols[static::colPrefix() . $colName])) { |
|
704 | 2 | return true; |
|
705 | 2 | } |
|
706 | $params = static::genColParams($colName); |
||
707 | if ($params === false) { |
||
708 | return false; |
||
709 | } |
||
710 | 4 | $result = App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params); |
|
711 | 4 | static::cols(true); |
|
712 | return $result; |
||
713 | } |
||
714 | 4 | ||
715 | public static function createTable() { |
||
769 | |||
770 | 4 | /** |
|
771 | 4 | * Return table name |
|
772 | * |
||
773 | * @return string |
||
774 | */ |
||
775 | public static function table() { |
||
778 | |||
779 | 4 | /** |
|
780 | * Return table index col name |
||
781 | 4 | * |
|
782 | * @return string |
||
783 | */ |
||
784 | public static function index() { |
||
785 | return static::colPrefix() . 'id'; |
||
786 | } |
||
787 | |||
788 | /** |
||
789 | 4 | * Return col prefix |
|
790 | 4 | * |
|
791 | 4 | * @return string |
|
792 | 4 | */ |
|
793 | public static function colPrefix() { |
||
798 | |||
799 | /** |
||
800 | 1 | * return relations list |
|
801 | 1 | * |
|
802 | * @return array |
||
803 | */ |
||
804 | public static function relations() { |
||
807 | |||
808 | /** |
||
809 | * views list |
||
810 | * |
||
811 | * @return array |
||
812 | */ |
||
813 | public static $views = []; |
||
814 | |||
815 | /** |
||
816 | * Return name of col with object name |
||
817 | * |
||
818 | * @return string |
||
819 | */ |
||
820 | public static function nameCol() { |
||
823 | |||
824 | /** |
||
825 | * Return object name |
||
826 | * |
||
827 | * @return string |
||
828 | */ |
||
829 | public function name() { |
||
832 | |||
833 | /** |
||
834 | * Get single object from data base |
||
835 | * |
||
836 | * @param mixed $param |
||
837 | 4 | * @param string $col |
|
838 | 4 | * @param array $options |
|
839 | * @return boolean|static |
||
840 | */ |
||
841 | 4 | public static function get($param, $col = null, $options = []) { |
|
910 | |||
911 | /** |
||
912 | * Old method |
||
913 | * |
||
914 | * @param type $options |
||
915 | * @return Array |
||
916 | */ |
||
917 | public static function get_list($options = [], $debug = false) { |
||
1030 | |||
1031 | /** |
||
1032 | * Return list of objects from data base |
||
1033 | * |
||
1034 | * @param array $options |
||
1035 | * @return static[] |
||
1036 | */ |
||
1037 | public static function getList($options = [], $debug = false) { |
||
1055 | |||
1056 | /** |
||
1057 | * Get single item from module storage |
||
1058 | * |
||
1059 | * @param array $param |
||
1060 | * @param string $col |
||
1061 | * @param array $options |
||
1062 | * @return boolean|\Model |
||
1063 | */ |
||
1064 | public static function getFromModuleStorage($param = null, $col = null, $options = []) { |
||
1105 | |||
1106 | /** |
||
1107 | * Return list items from module storage |
||
1108 | * |
||
1109 | * @param array $options |
||
1110 | * @return array |
||
1111 | */ |
||
1112 | public static function getListFromModuleStorage($options = []) { |
||
1168 | |||
1169 | /** |
||
1170 | * Return count of records from module storage |
||
1171 | * |
||
1172 | * @param array $options |
||
1173 | * @return int |
||
1174 | */ |
||
1175 | public static function getCountFromModuleStorage($options = []) { |
||
1206 | |||
1207 | /** |
||
1208 | * Check where for module storage query |
||
1209 | * |
||
1210 | * @param array $item |
||
1211 | * @param array|string $where |
||
1212 | * @param string $value |
||
1213 | * @param string $operation |
||
1214 | * @param string $concatenation |
||
1215 | * @return boolean |
||
1216 | */ |
||
1217 | public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') { |
||
1250 | |||
1251 | /** |
||
1252 | * Return count of records from data base |
||
1253 | * |
||
1254 | * @param array $options |
||
1255 | * @return array|int |
||
1256 | */ |
||
1257 | public static function getCount($options = []) { |
||
1258 | if (static::$storage['type'] == 'moduleConfig') { |
||
1259 | return static::getCountFromModuleStorage($options); |
||
1260 | } |
||
1261 | $query = App::$cur->db->newQuery(); |
||
1262 | if (!$query) { |
||
1263 | return 0; |
||
1264 | } |
||
1265 | if (!empty($options['where'])) { |
||
1266 | static::fixPrefix($options['where'], 'first'); |
||
1267 | } |
||
1268 | if (!empty($options['group'])) { |
||
1269 | static::fixPrefix($options['group'], 'first'); |
||
1270 | } |
||
1271 | if (!empty($options['order'])) { |
||
1272 | static::fixPrefix($options['order'], 'first'); |
||
1273 | } |
||
1274 | if (!empty($options['where'])) { |
||
1275 | $query->where($options['where']); |
||
1276 | } |
||
1277 | if (!empty($options['join'])) { |
||
1278 | $query->join($options['join']); |
||
1279 | } |
||
1280 | if (!empty($options['order'])) { |
||
1281 | $query->order($options['order']); |
||
1282 | } |
||
1283 | View Code Duplication | if (!empty($options['limit'])) { |
|
1284 | $limit = (int) $options['limit']; |
||
1285 | } else { |
||
1286 | $limit = 0; |
||
1287 | } |
||
1288 | View Code Duplication | if (!empty($options['start'])) { |
|
1289 | $start = (int) $options['start']; |
||
1290 | } else { |
||
1291 | $start = 0; |
||
1292 | } |
||
1293 | if ($limit || $start) { |
||
1294 | $query->limit($start, $limit); |
||
1295 | } |
||
1296 | |||
1297 | View Code Duplication | foreach (static::$needJoin as $rel) { |
|
1298 | $relations = static::relations(); |
||
1299 | foreach ($query->join as $item) { |
||
1300 | if ($item[0] === $relations[$rel]['model']::table() && $item[3] === '') { |
||
1301 | continue 2; |
||
1302 | } |
||
1303 | } |
||
1304 | if (isset($relations[$rel])) { |
||
1305 | $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type']; |
||
1306 | switch ($type) { |
||
1307 | case 'to': |
||
1308 | $relCol = $relations[$rel]['col']; |
||
1309 | static::fixPrefix($relCol); |
||
1310 | $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol); |
||
1311 | break; |
||
1312 | case 'one': |
||
1313 | $col = $relations[$rel]['col']; |
||
1314 | $relations[$rel]['model']::fixPrefix($col); |
||
1315 | $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col); |
||
1316 | break; |
||
1317 | } |
||
1318 | } |
||
1319 | } |
||
1320 | static::$needJoin = []; |
||
1321 | View Code Duplication | foreach (static::$relJoins as $join) { |
|
1322 | foreach ($query->join as $item) { |
||
1323 | if ($item[0] === $join[0] && $item[3] === $join[3]) { |
||
1324 | continue 2; |
||
1325 | } |
||
1326 | } |
||
1327 | $query->join($join); |
||
1328 | } |
||
1329 | static::$relJoins = []; |
||
1330 | $cols = 'COUNT('; |
||
1331 | |||
1332 | if (!empty($options['distinct'])) { |
||
1333 | if (is_bool($options['distinct'])) { |
||
1334 | $cols .= 'DISTINCT *'; |
||
1335 | } else { |
||
1336 | $cols .= "DISTINCT {$options['distinct']}"; |
||
1337 | } |
||
1338 | } else { |
||
1339 | $cols .= '*'; |
||
1340 | } |
||
1341 | $cols .= ') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : ''); |
||
1342 | $query->cols = $cols; |
||
1343 | if (!empty($options['group'])) { |
||
1344 | $query->group($options['group']); |
||
1345 | } |
||
1346 | try { |
||
1347 | $result = $query->select(static::table()); |
||
1348 | } catch (PDOException $exc) { |
||
1349 | if ($exc->getCode() == '42S02') { |
||
1350 | static::createTable(); |
||
1351 | } else { |
||
1352 | throw $exc; |
||
1353 | } |
||
1354 | $result = $query->select(static::table()); |
||
1355 | } |
||
1356 | if (!empty($options['group'])) { |
||
1357 | $count = $result->getArray(); |
||
1358 | return $count; |
||
1359 | } else { |
||
1360 | $count = $result->fetch(); |
||
1361 | return $count['count']; |
||
1362 | } |
||
1363 | } |
||
1364 | |||
1365 | 4 | /** |
|
1366 | 4 | * Update records in data base |
|
1367 | * |
||
1368 | * @param array $params |
||
1369 | * @param array $where |
||
1370 | * @return false|null |
||
1371 | */ |
||
1372 | 4 | public static function update($params, $where = []) { |
|
1394 | |||
1395 | 1 | /** |
|
1396 | 1 | * Return primary key of object |
|
1397 | * |
||
1398 | * @return mixed |
||
1399 | 1 | */ |
|
1400 | public function pk() { |
||
1403 | |||
1404 | /** |
||
1405 | 1 | * Before save trigger |
|
1406 | */ |
||
1407 | public function beforeSave() { |
||
1410 | |||
1411 | /** |
||
1412 | * Save object to module storage |
||
1413 | * |
||
1414 | * @param array $options |
||
1415 | * @return boolean |
||
1416 | 1 | */ |
|
1417 | 1 | public function saveModuleStorage($options) { |
|
1468 | |||
1469 | /** |
||
1470 | * Update tree path category |
||
1471 | */ |
||
1472 | public function changeCategoryTree() { |
||
1496 | |||
1497 | /** |
||
1498 | * Return tree path |
||
1499 | * |
||
1500 | * @param \Model $catalog |
||
1501 | * @return string |
||
1502 | 4 | */ |
|
1503 | public function getCatalogTree($catalog) { |
||
1515 | 3 | ||
1516 | 3 | /** |
|
1517 | 4 | * Update tree path item |
|
1518 | 4 | */ |
|
1519 | public function changeItemTree() { |
||
1530 | 4 | ||
1531 | /** |
||
1532 | 4 | * Save object to data base |
|
1533 | * |
||
1534 | * @param array $options |
||
1535 | * @return boolean|int |
||
1536 | 4 | */ |
|
1537 | 3 | public function save($options = []) { |
|
1608 | |||
1609 | /** |
||
1610 | * After save trigger |
||
1611 | */ |
||
1612 | public function afterSave() { |
||
1615 | |||
1616 | /** |
||
1617 | * Before delete trigger |
||
1618 | */ |
||
1619 | public function beforeDelete() { |
||
1622 | |||
1623 | /** |
||
1624 | * Delete item from module storage |
||
1625 | * |
||
1626 | * @param array $options |
||
1627 | * @return boolean |
||
1628 | */ |
||
1629 | public function deleteFromModuleStorage($options) { |
||
1673 | 1 | ||
1674 | /** |
||
1675 | * Delete item from data base |
||
1676 | * |
||
1677 | * @param array $options |
||
1678 | * @return boolean |
||
1679 | */ |
||
1680 | public function delete($options = []) { |
||
1696 | 4 | ||
1697 | 4 | /** |
|
1698 | 2 | * Delete items from data base |
|
1699 | 4 | * |
|
1700 | 4 | * @param array $where |
|
1701 | */ |
||
1702 | public static function deleteList($where = []) { |
||
1709 | 4 | ||
1710 | 4 | /** |
|
1711 | * After delete trigger |
||
1712 | */ |
||
1713 | public function afterDelete() { |
||
1716 | |||
1717 | /** |
||
1718 | * find relation for col name |
||
1719 | * |
||
1720 | 4 | * @param string $col |
|
1721 | 4 | * @return array|null |
|
1722 | 4 | */ |
|
1723 | 2 | public static function findRelation($col) { |
|
1732 | |||
1733 | /** |
||
1734 | * Set params for model |
||
1735 | * |
||
1736 | * @param array $params |
||
1737 | */ |
||
1738 | public function setParams($params) { |
||
1743 | |||
1744 | /** |
||
1745 | * Return relation |
||
1746 | * |
||
1747 | * @param string $relName |
||
1748 | * @return array|boolean |
||
1749 | */ |
||
1750 | public static function getRelation($relName) { |
||
1754 | |||
1755 | 2 | /** |
|
1756 | * Load relation |
||
1757 | * |
||
1758 | * @param string $name |
||
1759 | * @param array $params |
||
1760 | * @return null|array|integer|\Model |
||
1761 | */ |
||
1762 | public function loadRelation($name, $params = []) { |
||
1845 | |||
1846 | /** |
||
1847 | * Add relation item |
||
1848 | * |
||
1849 | * @param string $relName |
||
1850 | * @param \Model $objectId |
||
1851 | * @return \Model|boolean |
||
1852 | */ |
||
1853 | public function addRelation($relName, $objectId) { |
||
1868 | |||
1869 | /** |
||
1870 | * Check user access for form |
||
1871 | * |
||
1872 | * @param string $formName |
||
1873 | * @return boolean |
||
1874 | */ |
||
1875 | public function checkFormAccess($formName) { |
||
1881 | |||
1882 | 4 | /** |
|
1883 | 4 | * Check access for model |
|
1884 | 4 | * |
|
1885 | 4 | * @param string $mode |
|
1886 | 4 | * @param \Users\User $user |
|
1887 | * @return boolean |
||
1888 | 4 | */ |
|
1889 | 2 | public function checkAccess($mode = 'write', $user = null) { |
|
1895 | |||
1896 | /** |
||
1897 | * Param and relation with params getter |
||
1898 | * |
||
1899 | * @param string $name |
||
1900 | * @param array $params |
||
1901 | * @return \Value|mixed |
||
1902 | */ |
||
1903 | public function __call($name, $params) { |
||
1915 | |||
1916 | /** |
||
1917 | * Param and relation getter |
||
1918 | * |
||
1919 | * @param string $name |
||
1920 | * @return mixed |
||
1921 | */ |
||
1922 | public function __get($name) { |
||
1933 | |||
1934 | /** |
||
1935 | * Return model value in object |
||
1936 | * |
||
1937 | * @param string $name |
||
1938 | * @return \Value|null |
||
1939 | */ |
||
1940 | public function value($name) { |
||
1950 | |||
1951 | /** |
||
1952 | * Return manager filters |
||
1953 | * |
||
1954 | * @return array |
||
1955 | */ |
||
1956 | public static function managerFilters() { |
||
1959 | 4 | ||
1960 | 4 | /** |
|
1961 | 4 | * Return validators for cols |
|
1962 | 4 | * |
|
1963 | * @return array |
||
1964 | */ |
||
1965 | 4 | public static function validators() { |
|
1968 | 4 | ||
1969 | 4 | /** |
|
1970 | 4 | * Return validator by name |
|
1971 | * |
||
1972 | * @param string $name |
||
1973 | 4 | * @return array |
|
1974 | 2 | */ |
|
1975 | 2 | public static function validator($name) { |
|
1982 | 4 | ||
1983 | 3 | public function genViewLink() { |
|
1991 | |||
1992 | public function extract($model) { |
||
2009 | |||
2010 | /** |
||
2011 | * Set handler for model params |
||
2012 | * |
||
2013 | * @param string $name |
||
2014 | * @param mixed $value |
||
2015 | */ |
||
2016 | public function __set($name, $value) { |
||
2047 | |||
2048 | /** |
||
2049 | * Isset handler for model params |
||
2050 | * |
||
2051 | * @param string $name |
||
2052 | * @return boolean |
||
2053 | */ |
||
2054 | public function __isset($name) { |
||
2058 | |||
2059 | /** |
||
2060 | * Convert object to string |
||
2061 | * |
||
2062 | * @return string |
||
2063 | */ |
||
2064 | public function __toString() { |
||
2067 | } |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.