Total Complexity | 126 |
Total Lines | 679 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like FileBehavior 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.
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 FileBehavior, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class FileBehavior extends Behavior |
||
12 | { |
||
13 | |||
14 | /** |
||
15 | * {@inheritDoc} |
||
16 | */ |
||
17 | protected $_defaultConfig = [ |
||
18 | 'library' => 'gd', |
||
19 | 'types' => [ // Default allowed types |
||
20 | 'image/bmp', |
||
21 | 'image/gif', |
||
22 | 'image/jpeg', |
||
23 | 'image/jpg', |
||
24 | 'image/pjpeg', |
||
25 | 'image/pjpg', |
||
26 | 'image/png', |
||
27 | 'image/x-png', |
||
28 | 'image/webp', |
||
29 | ], |
||
30 | 'extensions' => [ // Default allowed extensions |
||
31 | 'bmp', |
||
32 | 'gif', |
||
33 | 'jpeg', |
||
34 | 'jpg', |
||
35 | 'pjpg', |
||
36 | 'pjpeg', |
||
37 | 'png', |
||
38 | 'webp', |
||
39 | ], |
||
40 | 'path' => 'files', |
||
41 | 'background' => [255, 255, 255, 127], |
||
42 | 'watermark' => '', |
||
43 | 'thumbs' => [], |
||
44 | ]; |
||
45 | |||
46 | /** |
||
47 | * Array of files to upload |
||
48 | * |
||
49 | * @var array |
||
50 | */ |
||
51 | protected $_files = []; |
||
52 | |||
53 | /** |
||
54 | * {@inheritDoc} |
||
55 | */ |
||
56 | public function initialize(array $config) |
||
67 | } |
||
68 | } |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * {@inheritDoc} |
||
73 | */ |
||
74 | public function beforeMarshal(Event $event, $data = [], $options = []) |
||
75 | { |
||
76 | if (!empty($config = $this->getConfig($this->getTable()->getAlias()))) { |
||
77 | foreach ($config as $field => $fieldOptions) { |
||
78 | if (array_key_exists($field, $data)) { |
||
79 | // Save file array to suffixed field |
||
80 | $data['_' . $field] = $data[$field]; |
||
81 | |||
82 | // Detect multiple files by array keys |
||
83 | if (is_numeric(key($data[$field]))) { |
||
84 | foreach (array_keys($data[$field]) as $key) { |
||
85 | if (!empty($data[$field][$key]['tmp_name'])) { |
||
86 | $this->_files[$field . '_' . $key] = array_merge($fieldOptions, [ |
||
87 | 'name' => $this->_prepareName($data[$field][$key]['name']), |
||
88 | 'source' => $data[$field][$key]['tmp_name'], |
||
89 | ]); |
||
90 | |||
91 | $data[$field][$key] = $this->_files[$field . '_' . $key]['name']; |
||
92 | } else { |
||
93 | unset($data[$field][$key]); |
||
94 | } |
||
95 | } |
||
96 | } else { |
||
97 | if (!empty($data[$field]['tmp_name'])) { |
||
98 | $this->_files[$field] = array_merge($fieldOptions, [ |
||
99 | 'name' => $this->_prepareName($data[$field]['name']), |
||
100 | 'source' => $data[$field]['tmp_name'], |
||
101 | ]); |
||
102 | |||
103 | $data[$field] = $this->_files[$field]['name']; |
||
104 | } else { |
||
105 | unset($data[$field]); |
||
106 | } |
||
107 | } |
||
108 | } |
||
109 | } |
||
110 | } |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * {@inheritDoc} |
||
115 | */ |
||
116 | public function afterSave(Event $event, EntityInterface $entity, $options = []) |
||
117 | { |
||
118 | $this->_prepareFile($entity); |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * {@inheritDoc} |
||
123 | */ |
||
124 | public function beforeDelete(Event $event, EntityInterface $entity) |
||
125 | { |
||
126 | return $this->deleteFile($event); |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Copy source file to destination and if field (image) has configurations for thumbs, then create them. |
||
131 | * |
||
132 | * @param EntityInterface $entity Entity |
||
133 | */ |
||
134 | protected function _prepareFile(EntityInterface $entity) |
||
135 | { |
||
136 | foreach ($this->_files as $field => $fieldOptions) { |
||
137 | if (!is_dir($fieldOptions['path'])) { |
||
138 | $this->_prepareDir($fieldOptions['path']); |
||
139 | } |
||
140 | |||
141 | $file = $fieldOptions['path'] . DS . $fieldOptions['name']; |
||
142 | |||
143 | if (move_uploaded_file($fieldOptions['source'], $file) || (file_exists($fieldOptions['source']) && rename($fieldOptions['source'], $file))) { |
||
144 | $fileType = mb_strtolower(getimagesize($fieldOptions['source'])['mime']); |
||
145 | |||
146 | $fieldTypes = array_map(function ($fieldType) { |
||
147 | return mb_strtolower($fieldType); |
||
148 | }, $fieldOptions['types']); |
||
149 | |||
150 | // Create thumbs |
||
151 | if (mb_strpos($fileType, 'image/') !== false && in_array($fileType, $fieldTypes)) { |
||
152 | $this->_prepareThumbs($file, $fieldOptions); |
||
153 | } |
||
154 | } |
||
155 | } |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Delete file with created thumbs |
||
160 | * |
||
161 | * @param Event $event Reference to event |
||
162 | * @return boolean True if is success |
||
163 | */ |
||
164 | public function deleteFile(Event $event) |
||
165 | { |
||
166 | // Get field list of model schema |
||
167 | $modelSchema = $model->schema(); |
||
|
|||
168 | |||
169 | foreach ($this->settings[$model->alias] as $fieldName => $fieldOptions) { |
||
170 | // Check is field in model schema |
||
171 | if (isset($modelSchema[$fieldName])) { |
||
172 | $dataField = $model->findById($model->id); |
||
173 | |||
174 | if (is_array($dataField) && !empty($dataField[$model->alias][$fieldName])) { |
||
175 | // Pattern for original file with thumbs |
||
176 | $filePattern = $this->settings[$model->alias][$fieldName]['path'] . DS . substr($dataField[$model->alias][$fieldName], 0, 14); |
||
177 | |||
178 | foreach (glob($filePattern . '*') as $fileName) { |
||
179 | // Remove file |
||
180 | @unlink($fileName); |
||
181 | } |
||
182 | } |
||
183 | } |
||
184 | } |
||
185 | |||
186 | return true; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Generate thumbs by names with parameters |
||
191 | * |
||
192 | * @param string $originalFile Path to original file |
||
193 | * @param array $thumbParams Settings for uploaded files |
||
194 | * @return boolean Output image to save file |
||
195 | */ |
||
196 | protected function _prepareThumbs($originalFile, $settingParams) |
||
374 | } |
||
375 | } |
||
376 | } |
||
377 | } |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Get extension from original name |
||
382 | * |
||
383 | * @param string $originalName Name of original file |
||
384 | * @return string Extension of uploaded file |
||
385 | */ |
||
386 | public function getExtension($originalName) |
||
387 | { |
||
388 | $fileExtension = pathinfo(mb_strtolower($originalName), PATHINFO_EXTENSION); |
||
389 | |||
390 | switch ($fileExtension) { |
||
391 | case 'jpg': |
||
392 | case 'jpeg': |
||
393 | case 'pjpg': |
||
394 | case 'pjpeg': |
||
395 | // Standarize JPEG image file extension |
||
396 | return 'jpg'; |
||
397 | |||
398 | break; |
||
399 | default: |
||
400 | return $fileExtension; |
||
401 | |||
402 | break; |
||
403 | } |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * Get position of watermark image |
||
408 | * |
||
409 | * @param integer $newWidth New width of uploaded image |
||
410 | * @param integer $newHeight New height of uploaded image |
||
411 | * @param integer $watermarkWidth Original width of watermark image |
||
412 | * @param integer $watermarkHeight Original height of watermark image |
||
413 | * @param integer $offsetX Horizontal offset |
||
414 | * @param integer $offsetY Vertical offset |
||
415 | * @param integer $positionValue Value for position watermark, value between 1 and 9 |
||
416 | * @return array Coordinates of position watermark |
||
417 | */ |
||
418 | public function getPosition($newWidth, $newHeight, $watermarkWidth, $watermarkHeight, $offsetX = 0, $offsetY = 0, $positionValue = 1) |
||
419 | { |
||
420 | switch (intval($positionValue)) { |
||
421 | case 1: // Top left |
||
422 | return [$offsetX, $offsetY]; |
||
423 | |||
424 | break; |
||
425 | case 2: // Top center |
||
426 | return [($newWidth / 2) - ($watermarkWidth / 2), 0 + $offsetY]; |
||
427 | |||
428 | break; |
||
429 | case 3: // Top right |
||
430 | return [($newWidth - $watermarkWidth) - $offsetX, 0 + $offsetY]; |
||
431 | |||
432 | break; |
||
433 | case 4: // Middle left |
||
434 | return [$offsetX, ($newHeight / 2) - ($watermarkHeight / 2)]; |
||
435 | |||
436 | break; |
||
437 | case 5: // Middle center |
||
438 | return [($newWidth / 2) - ($watermarkWidth / 2), ($newHeight / 2) - ($watermarkHeight / 2)]; |
||
439 | |||
440 | break; |
||
441 | case 6: // Middle right |
||
442 | return [($newWidth - $watermarkWidth) - $offsetX, ($newHeight / 2) - ($watermarkHeight / 2)]; |
||
443 | |||
444 | break; |
||
445 | case 7: // Bottom left |
||
446 | return [$offsetX, ($newHeight - $watermarkHeight) - $offsetY]; |
||
447 | |||
448 | break; |
||
449 | case 8: // Bottom center |
||
450 | return [($newWidth / 2) - ($watermarkWidth / 2), ($newHeight - $watermarkHeight) - $offsetY]; |
||
451 | |||
452 | break; |
||
453 | case 9: // Bottom right |
||
454 | return [($newWidth - $watermarkWidth) - $offsetX, ($newHeight - $watermarkHeight) - $offsetY]; |
||
455 | |||
456 | break; |
||
457 | default: |
||
458 | return [$offsetX, $offsetY]; |
||
459 | |||
460 | break; |
||
461 | } |
||
462 | } |
||
463 | |||
464 | /** |
||
465 | * Generate random name of uploaded file. |
||
466 | * If action is for update with not used file then it will be removed. |
||
467 | * |
||
468 | * @todo Prepare method for working without primary key field |
||
469 | * @todo Generate names of files by user method |
||
470 | * @param string $fieldName Name of file field |
||
471 | * @return string New name of file |
||
472 | */ |
||
473 | protected function _prepareName($fieldName) |
||
474 | { |
||
475 | return Text::uuid() . '_default.' . $this->getExtension($fieldName); |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Set path to directory for save uploaded files. |
||
480 | * If directory isn't exists, will be created with full privileges. |
||
481 | * |
||
482 | * @param string $dirPath Path to directory |
||
483 | * @return string Path to directory |
||
484 | */ |
||
485 | protected function _prepareDir($dirPath) |
||
486 | { |
||
487 | $dirPath = WWW_ROOT . str_replace('/', DS, $dirPath); |
||
488 | |||
489 | if (!is_dir($dirPath) && mb_strlen($dirPath) > 0) { |
||
490 | mkdir($dirPath, 0777, true); |
||
491 | } |
||
492 | |||
493 | chmod($dirPath, 0777); |
||
494 | |||
495 | return $dirPath; |
||
496 | } |
||
497 | |||
498 | /** |
||
499 | * Create image dimension by new width. |
||
500 | * |
||
501 | * @param integer $originalWidth Original width of uploaded image |
||
502 | * @param integer $originalHeight Original height of uploaded image |
||
503 | * @param integer $newWidth Set new image width |
||
504 | * @return array New width and height |
||
505 | */ |
||
506 | protected function _byWidth($originalWidth, $originalHeight, $newWidth) |
||
518 | } |
||
519 | |||
520 | /** |
||
521 | * Create image dimension by new height. |
||
522 | * |
||
523 | * @param integer $originalWidth Original width of uploaded image |
||
524 | * @param integer $originalHeight Original height of uploaded image |
||
525 | * @param integer $newHeight Set new image height |
||
526 | * @return array New width and height |
||
527 | */ |
||
528 | protected function _byHeight($originalWidth, $originalHeight, $newHeight) |
||
529 | { |
||
530 | $newHeight = intval($newHeight); |
||
531 | |||
532 | if ($newHeight > $originalHeight) { |
||
533 | $newHeight = $originalHeight; |
||
534 | $newWidth = $originalWidth; |
||
535 | } else { |
||
536 | $newWidth = intval($newHeight * ($originalWidth / $originalHeight)); |
||
537 | } |
||
538 | |||
539 | return [$newWidth, $newHeight]; |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * Create image dimension by shorter side. |
||
544 | * |
||
545 | * @param integer $originalWidth Original width of uploaded image |
||
546 | * @param integer $originalHeight Original height of uploaded image |
||
547 | * @param integer $newWidth Set new image min width |
||
548 | * @param integer $newHeight Set new image min height |
||
549 | * @return array New width and height |
||
550 | */ |
||
551 | protected function _byShorter($originalWidth, $originalHeight, $newWidth, $newHeight) |
||
552 | { |
||
553 | $newWidth = intval($newWidth); |
||
554 | $newHeight = intval($newHeight); |
||
555 | |||
556 | if ($originalWidth < $originalHeight) { |
||
557 | list($newWidth, $newHeight) = $this->_byWidth($originalWidth, $originalHeight, $newWidth); |
||
558 | } else { |
||
559 | list($newWidth, $newHeight) = $this->_byHeight($originalWidth, $originalHeight, $newHeight); |
||
560 | } |
||
561 | |||
562 | return [$newWidth, $newHeight]; |
||
563 | } |
||
564 | |||
565 | /** |
||
566 | * Create image dimension by longer side. |
||
567 | * |
||
568 | * @param integer $originalWidth Original width of uploaded image |
||
569 | * @param integer $originalHeight Original height of uploaded image |
||
570 | * @param integer $newWidth Set new image max width |
||
571 | * @param integer $newHeight Set new image max height |
||
572 | * @return array New width and height |
||
573 | */ |
||
574 | protected function _byLonger($originalWidth, $originalHeight, $newWidth, $newHeight) |
||
575 | { |
||
576 | $newWidth = intval($newWidth); |
||
577 | $newHeight = intval($newHeight); |
||
578 | |||
579 | if ($originalWidth > $originalHeight) { |
||
580 | list($newWidth, $newHeight) = $this->_byWidth($originalWidth, $originalHeight, $newWidth); |
||
581 | } else { |
||
582 | list($newWidth, $newHeight) = $this->_byHeight($originalWidth, $originalHeight, $newHeight); |
||
583 | } |
||
584 | |||
585 | return [$newWidth, $newHeight]; |
||
586 | } |
||
587 | |||
588 | /** |
||
589 | * Create image dimension by fit. |
||
590 | * |
||
591 | * @param integer $originalWidth Original width of uploaded image |
||
592 | * @param integer $originalHeight Original height of uploaded image |
||
593 | * @param integer $newWidth Set new image width |
||
594 | * @param integer $newHeight Set new image height |
||
595 | * @param boolean $originalKeep Save original shape |
||
596 | * @return array New width and height and offsets of position with keeping original shape |
||
597 | */ |
||
598 | protected function _byFit($originalWidth, $originalHeight, $newWidth, $newHeight, $originalKeep = false) |
||
599 | { |
||
600 | $newWidth = intval($newWidth); |
||
601 | $newHeight = intval($newHeight); |
||
602 | |||
603 | $offsetX = 0; |
||
604 | $offsetY = 0; |
||
605 | $cropX = 0; |
||
606 | $cropY = 0; |
||
607 | |||
608 | if ($originalKeep === true) { |
||
609 | if ($originalWidth == $originalHeight) { |
||
610 | $newSizes = $this->_byLonger($originalWidth, $originalHeight, min($newWidth, $newHeight), min($newWidth, $newHeight)); |
||
611 | } else { |
||
612 | $newSizes = $this->_byLonger($originalWidth, $originalHeight, $newWidth, $newHeight); |
||
613 | |||
614 | if ($newWidth < $newSizes[0] || $newHeight < $newSizes[1]) { |
||
615 | $newSizes = $this->_byShorter($originalWidth, $originalHeight, $newWidth, $newHeight); |
||
616 | } |
||
617 | } |
||
618 | } else { |
||
619 | if ($originalWidth == $originalHeight) { |
||
620 | $newSizes = $this->_byShorter($originalWidth, $originalHeight, max($newWidth, $newHeight), max($newWidth, $newHeight)); |
||
621 | } else { |
||
622 | $newSizes = $this->_byShorter($originalWidth, $originalHeight, $newWidth, $newHeight); |
||
623 | |||
624 | if ($newWidth > $newSizes[0] || $newHeight > $newSizes[1]) { |
||
625 | $newSizes = $this->_byLonger($originalWidth, $originalHeight, $newWidth, $newHeight); |
||
626 | } |
||
627 | } |
||
628 | } |
||
629 | |||
630 | if ($newWidth < $newSizes[0]) { |
||
631 | $cropX = ($newSizes[0] - $newWidth) / 2; |
||
632 | } else { |
||
633 | $offsetX = ($newWidth - $newSizes[0]) / 2; |
||
634 | } |
||
635 | |||
636 | if ($newHeight < $newSizes[1]) { |
||
637 | $cropY = ($newSizes[1] - $newHeight) / 2; |
||
638 | } else { |
||
639 | $offsetY = ($newHeight - $newSizes[1]) / 2; |
||
640 | } |
||
641 | |||
642 | return [$newSizes[0], $newSizes[1], $offsetX, $offsetY, $cropX, $cropY]; |
||
643 | } |
||
644 | |||
645 | /** |
||
646 | * Create image dimension to square |
||
647 | * |
||
648 | * @param integer $originalWidth Original width of uploaded image |
||
649 | * @param integer $originalHeight Original height of uploaded image |
||
650 | * @param integer $newSide Set new image side |
||
651 | * @param boolean $originalKeep Save original shape |
||
652 | * @return array New width and height with coordinates of crop or offsets of position |
||
653 | */ |
||
654 | protected function _bySquare($originalWidth, $originalHeight, $newSide, $originalKeep = false) |
||
690 | } |
||
691 | } |