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 FileProperty 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 FileProperty, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | class FileProperty extends AbstractProperty |
||
24 | { |
||
25 | const DEFAULT_PUBLIC_ACCESS = false; |
||
26 | const DEFAULT_UPLOAD_PATH = 'uploads/'; |
||
27 | const DEFAULT_FILESYSTEM = 'public'; |
||
28 | const DEFAULT_OVERWRITE = false; |
||
29 | const ERROR_MESSAGES = [ |
||
30 | UPLOAD_ERR_OK => 'There is no error, the file uploaded with success', |
||
31 | UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini', |
||
32 | UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive'. |
||
33 | 'that was specified in the HTML form', |
||
34 | UPLOAD_ERR_PARTIAL => 'The uploaded file was only partially uploaded', |
||
35 | UPLOAD_ERR_NO_FILE => 'No file was uploaded', |
||
36 | UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder', |
||
37 | UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk', |
||
38 | UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload.', |
||
39 | ]; |
||
40 | |||
41 | /** |
||
42 | * Whether uploaded files should be accessible from the web root. |
||
43 | * |
||
44 | * @var boolean |
||
45 | */ |
||
46 | private $publicAccess = self::DEFAULT_PUBLIC_ACCESS; |
||
47 | |||
48 | /** |
||
49 | * The relative path to the storage directory. |
||
50 | * |
||
51 | * @var string |
||
52 | */ |
||
53 | private $uploadPath = self::DEFAULT_UPLOAD_PATH; |
||
54 | |||
55 | /** |
||
56 | * The base path for the Charcoal installation. |
||
57 | * |
||
58 | * @var string |
||
59 | */ |
||
60 | private $basePath; |
||
61 | |||
62 | /** |
||
63 | * The path to the public / web directory. |
||
64 | * |
||
65 | * @var string |
||
66 | */ |
||
67 | private $publicPath; |
||
68 | |||
69 | /** |
||
70 | * Whether existing destinations should be overwritten. |
||
71 | * |
||
72 | * @var boolean |
||
73 | */ |
||
74 | private $overwrite = self::DEFAULT_OVERWRITE; |
||
75 | |||
76 | /** |
||
77 | * Collection of accepted MIME types. |
||
78 | * |
||
79 | * @var string[] |
||
80 | */ |
||
81 | private $acceptedMimetypes = []; |
||
82 | |||
83 | /** |
||
84 | * Current file mimetype |
||
85 | * |
||
86 | * @var string |
||
87 | */ |
||
88 | private $mimetype; |
||
89 | |||
90 | /** |
||
91 | * Maximum allowed file size, in bytes. |
||
92 | * |
||
93 | * @var integer |
||
94 | */ |
||
95 | private $maxFilesize; |
||
96 | |||
97 | /** |
||
98 | * Current file size, in bytes. |
||
99 | * |
||
100 | * @var integer |
||
101 | */ |
||
102 | private $filesize; |
||
103 | |||
104 | /** |
||
105 | * The filesystem to use while uploading a file. |
||
106 | * |
||
107 | * @var string |
||
108 | */ |
||
109 | private $filesystem = self::DEFAULT_FILESYSTEM; |
||
110 | |||
111 | /** |
||
112 | * @return string |
||
113 | */ |
||
114 | public function type() |
||
118 | |||
119 | /** |
||
120 | * Set whether uploaded files should be publicly available. |
||
121 | * |
||
122 | * @param boolean $public Whether uploaded files should be accessible (TRUE) or not (FALSE) from the web root. |
||
123 | * @return self |
||
124 | */ |
||
125 | public function setPublicAccess($public) |
||
131 | |||
132 | /** |
||
133 | * Determine if uploaded files should be publicly available. |
||
134 | * |
||
135 | * @return boolean |
||
136 | */ |
||
137 | public function getPublicAccess() |
||
141 | |||
142 | /** |
||
143 | * Set the destination (directory) where uploaded files are stored. |
||
144 | * |
||
145 | * The path must be relative to the {@see self::basePath()}, |
||
146 | * |
||
147 | * @param string $path The destination directory, relative to project's root. |
||
148 | * @throws InvalidArgumentException If the path is not a string. |
||
149 | * @return self |
||
150 | */ |
||
151 | public function setUploadPath($path) |
||
164 | |||
165 | /** |
||
166 | * Retrieve the destination for the uploaded file(s). |
||
167 | * |
||
168 | * @return string |
||
169 | */ |
||
170 | public function getUploadPath() |
||
174 | |||
175 | /** |
||
176 | * Set whether existing destinations should be overwritten. |
||
177 | * |
||
178 | * @param boolean $overwrite Whether existing destinations should be overwritten (TRUE) or not (FALSE). |
||
179 | * @return self |
||
180 | */ |
||
181 | public function setOverwrite($overwrite) |
||
187 | |||
188 | /** |
||
189 | * Determine if existing destinations should be overwritten. |
||
190 | * |
||
191 | * @return boolean |
||
192 | */ |
||
193 | public function getOverwrite() |
||
197 | |||
198 | /** |
||
199 | * @param string[] $mimetypes The accepted mimetypes. |
||
200 | * @return self |
||
201 | */ |
||
202 | public function setAcceptedMimetypes(array $mimetypes) |
||
208 | |||
209 | /** |
||
210 | * @return string[] |
||
211 | */ |
||
212 | public function getAcceptedMimetypes() |
||
216 | |||
217 | /** |
||
218 | * Set the MIME type. |
||
219 | * |
||
220 | * @param mixed $type The file MIME type. |
||
221 | * @throws InvalidArgumentException If the MIME type argument is not a string. |
||
222 | * @return FileProperty Chainable |
||
223 | */ |
||
224 | public function setMimetype($type) |
||
242 | |||
243 | /** |
||
244 | * Retrieve the MIME type. |
||
245 | * |
||
246 | * @return string |
||
247 | */ |
||
248 | public function getMimetype() |
||
262 | |||
263 | /** |
||
264 | * Alias of {@see self::getMimetype()}. |
||
265 | * |
||
266 | * @return string |
||
267 | */ |
||
268 | public function mimetype() |
||
272 | |||
273 | /** |
||
274 | * Extract the MIME type from the given file. |
||
275 | * |
||
276 | * @uses finfo |
||
277 | * @param string $file The file to check. |
||
278 | * @return string|false Returns the given file's MIME type or FALSE if an error occurred. |
||
279 | */ |
||
280 | public function getMimetypeFor($file) |
||
286 | |||
287 | /** |
||
288 | * Alias of {@see self::getMimetypeFor()}. |
||
289 | * |
||
290 | * @param string $file The file to check. |
||
291 | * @return string|false |
||
292 | */ |
||
293 | public function mimetypeFor($file) |
||
297 | |||
298 | /** |
||
299 | * Set the maximium size accepted for an uploaded files. |
||
300 | * |
||
301 | * @param string|integer $size The maximum file size allowed, in bytes. |
||
302 | * @throws InvalidArgumentException If the size argument is not an integer. |
||
303 | * @return FileProperty Chainable |
||
304 | */ |
||
305 | public function setMaxFilesize($size) |
||
311 | |||
312 | /** |
||
313 | * Retrieve the maximum size accepted for uploaded files. |
||
314 | * |
||
315 | * If null or 0, then no limit. Defaults to 128 MB. |
||
316 | * |
||
317 | * @return integer |
||
318 | */ |
||
319 | public function getMaxFilesize() |
||
327 | |||
328 | /** |
||
329 | * Retrieve the maximum size (in bytes) allowed for an uploaded file |
||
330 | * as configured in {@link http://php.net/manual/en/ini.php `php.ini`}. |
||
331 | * |
||
332 | * @param string|null $iniDirective If $iniDirective is provided, then it is filled with |
||
333 | * the name of the PHP INI directive corresponding to the maximum size allowed. |
||
334 | * @return integer |
||
335 | */ |
||
336 | public function maxFilesizeAllowedByPhp(&$iniDirective = null) |
||
351 | |||
352 | /** |
||
353 | * @param integer $size The file size, in bytes. |
||
354 | * @throws InvalidArgumentException If the size argument is not an integer. |
||
355 | * @return FileProperty Chainable |
||
356 | */ |
||
357 | public function setFilesize($size) |
||
368 | |||
369 | /** |
||
370 | * @return integer |
||
371 | */ |
||
372 | public function getFilesize() |
||
385 | |||
386 | /** |
||
387 | * Alias of {@see self::getFilesize()}. |
||
388 | * |
||
389 | * @return integer |
||
390 | */ |
||
391 | public function filesize() |
||
395 | |||
396 | /** |
||
397 | * @return array |
||
398 | */ |
||
399 | public function validationMethods() |
||
408 | |||
409 | /** |
||
410 | * @return boolean |
||
411 | */ |
||
412 | public function validateAcceptedMimetypes() |
||
442 | |||
443 | /** |
||
444 | * @return boolean |
||
445 | */ |
||
446 | public function validateMaxFilesize() |
||
462 | |||
463 | /** |
||
464 | * Get the SQL type (Storage format) |
||
465 | * |
||
466 | * Stored as `VARCHAR` for max_length under 255 and `TEXT` for other, longer strings |
||
467 | * |
||
468 | * @see StorablePropertyTrait::sqlType() |
||
469 | * @return string The SQL type |
||
470 | */ |
||
471 | public function sqlType() |
||
480 | |||
481 | /** |
||
482 | * @see StorablePropertyTrait::sqlPdoType() |
||
483 | * @return integer |
||
484 | */ |
||
485 | public function sqlPdoType() |
||
489 | |||
490 | /** |
||
491 | * Process file uploads {@see AbstractProperty::save() parsing values}. |
||
492 | * |
||
493 | * @param mixed $val The value, at time of saving. |
||
494 | * @return mixed |
||
495 | */ |
||
496 | public function save($val) |
||
540 | |||
541 | /** |
||
542 | * Process and transfer any data URIs to the filesystem, |
||
543 | * and carry over any pre-processed file paths. |
||
544 | * |
||
545 | * @param mixed $values One or more data URIs, data entries, or processed file paths. |
||
546 | * @return string|string[] One or more paths to the processed uploaded files. |
||
547 | */ |
||
548 | protected function saveDataUploads($values) |
||
569 | |||
570 | /** |
||
571 | * Process and transfer any uploaded files to the filesystem. |
||
572 | * |
||
573 | * @param mixed $files One or more normalized $_FILE entries. |
||
574 | * @return string[] One or more paths to the processed uploaded files. |
||
575 | */ |
||
576 | protected function saveFileUploads($files) |
||
595 | |||
596 | /** |
||
597 | * Finalize any processed files. |
||
598 | * |
||
599 | * @param mixed $saved One or more values, at time of saving. |
||
600 | * @param mixed $default The default value to return. |
||
601 | * @return string|string[] One or more paths to the processed uploaded files. |
||
602 | */ |
||
603 | protected function parseSavedValues($saved, $default = null) |
||
619 | |||
620 | /** |
||
621 | * Upload to filesystem, from data URI. |
||
622 | * |
||
623 | * @param mixed $data A data URI. |
||
624 | * @throws Exception If data content decoding fails. |
||
625 | * @throws InvalidArgumentException If the $data is invalid. |
||
626 | * @return string|null The file path to the uploaded data. |
||
627 | */ |
||
628 | public function dataUpload($data) |
||
688 | |||
689 | /** |
||
690 | * Upload to filesystem. |
||
691 | * |
||
692 | * @link https://github.com/slimphp/Slim/blob/3.12.1/Slim/Http/UploadedFile.php |
||
693 | * Adapted from slim/slim. |
||
694 | * |
||
695 | * @param array $file A single $_FILES entry. |
||
696 | * @throws InvalidArgumentException If the $file is invalid. |
||
697 | * @return string|null The file path to the uploaded file. |
||
698 | */ |
||
699 | public function fileUpload(array $file) |
||
762 | |||
763 | /** |
||
764 | * @param string $filename Optional. The filename to save. If unset, a default filename will be generated. |
||
765 | * @throws Exception If the target path is not writeable. |
||
766 | * @return string |
||
767 | */ |
||
768 | public function uploadTarget($filename = null) |
||
803 | |||
804 | /** |
||
805 | * Checks whether a file or directory exists. |
||
806 | * |
||
807 | * PHP built-in's `file_exists` is only case-insensitive on case-insensitive filesystem (such as Windows) |
||
808 | * This method allows to have the same validation across different platforms / filesystem. |
||
809 | * |
||
810 | * @param string $file The full file to check. |
||
811 | * @param boolean $caseInsensitive Case-insensitive by default. |
||
812 | * @return boolean |
||
813 | */ |
||
814 | public function fileExists($file, $caseInsensitive = true) |
||
840 | |||
841 | /** |
||
842 | * Sanitize a filename by removing characters from a blacklist and escaping dot. |
||
843 | * |
||
844 | * @param string $filename The filename to sanitize. |
||
845 | * @return string The sanitized filename. |
||
846 | */ |
||
847 | public function sanitizeFilename($filename) |
||
858 | |||
859 | /** |
||
860 | * Render the given file to the given pattern. |
||
861 | * |
||
862 | * This method does not rename the given path. |
||
863 | * |
||
864 | * @uses strtr() To replace tokens in the form `{{foobar}}`. |
||
865 | * @param string $from The string being rendered. |
||
866 | * @param string $to The pattern replacing $from. |
||
867 | * @param array|callable $args Extra rename tokens. |
||
868 | * @throws InvalidArgumentException If the given arguments are invalid. |
||
869 | * @throws UnexpectedValueException If the renaming failed. |
||
870 | * @return string Returns the rendered target. |
||
871 | */ |
||
872 | public function renderFileRenamePattern($from, $to, $args = null) |
||
905 | |||
906 | /** |
||
907 | * Generate a new filename from the property. |
||
908 | * |
||
909 | * @return string |
||
910 | */ |
||
911 | public function generateFilename() |
||
922 | |||
923 | /** |
||
924 | * Generate a unique filename. |
||
925 | * |
||
926 | * @param string|array $filename The filename to alter. |
||
927 | * @throws InvalidArgumentException If the given filename is invalid. |
||
928 | * @return string |
||
929 | */ |
||
930 | public function generateUniqueFilename($filename) |
||
953 | |||
954 | /** |
||
955 | * Generate the file extension from the property's value. |
||
956 | * |
||
957 | * @param string $file The file to parse. |
||
958 | * @return string The extension based on the MIME type. |
||
959 | */ |
||
960 | public function generateExtension($file = null) |
||
985 | |||
986 | /** |
||
987 | * @return string |
||
988 | */ |
||
989 | public function getFilesystem() |
||
993 | |||
994 | /** |
||
995 | * @param string $filesystem The file system. |
||
996 | * @return self |
||
997 | */ |
||
998 | public function setFilesystem($filesystem) |
||
1004 | |||
1005 | /** |
||
1006 | * Inject dependencies from a DI Container. |
||
1007 | * |
||
1008 | * @param Container $container A dependencies container instance. |
||
1009 | * @return void |
||
1010 | */ |
||
1011 | protected function setDependencies(Container $container) |
||
1018 | /** |
||
1019 | * Retrieve the path to the storage directory. |
||
1020 | * |
||
1021 | * @return string |
||
1022 | */ |
||
1023 | protected function basePath() |
||
1031 | |||
1032 | /** |
||
1033 | * Converts a php.ini notation for size to an integer. |
||
1034 | * |
||
1035 | * @param mixed $size A php.ini notation for size. |
||
1036 | * @throws InvalidArgumentException If the given parameter is invalid. |
||
1037 | * @return integer Returns the size in bytes. |
||
1038 | */ |
||
1039 | protected function parseIniSize($size) |
||
1061 | |||
1062 | /** |
||
1063 | * Determine if the given file path is am absolute path. |
||
1064 | * |
||
1065 | * Note: Adapted from symfony\filesystem. |
||
1066 | * |
||
1067 | * @see https://github.com/symfony/symfony/blob/v3.2.2/LICENSE |
||
1068 | * |
||
1069 | * @param string $file A file path. |
||
1070 | * @return boolean Returns TRUE if the given path is absolute. Otherwise, returns FALSE. |
||
1071 | */ |
||
1072 | protected function isAbsolutePath($file) |
||
1081 | |||
1082 | /** |
||
1083 | * Determine if the given value is a data URI. |
||
1084 | * |
||
1085 | * @param mixed $val The value to check. |
||
1086 | * @return boolean |
||
1087 | */ |
||
1088 | protected function isDataUri($val) |
||
1092 | |||
1093 | /** |
||
1094 | * Determine if the given value is a data array. |
||
1095 | * |
||
1096 | * @param mixed $val The value to check. |
||
1097 | * @return boolean |
||
1098 | */ |
||
1099 | protected function isDataArr($val) |
||
1103 | |||
1104 | /** |
||
1105 | * Retrieve the rename pattern tokens for the given file. |
||
1106 | * |
||
1107 | * @param string|array $path The string to be parsed or an associative array of information about the file. |
||
1108 | * @param array|callable $args Extra rename tokens. |
||
1109 | * @throws InvalidArgumentException If the given arguments are invalid. |
||
1110 | * @throws UnexpectedValueException If the given path is invalid. |
||
1111 | * @return string Returns the rendered target. |
||
1112 | */ |
||
1113 | private function renamePatternArgs($path, $args = null) |
||
1174 | |||
1175 | /** |
||
1176 | * Retrieve normalized file upload data for this property. |
||
1177 | * |
||
1178 | * @return array A tree of normalized $_FILE entries. |
||
1179 | */ |
||
1180 | public function getUploadedFiles() |
||
1191 | |||
1192 | /** |
||
1193 | * Parse a non-normalized, i.e. $_FILES superglobal, tree of uploaded file data. |
||
1194 | * |
||
1195 | * @link https://github.com/slimphp/Slim/blob/3.12.1/Slim/Http/UploadedFile.php |
||
1196 | * Adapted from slim/slim. |
||
1197 | * |
||
1198 | * @todo Add support for "dot" notation on $searchKey. |
||
1199 | * |
||
1200 | * @param array $uploadedFiles The non-normalized tree of uploaded file data. |
||
1201 | * @param callable $filterCallback If specified, the callback function to used to filter files. |
||
1202 | * @param mixed $searchKey If specified, then only top-level keys containing these values are returned. |
||
1203 | * @return array A tree of normalized $_FILE entries. |
||
1204 | */ |
||
1205 | public static function parseUploadedFiles(array $uploadedFiles, callable $filterCallback = null, $searchKey = null) |
||
1282 | } |
||
1283 |
This method has been deprecated.