Complex classes like ExposeFields 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 ExposeFields, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | class ExposeFields implements \Iterator |
||
27 | { |
||
28 | /** |
||
29 | * Current iteration position |
||
30 | * @var integer $position |
||
31 | */ |
||
32 | private $position = 0; |
||
33 | |||
34 | /** |
||
35 | * Expose fields to be used - multidimensional array |
||
36 | * @var array $fields |
||
37 | */ |
||
38 | private $fields; |
||
39 | |||
40 | /** |
||
41 | * The matched route |
||
42 | * @var RouteMetaData $route |
||
43 | */ |
||
44 | protected $route; |
||
45 | |||
46 | /** |
||
47 | * The route expose array - If explicitly set it overrides any default config settings |
||
48 | * @var array $route_expose |
||
49 | */ |
||
50 | protected $route_expose; |
||
51 | |||
52 | /** |
||
53 | * An array of classes that are registered on default expose depth. |
||
54 | * Temporary used during processExposeDepth to prevent you traversing up and down bi-directional relations |
||
55 | * @var array $registered_expose_classes ; |
||
56 | */ |
||
57 | protected $registered_expose_classes = []; |
||
58 | |||
59 | /** |
||
60 | * Create an instance of ExposeFields - use create() method |
||
61 | * @param RouteMetaData $route - requires a matched route |
||
62 | */ |
||
63 | 30 | private function __construct(RouteMetaData $route) |
|
68 | |||
69 | /** |
||
70 | * Create an instance of ExposeFields |
||
71 | * @param RouteMetaData $route - requires a matched route |
||
72 | * @return \Drest\Query\ExposeFields |
||
73 | */ |
||
74 | 30 | public static function create(RouteMetaData $route) |
|
78 | |||
79 | /** |
||
80 | * Set the default exposure fields using the configured exposure depth |
||
81 | * @param EntityManagerRegistry $emr |
||
82 | * @param integer $exposureDepth |
||
83 | * @param integer $exposureRelationsFetchType |
||
84 | * @return ExposeFields $this object instance |
||
85 | */ |
||
86 | 22 | public function configureExposeDepth(EntityManagerRegistry $emr, $exposureDepth = 0, $exposureRelationsFetchType = null) |
|
102 | |||
103 | /** |
||
104 | * Configure the expose object to filter out fields that are not allowed to be use by the client. |
||
105 | * Unlike the configuring of the Pull request, this function will return the formatted array in a ResultSet object |
||
106 | * This is only applicable for a HTTP push (POST/PUT/PATCH) call |
||
107 | * @param array $pushed - the data push on the request |
||
108 | * @throws \Drest\DrestException |
||
109 | * @return \DrestCommon\ResultSet |
||
110 | * |
||
111 | * @todo: this should follow the same pattern as configurePullRequest |
||
112 | */ |
||
113 | 3 | public function configurePushRequest($pushed) |
|
127 | |||
128 | /** |
||
129 | * Filter out requested expose fields against what's allowed |
||
130 | * @param array $requested - The requested expose definition |
||
131 | * @param array $actual - current allowed expose definition |
||
132 | * @return array $request - The requested expose data with non-allowed data stripped off |
||
133 | */ |
||
134 | 3 | protected function filterPushExpose($requested, $actual) |
|
161 | |||
162 | |||
163 | /** |
||
164 | * Configure the expose object to filter out fields that have been explicitly requested by the client. |
||
165 | * This is only applicable for a HTTP pull (GET) call. For configuring |
||
166 | * @param array $requestOptions |
||
167 | * @param Request $request |
||
168 | * @return ExposeFields $this object instance |
||
169 | */ |
||
170 | 20 | public function configurePullRequest(array $requestOptions, Request $request) |
|
199 | |||
200 | |||
201 | /** |
||
202 | * An awesome solution was posted on (link below) to parse these using a regex |
||
203 | * http://stackoverflow.com/questions/16415558/regex-top-level-contents-from-a-string |
||
204 | * |
||
205 | * preg_match_all( |
||
206 | * '/(?<=\[) # Assert that the previous characters is a [ |
||
207 | * (?: # Match either... |
||
208 | * [^[\]]* # any number of characters except brackets |
||
209 | * | # or |
||
210 | * \[ # an opening bracket |
||
211 | * (?R) # containing a match of this very regex |
||
212 | * \] # followed by a closing bracket |
||
213 | * )* # Repeat as needed |
||
214 | * (?=\]) # Assert the next character is a ]/x', |
||
215 | * $string, $result, PREG_PATTERN_ORDER); |
||
216 | * |
||
217 | * @todo: Adapt the parser to use the regex above (will also need alter it to grab parent keys) |
||
218 | * |
||
219 | * Parses an expose string into an array |
||
220 | * Example: "username|email_address|profile[id|lastname|addresses[id]]|phone_numbers" |
||
221 | * @param string $string |
||
222 | * @return array $result |
||
223 | * @throws InvalidExposeFieldsException - if any syntax error occurs, or unable to parse the string |
||
224 | */ |
||
225 | 6 | protected function parseExposeString($string) |
|
237 | |||
238 | /** |
||
239 | * Recursively process the passed expose string |
||
240 | * @param string $string - the string to be processed |
||
241 | * @param array $results - passed by reference |
||
242 | * @throws InvalidExposeFieldsException if unable to correctly parse the square brackets. |
||
243 | */ |
||
244 | 5 | protected function recurseExposeString($string, &$results) |
|
267 | |||
268 | /** |
||
269 | * Get information on parsed (top-level) brackets |
||
270 | * @param string $string |
||
271 | * @return \stdClass $information contains parse information object containing a $parts array eg array( |
||
272 | * 'openBracket' => xx, - The position of the open bracket |
||
273 | * 'closeBracket' => xx - The position of the close bracket |
||
274 | * 'contents' => xx - The contents of the bracket |
||
275 | * 'tagName' => xx - The name of the accompanying tag |
||
276 | * ) |
||
277 | */ |
||
278 | 4 | private function parseStringParts($string) |
|
335 | |||
336 | /** |
||
337 | * Filter out requested expose fields against what's allowed |
||
338 | * @param array $requested - The requested expose definition - invalid / not allowed data is stripped off |
||
339 | * @param array $actual - current allowed expose definition |
||
340 | */ |
||
341 | 1 | protected function filterRequestedExpose(&$requested, &$actual) |
|
366 | |||
367 | /** |
||
368 | * Recursive function to generate default expose columns |
||
369 | * |
||
370 | * @param array $fields - array to be populated recursively (referenced) |
||
371 | * @param string $class - name of the class to process |
||
372 | * @param EntityManagerRegistry $emr - entity manager registry used to fetch class information |
||
373 | * @param integer $depth - maximum depth you want to travel through the relations |
||
374 | * @param integer $fetchType - The fetch type to be used |
||
375 | * @param integer|null $fetchType - The required fetch type of the relation |
||
376 | */ |
||
377 | 5 | protected function processExposeDepth(&$fields, $class, EntityManagerRegistry $emr, $depth = 0, $fetchType = null) |
|
404 | |||
405 | /** |
||
406 | * Get the expose fields |
||
407 | * @return array $fields |
||
408 | */ |
||
409 | 21 | public function toArray() |
|
417 | |||
418 | public function current() |
||
422 | |||
423 | public function key() |
||
427 | |||
428 | public function next() |
||
432 | |||
433 | public function rewind() |
||
437 | |||
438 | public function valid() |
||
442 | |||
443 | } |
||
444 |