Complex classes like DataPath 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 DataPath, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class DataPath extends AbstractComponent implements DataPathInterface |
||
28 | { |
||
29 | use PathTrait; |
||
30 | |||
31 | const DEFAULT_MIMETYPE = 'text/plain'; |
||
32 | |||
33 | const DEFAULT_PARAMETER = 'charset=us-ascii'; |
||
34 | |||
35 | const BINARY_PARAMETER = 'base64'; |
||
36 | |||
37 | const REGEXP_MIMETYPE = ',^\w+/[-.\w]+(?:\+[-.\w]+)?$,'; |
||
38 | |||
39 | /** |
||
40 | * The mediatype mimetype |
||
41 | * |
||
42 | * @var string |
||
43 | */ |
||
44 | protected $mimetype; |
||
45 | |||
46 | /** |
||
47 | * The mediatype parameters |
||
48 | * |
||
49 | * @var string[] |
||
50 | */ |
||
51 | protected $parameters; |
||
52 | |||
53 | /** |
||
54 | * Is the Document bas64 encoded |
||
55 | * |
||
56 | * @var bool |
||
57 | */ |
||
58 | protected $isBinaryData; |
||
59 | |||
60 | /** |
||
61 | * The document string representation |
||
62 | * |
||
63 | * @var string |
||
64 | */ |
||
65 | protected $document; |
||
66 | |||
67 | /** |
||
68 | * @inheritdoc |
||
69 | */ |
||
70 | protected static $characters_set = [ |
||
71 | '/', ':', '@', '!', '$', '&', "'", '%', |
||
72 | '(', ')', '*', '+', ',', ';', '=', '?', |
||
73 | ]; |
||
74 | |||
75 | /** |
||
76 | * @inheritdoc |
||
77 | */ |
||
78 | protected static $characters_set_encoded = [ |
||
79 | '%2F', '%3A', '%40', '%21', '%24', '%26', '%27', '%25', |
||
80 | '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D', '%3F', |
||
81 | ]; |
||
82 | |||
83 | /** |
||
84 | * @inheritdoc |
||
85 | */ |
||
86 | protected static $invalidCharactersRegex = ',[?#],'; |
||
87 | |||
88 | /** |
||
89 | * new instance |
||
90 | * |
||
91 | * @param string $path the component value |
||
92 | */ |
||
93 | 84 | public function __construct($path = '') |
|
94 | { |
||
95 | 84 | $path = $this->validateString($path); |
|
96 | 84 | if ('' === $path) { |
|
97 | 2 | $path = static::DEFAULT_MIMETYPE.';'.static::DEFAULT_PARAMETER.','; |
|
98 | 2 | } |
|
99 | 84 | $this->setComponentProperties($path); |
|
100 | 68 | } |
|
101 | |||
102 | /** |
||
103 | * Set Data Path properties |
||
104 | * |
||
105 | * @param string $path |
||
106 | */ |
||
107 | 84 | protected function setComponentProperties($path) |
|
108 | { |
||
109 | 84 | $this->assertValidComponent($path); |
|
110 | 74 | $parts = explode(',', $path, 2); |
|
111 | 74 | $mediatype = array_shift($parts); |
|
112 | 74 | $this->document = (string) array_shift($parts); |
|
113 | 74 | $mimetype = static::DEFAULT_MIMETYPE; |
|
114 | 74 | $parameters = static::DEFAULT_PARAMETER; |
|
115 | 74 | if ('' !== $mediatype) { |
|
116 | 68 | $mediatype = explode(';', $mediatype, 2); |
|
117 | 68 | $mimetype = array_shift($mediatype); |
|
118 | 68 | $parameters = (string) array_shift($mediatype); |
|
119 | 68 | } |
|
120 | 74 | $this->mimetype = $this->filterMimeType($mimetype); |
|
121 | 72 | $this->parameters = $this->filterParameters($parameters); |
|
122 | 70 | if ($this->isBinaryData) { |
|
123 | 38 | $this->validateDocument(); |
|
124 | 36 | } |
|
125 | 68 | } |
|
126 | |||
127 | /** |
||
128 | * @inheritdoc |
||
129 | */ |
||
130 | 84 | protected function assertValidComponent($path) |
|
131 | { |
||
132 | 84 | parent::assertValidComponent($path); |
|
133 | 84 | if (!mb_detect_encoding($path, 'US-ASCII', true) |
|
134 | 84 | || false === strpos($path, ',') |
|
135 | 80 | || false !== strpos($path, '\n') |
|
136 | 84 | ) { |
|
137 | 10 | throw new InvalidArgumentException( |
|
138 | 10 | sprintf('The submitted path `%s` is invalid according to RFC2937', $path) |
|
139 | 10 | ); |
|
140 | } |
||
141 | 74 | } |
|
142 | |||
143 | /** |
||
144 | * Filter the mimeType property |
||
145 | * |
||
146 | * @param string $mimetype |
||
147 | * |
||
148 | * @throws InvalidArgumentException If the mimetype is invalid |
||
149 | * |
||
150 | * @return string |
||
151 | */ |
||
152 | 74 | protected function filterMimeType($mimetype) |
|
153 | { |
||
154 | 74 | if (!preg_match(static::REGEXP_MIMETYPE, $mimetype)) { |
|
155 | 2 | throw new InvalidArgumentException(sprintf('invalid mimeType, `%s`', $mimetype)); |
|
156 | } |
||
157 | |||
158 | 72 | return $mimetype; |
|
159 | } |
||
160 | |||
161 | /** |
||
162 | * Extract and set the binary flag from the parameters if it exists |
||
163 | * |
||
164 | * @param string $parameters |
||
165 | * |
||
166 | * @throws InvalidArgumentException If the mediatype parameters contain invalid data |
||
167 | * |
||
168 | * @return string[] |
||
169 | */ |
||
170 | 72 | protected function filterParameters($parameters) |
|
189 | |||
190 | /** |
||
191 | * Validate mediatype parameter |
||
192 | * |
||
193 | * @param string $parameter a mediatype parameter |
||
194 | * |
||
195 | * @return bool |
||
196 | */ |
||
197 | 66 | protected function validateParameter($parameter) |
|
203 | |||
204 | /** |
||
205 | * Validate the path document string representation |
||
206 | * |
||
207 | * @throws InvalidArgumentException If the data is invalid |
||
208 | */ |
||
209 | 38 | protected function validateDocument() |
|
216 | |||
217 | /** |
||
218 | * Retrieves the data string. |
||
219 | * |
||
220 | 12 | * Retrieves the data part of the path. If no data part is provided return |
|
221 | * a empty string |
||
222 | 12 | * |
|
223 | * @return string |
||
224 | */ |
||
225 | public function getData() |
||
229 | |||
230 | 18 | /** |
|
231 | * Tells whether the data is binary safe encoded |
||
232 | * |
||
233 | * @return bool |
||
234 | */ |
||
235 | public function isBinaryData() |
||
239 | |||
240 | /** |
||
241 | * Retrieve the data mime type associated to the URI. |
||
242 | * |
||
243 | * If no mimetype is present, this method MUST return the default mimetype 'text/plain'. |
||
244 | 60 | * |
|
245 | * @see http://tools.ietf.org/html/rfc2397#section-2 |
||
246 | 60 | * |
|
247 | * @return string The URI scheme. |
||
248 | */ |
||
249 | public function getMimeType() |
||
253 | |||
254 | 10 | /** |
|
255 | * Retrieve the parameters associated with the Mime Type of the URI. |
||
256 | * |
||
257 | * If no parameters is present, this method MUST return the default parameter 'charset=US-ASCII'. |
||
258 | * |
||
259 | * @see http://tools.ietf.org/html/rfc2397#section-2 |
||
260 | 6 | * |
|
261 | * @return string The URI scheme. |
||
262 | 6 | */ |
|
263 | 4 | public function getParameters() |
|
267 | |||
268 | /** |
||
269 | * Retrieve the mediatype associated with the URI. |
||
270 | * |
||
271 | * If no mediatype is present, this method MUST return the default parameter 'text/plain;charset=US-ASCII'. |
||
272 | 36 | * |
|
273 | * @see http://tools.ietf.org/html/rfc2397#section-3 |
||
274 | 36 | * |
|
275 | * @return string The URI scheme. |
||
276 | */ |
||
277 | public function getMediaType() |
||
281 | |||
282 | 44 | /** |
|
283 | 44 | * Save the data to a specific file |
|
284 | 44 | * |
|
285 | 44 | * @param string $path The path to the file where to save the data |
|
286 | 44 | * @param string $mode The mode parameter specifies the type of access you require to the stream. |
|
287 | 44 | * |
|
288 | * @throws RuntimeException if the path is not reachable |
||
289 | * |
||
290 | * @return SplFileObject |
||
291 | */ |
||
292 | public function save($path, $mode = 'w') |
||
300 | 66 | ||
301 | /** |
||
302 | 66 | * Returns the instance string representation |
|
303 | 54 | * with its optional URI delimiters |
|
304 | 54 | * |
|
305 | * @return string |
||
306 | 66 | */ |
|
307 | 38 | public function getUriComponent() |
|
311 | |||
312 | /** |
||
313 | * Returns the instance string representation; If the |
||
314 | * instance is not defined an empty string is returned |
||
315 | * |
||
316 | 8 | * @return string |
|
317 | */ |
||
318 | 8 | public function __toString() |
|
327 | 6 | ||
328 | /** |
||
329 | * Format the DataURI string |
||
330 | * |
||
331 | * @param string $mimetype |
||
332 | * @param string $parameters |
||
333 | 8 | * @param bool $isBinaryData |
|
334 | * @param string $data |
||
335 | 8 | * |
|
336 | 2 | * @return string |
|
337 | */ |
||
338 | protected static function format($mimetype, $parameters, $isBinaryData, $data) |
||
350 | 14 | ||
351 | /** |
||
352 | 14 | * Returns an instance where the data part is base64 encoded |
|
353 | 2 | * |
|
354 | * This method MUST retain the state of the current instance, and return |
||
355 | * an instance where the data part is base64 encoded |
||
356 | 12 | * |
|
357 | 2 | * @return static |
|
358 | */ |
||
359 | public function toBinary() |
||
372 | |||
373 | /** |
||
374 | * Returns an instance where the data part is url encoded following RFC3986 rules |
||
375 | * |
||
376 | * This method MUST retain the state of the current instance, and return |
||
377 | 34 | * an instance where the data part is url encoded |
|
378 | * |
||
379 | 34 | * @return static |
|
380 | 12 | */ |
|
381 | public function toAscii() |
||
394 | |||
395 | /** |
||
396 | * @inheritdoc |
||
397 | */ |
||
398 | public static function __set_state(array $properties) |
||
407 | |||
408 | /** |
||
409 | * Return an instance with the specified mediatype parameters. |
||
410 | * |
||
411 | * This method MUST retain the state of the current instance, and return |
||
412 | * an instance that contains the specified mediatype parameters. |
||
413 | * |
||
414 | * Users must provide encoded characters. |
||
415 | * |
||
416 | * An empty parameters value is equivalent to removing the parameter. |
||
417 | * |
||
418 | * @param string $parameters The mediatype parameters to use with the new instance. |
||
419 | * |
||
420 | * @throws InvalidArgumentException for invalid query strings. |
||
421 | * |
||
422 | * @return static A new instance with the specified mediatype parameters. |
||
423 | */ |
||
424 | public function withParameters($parameters) |
||
441 | |||
442 | /** |
||
443 | * Create a new instance from a file path |
||
444 | * |
||
445 | * @param string $path |
||
446 | * |
||
447 | * @throws RuntimeException If the File is not readable |
||
448 | * |
||
449 | * @return static |
||
450 | */ |
||
451 | public static function createFromPath($path) |
||
464 | } |
||
465 |