Complex classes like QueryParser 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 QueryParser, and based on these observations, apply Extract Interface, too.
1 | <?php namespace Limoncello\Flute\Validation\JsonApi; |
||
48 | class QueryParser implements JsonApiQueryValidatingParserInterface |
||
49 | { |
||
50 | use BaseQueryParserTrait { |
||
51 | BaseQueryParserTrait::getFields as getFieldsImpl; |
||
52 | BaseQueryParserTrait::getIncludes as getIncludesImpl; |
||
53 | BaseQueryParserTrait::getSorts as getSortsImpl; |
||
54 | } |
||
55 | |||
56 | /** Message */ |
||
57 | public const MSG_ERR_INVALID_PARAMETER = 'Invalid Parameter.'; |
||
58 | |||
59 | /** |
||
60 | * @var array |
||
61 | */ |
||
62 | private $parameters; |
||
63 | |||
64 | /** |
||
65 | * @var string[]|null |
||
66 | */ |
||
67 | private $messages; |
||
68 | |||
69 | /** |
||
70 | * @var array |
||
71 | */ |
||
72 | private $filterParameters; |
||
73 | |||
74 | /** |
||
75 | * @var bool |
||
76 | */ |
||
77 | private $areFiltersWithAnd; |
||
78 | |||
79 | /** |
||
80 | * @var int|null |
||
81 | */ |
||
82 | private $pagingOffset; |
||
83 | |||
84 | /** |
||
85 | * @var int|null |
||
86 | */ |
||
87 | private $pagingLimit; |
||
88 | |||
89 | /** |
||
90 | * NOTE: Despite the type it is just a string so only static methods can be called from the interface. |
||
91 | * |
||
92 | * @var JsonApiQueryRulesSerializerInterface|string |
||
93 | */ |
||
94 | private $serializerClass; |
||
95 | |||
96 | /** |
||
97 | * @var array |
||
98 | */ |
||
99 | private $serializedRuleSet; |
||
100 | |||
101 | /** |
||
102 | * @var array |
||
103 | */ |
||
104 | private $validationBlocks; |
||
105 | |||
106 | /** |
||
107 | * @var ContextStorageInterface |
||
108 | */ |
||
109 | private $context; |
||
110 | |||
111 | /** |
||
112 | * @var CaptureAggregatorInterface |
||
113 | */ |
||
114 | private $captures; |
||
115 | |||
116 | /** |
||
117 | * @var ErrorAggregatorInterface |
||
118 | */ |
||
119 | private $validationErrors; |
||
120 | |||
121 | /** |
||
122 | * @var JsonApiErrorCollection |
||
123 | */ |
||
124 | private $jsonErrors; |
||
125 | |||
126 | /** |
||
127 | * @var null|array |
||
128 | */ |
||
129 | private $cachedFilters = null; |
||
130 | |||
131 | /** |
||
132 | * @var null|array |
||
133 | */ |
||
134 | private $cachedFields = null; |
||
135 | |||
136 | /** |
||
137 | * @var null|array |
||
138 | */ |
||
139 | private $cachedSorts = null; |
||
140 | |||
141 | /** |
||
142 | * @var null|array |
||
143 | */ |
||
144 | private $cachedIncludes = null; |
||
145 | |||
146 | /** |
||
147 | * @var FormatterFactoryInterface |
||
148 | */ |
||
149 | private $formatterFactory; |
||
150 | |||
151 | /** |
||
152 | * @var FormatterInterface|null |
||
153 | */ |
||
154 | private $formatter; |
||
155 | |||
156 | /** |
||
157 | * @param string $rulesClass |
||
158 | * @param string $serializerClass |
||
159 | * @param array $serializedData |
||
160 | * @param ContextStorageInterface $context |
||
161 | * @param CaptureAggregatorInterface $captures |
||
162 | * @param ErrorAggregatorInterface $validationErrors |
||
163 | * @param JsonApiErrorCollection $jsonErrors |
||
164 | * @param FormatterFactoryInterface $formatterFactory |
||
165 | * @param string[]|null $messages |
||
166 | */ |
||
167 | 32 | public function __construct( |
|
198 | |||
199 | /** |
||
200 | * @inheritdoc |
||
201 | */ |
||
202 | 31 | public function parse(array $parameters): JsonApiQueryValidatingParserInterface |
|
212 | |||
213 | /** |
||
214 | * @inheritdoc |
||
215 | */ |
||
216 | 17 | public function areFiltersWithAnd(): bool |
|
220 | |||
221 | /** |
||
222 | * @inheritdoc |
||
223 | */ |
||
224 | 1 | public function hasFilters(): bool |
|
228 | |||
229 | /** |
||
230 | * @inheritdoc |
||
231 | */ |
||
232 | 14 | public function hasFields(): bool |
|
236 | |||
237 | /** |
||
238 | * @inheritdoc |
||
239 | */ |
||
240 | 14 | public function hasIncludes(): bool |
|
244 | |||
245 | /** |
||
246 | * @inheritdoc |
||
247 | */ |
||
248 | 1 | public function hasSorts(): bool |
|
252 | |||
253 | /** |
||
254 | * @inheritdoc |
||
255 | */ |
||
256 | 1 | public function hasPaging(): bool |
|
260 | |||
261 | /** |
||
262 | * @inheritdoc |
||
263 | */ |
||
264 | 22 | public function getFilters(): array |
|
272 | |||
273 | /** |
||
274 | * @inheritdoc |
||
275 | */ |
||
276 | 2 | public function getFields(): array |
|
285 | |||
286 | /** |
||
287 | * @inheritdoc |
||
288 | */ |
||
289 | 16 | public function getSorts(): array |
|
298 | |||
299 | /** |
||
300 | * @inheritdoc |
||
301 | */ |
||
302 | 16 | public function getIncludes(): iterable |
|
311 | |||
312 | /** |
||
313 | * @inheritdoc |
||
314 | */ |
||
315 | 17 | public function getPagingOffset(): ?int |
|
319 | |||
320 | /** |
||
321 | * @inheritdoc |
||
322 | */ |
||
323 | 17 | public function getPagingLimit(): ?int |
|
327 | |||
328 | /** |
||
329 | * @param array $parameters |
||
330 | * |
||
331 | * @return self |
||
332 | */ |
||
333 | 32 | protected function setParameters(array $parameters): self |
|
339 | |||
340 | /** |
||
341 | * @return array |
||
342 | */ |
||
343 | 31 | protected function getParameters(): array |
|
347 | |||
348 | /** |
||
349 | * @param array $messages |
||
350 | * |
||
351 | * @return self |
||
352 | */ |
||
353 | 32 | protected function setMessages(?array $messages): self |
|
359 | |||
360 | /** |
||
361 | * @param string $message |
||
362 | * |
||
363 | * @return string |
||
364 | */ |
||
365 | 25 | protected function getMessage(string $message): string |
|
371 | |||
372 | /** |
||
373 | * @return JsonApiErrorCollection |
||
374 | */ |
||
375 | 6 | protected function getJsonErrors(): JsonApiErrorCollection |
|
379 | |||
380 | /** |
||
381 | * @return ErrorAggregatorInterface |
||
382 | */ |
||
383 | 32 | protected function getValidationErrors(): ErrorAggregatorInterface |
|
387 | |||
388 | /** |
||
389 | * @return CaptureAggregatorInterface |
||
390 | */ |
||
391 | 32 | protected function getCaptures(): CaptureAggregatorInterface |
|
395 | |||
396 | /** |
||
397 | * @return ContextStorageInterface |
||
398 | */ |
||
399 | 30 | protected function getContext(): ContextStorageInterface |
|
403 | |||
404 | /** |
||
405 | * @return array |
||
406 | */ |
||
407 | 30 | protected function getValidationBlocks(): array |
|
411 | |||
412 | /** |
||
413 | * @return array |
||
414 | */ |
||
415 | 31 | protected function getSerializedRuleSet(): array |
|
419 | |||
420 | /** |
||
421 | * @return FormatterFactoryInterface |
||
422 | */ |
||
423 | 1 | protected function getFormatterFactory(): FormatterFactoryInterface |
|
427 | |||
428 | /** |
||
429 | * @return FormatterInterface |
||
430 | */ |
||
431 | 1 | protected function getFormatter(): FormatterInterface |
|
439 | |||
440 | /** |
||
441 | * @param string $name |
||
442 | * |
||
443 | * @return bool |
||
444 | */ |
||
445 | 17 | protected function hasParameter(string $name): bool |
|
449 | |||
450 | /** |
||
451 | * @return iterable |
||
452 | * |
||
453 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
454 | */ |
||
455 | 22 | private function getValidatedFilters(): iterable |
|
494 | |||
495 | /** |
||
496 | * @param iterable $fieldsFromParent |
||
497 | * |
||
498 | * @return iterable |
||
499 | * |
||
500 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
501 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
502 | */ |
||
503 | 2 | private function getValidatedFields(iterable $fieldsFromParent): iterable |
|
529 | |||
530 | /** |
||
531 | * @param iterable $sortsFromParent |
||
532 | * |
||
533 | * @return iterable |
||
534 | * |
||
535 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
536 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
537 | */ |
||
538 | 16 | private function getValidatedSorts(iterable $sortsFromParent): iterable |
|
561 | |||
562 | /** |
||
563 | * @param iterable $includesFromParent |
||
564 | * |
||
565 | * @return iterable |
||
566 | * |
||
567 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
568 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
569 | */ |
||
570 | 16 | private function getValidatedIncludes(iterable $includesFromParent): iterable |
|
593 | |||
594 | /** |
||
595 | * @param iterable $iterable |
||
596 | * |
||
597 | * @return array |
||
598 | */ |
||
599 | 25 | private function iterableToArray(iterable $iterable): array |
|
609 | |||
610 | /** |
||
611 | * @param mixed $value |
||
612 | * |
||
613 | * @return int |
||
614 | */ |
||
615 | 31 | private function validatePageOffset($value): int |
|
622 | |||
623 | /** |
||
624 | * @param mixed $value |
||
625 | * |
||
626 | * @return int |
||
627 | */ |
||
628 | 31 | private function validatePageLimit($value): int |
|
635 | |||
636 | /** |
||
637 | * @param mixed $value |
||
638 | * @param array $ruleIndexes |
||
639 | * |
||
640 | * @return int |
||
641 | */ |
||
642 | 31 | private function validatePaginationValue($value, ?array $ruleIndexes): int |
|
659 | |||
660 | /** |
||
661 | * @param string $paramName |
||
662 | * @param array $ruleIndexes |
||
663 | * |
||
664 | * @return void |
||
665 | * |
||
666 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
667 | */ |
||
668 | 30 | private function validationStarts(string $paramName, array $ruleIndexes): void |
|
681 | |||
682 | /** |
||
683 | * @param string $paramName |
||
684 | * @param mixed $value |
||
685 | * @param int $ruleIndex |
||
686 | * |
||
687 | * @return void |
||
688 | * |
||
689 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
690 | */ |
||
691 | 30 | private function validateAndThrowOnError(string $paramName, $value, int $ruleIndex): void |
|
703 | |||
704 | /** |
||
705 | * @param mixed $value |
||
706 | * @param int $ruleIndex |
||
707 | * |
||
708 | * @return bool |
||
709 | * |
||
710 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
711 | */ |
||
712 | 16 | private function validateAndAccumulateError($value, int $ruleIndex): bool |
|
723 | |||
724 | /** |
||
725 | * @param string $paramName |
||
726 | * @param array $ruleIndexes |
||
727 | * |
||
728 | * @return void |
||
729 | * |
||
730 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
731 | */ |
||
732 | 30 | private function validateEnds(string $paramName, array $ruleIndexes): void |
|
742 | |||
743 | /** |
||
744 | * @return mixed |
||
745 | */ |
||
746 | 30 | private function readSingleCapturedValue() |
|
753 | |||
754 | /** |
||
755 | * @param int $ruleIndex |
||
756 | * @param iterable $values |
||
757 | * |
||
758 | * @return iterable |
||
759 | */ |
||
760 | 10 | private function validateValues(int $ruleIndex, iterable $values): iterable |
|
770 | |||
771 | /** |
||
772 | * @param int $ruleIndex |
||
773 | * @param iterable $opsAndArgs |
||
774 | * |
||
775 | * @return iterable |
||
776 | */ |
||
777 | 10 | private function validateFilterArguments(int $ruleIndex, iterable $opsAndArgs): iterable |
|
783 | |||
784 | /** |
||
785 | * @return self |
||
786 | */ |
||
787 | 31 | private function parsePagingParameters(): self |
|
801 | |||
802 | /** |
||
803 | * @param string $paramName |
||
804 | * |
||
805 | * @return void |
||
806 | * |
||
807 | * @throws JsonApiException |
||
808 | */ |
||
809 | 30 | private function checkValidationQueueErrors(string $paramName): void |
|
819 | |||
820 | /** |
||
821 | * @param array $values |
||
822 | * |
||
823 | * @return self |
||
824 | */ |
||
825 | 27 | private function setFilterParameters(array $values): self |
|
831 | |||
832 | /** |
||
833 | * @return array |
||
834 | */ |
||
835 | 22 | private function getFilterParameters(): array |
|
839 | |||
840 | /** |
||
841 | * @return self |
||
842 | */ |
||
843 | 25 | private function setFiltersWithAnd(): self |
|
849 | |||
850 | /** |
||
851 | * @return self |
||
852 | */ |
||
853 | 2 | private function setFiltersWithOr(): self |
|
859 | |||
860 | /** |
||
861 | * @return self |
||
862 | */ |
||
863 | 32 | private function clear(): self |
|
880 | |||
881 | /** |
||
882 | * Pre-parsing for filter parameters. |
||
883 | * |
||
884 | * @return self |
||
885 | * |
||
886 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
887 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||
888 | */ |
||
889 | 31 | private function parseFilterLink(): self |
|
934 | |||
935 | /** |
||
936 | * @param string $parameterName |
||
937 | * @param array $value |
||
938 | * |
||
939 | * @return iterable |
||
940 | * |
||
941 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
942 | */ |
||
943 | 11 | private function parseOperationsAndArguments(string $parameterName, array $value): iterable |
|
966 | |||
967 | /** |
||
968 | * @param string $paramName |
||
969 | * @param string $errorTitle |
||
970 | * |
||
971 | * @return ErrorInterface |
||
972 | */ |
||
973 | 1 | private function createQueryError(string $paramName, string $errorTitle): ErrorInterface |
|
980 | |||
981 | /** |
||
982 | * |
||
983 | * @return string |
||
984 | */ |
||
985 | 25 | private function getInvalidParamMessage(): string |
|
989 | } |
||
990 |
Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.