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 declare (strict_types = 1); |
||
62 | class QueryParser implements JsonApiQueryParserInterface |
||
63 | { |
||
64 | use BaseQueryParserTrait { |
||
65 | BaseQueryParserTrait::getFields as getFieldsImpl; |
||
66 | BaseQueryParserTrait::getIncludes as getIncludesImpl; |
||
67 | BaseQueryParserTrait::getSorts as getSortsImpl; |
||
68 | } |
||
69 | use ClassIsTrait; |
||
70 | |||
71 | /** Message */ |
||
72 | public const MSG_ERR_INVALID_PARAMETER = 'Invalid Parameter.'; |
||
73 | |||
74 | /** |
||
75 | * @var array |
||
76 | */ |
||
77 | private $parameters; |
||
78 | |||
79 | /** |
||
80 | * @var string[]|null |
||
81 | */ |
||
82 | private $messages; |
||
83 | |||
84 | /** |
||
85 | * @var null|string |
||
86 | */ |
||
87 | private $identityParameter; |
||
88 | |||
89 | /** |
||
90 | * @var array |
||
91 | */ |
||
92 | private $filterParameters; |
||
93 | |||
94 | /** |
||
95 | * @var bool |
||
96 | */ |
||
97 | private $areFiltersWithAnd; |
||
98 | |||
99 | /** |
||
100 | * @var int|null |
||
101 | */ |
||
102 | private $pagingOffset; |
||
103 | |||
104 | /** |
||
105 | * @var int|null |
||
106 | */ |
||
107 | private $pagingLimit; |
||
108 | |||
109 | /** |
||
110 | * NOTE: Despite the type it is just a string so only static methods can be called from the interface. |
||
111 | * |
||
112 | * @var JsonApiQueryRulesSerializerInterface|string |
||
113 | */ |
||
114 | private $serializerClass; |
||
115 | |||
116 | /** |
||
117 | * @var array |
||
118 | */ |
||
119 | private $serializedRuleSet; |
||
120 | |||
121 | /** |
||
122 | * @var array |
||
123 | */ |
||
124 | private $validationBlocks; |
||
125 | |||
126 | /** |
||
127 | * @var ContextStorageInterface |
||
128 | */ |
||
129 | private $context; |
||
130 | |||
131 | /** |
||
132 | * @var CaptureAggregatorInterface |
||
133 | */ |
||
134 | private $captures; |
||
135 | |||
136 | /** |
||
137 | * @var ErrorAggregatorInterface |
||
138 | */ |
||
139 | private $validationErrors; |
||
140 | |||
141 | /** |
||
142 | * @var JsonApiErrorCollection |
||
143 | */ |
||
144 | private $jsonErrors; |
||
145 | |||
146 | /** |
||
147 | * @var null|mixed |
||
148 | */ |
||
149 | private $cachedIdentity = null; |
||
150 | |||
151 | /** |
||
152 | * @var null|array |
||
153 | */ |
||
154 | private $cachedFilters = null; |
||
155 | |||
156 | /** |
||
157 | * @var null|array |
||
158 | */ |
||
159 | private $cachedFields = null; |
||
160 | |||
161 | /** |
||
162 | * @var null|array |
||
163 | */ |
||
164 | private $cachedSorts = null; |
||
165 | |||
166 | /** |
||
167 | * @var null|array |
||
168 | */ |
||
169 | private $cachedIncludes = null; |
||
170 | |||
171 | /** |
||
172 | * @var FormatterFactoryInterface |
||
173 | */ |
||
174 | private $formatterFactory; |
||
175 | |||
176 | /** |
||
177 | * @var FormatterInterface|null |
||
178 | */ |
||
179 | 38 | private $formatter; |
|
180 | |||
181 | /** |
||
182 | * @param string $rulesClass |
||
183 | * @param string $serializerClass |
||
184 | * @param array $serializedData |
||
185 | * @param ContextStorageInterface $context |
||
186 | * @param CaptureAggregatorInterface $captures |
||
187 | * @param ErrorAggregatorInterface $validationErrors |
||
188 | * @param JsonApiErrorCollection $jsonErrors |
||
189 | * @param FormatterFactoryInterface $formatterFactory |
||
190 | 38 | * @param string[]|null $messages |
|
191 | 38 | */ |
|
192 | 38 | public function __construct( |
|
221 | |||
222 | 31 | /** |
|
223 | * @inheritdoc |
||
224 | */ |
||
225 | public function parse(?string $identity, array $parameters = []): JsonApiQueryParserInterface |
||
235 | |||
236 | 1 | /** |
|
237 | * @inheritdoc |
||
238 | 1 | */ |
|
239 | public function areFiltersWithAnd(): bool |
||
243 | |||
244 | 14 | /** |
|
245 | * @inheritdoc |
||
246 | 14 | */ |
|
247 | public function hasFilters(): bool |
||
251 | |||
252 | 14 | /** |
|
253 | * @inheritdoc |
||
254 | 14 | */ |
|
255 | public function hasFields(): bool |
||
259 | |||
260 | 1 | /** |
|
261 | * @inheritdoc |
||
262 | 1 | */ |
|
263 | public function hasIncludes(): bool |
||
267 | |||
268 | 1 | /** |
|
269 | * @inheritdoc |
||
270 | 1 | */ |
|
271 | public function hasSorts(): bool |
||
275 | |||
276 | 5 | /** |
|
277 | * @inheritdoc |
||
278 | 5 | */ |
|
279 | 5 | public function hasPaging(): bool |
|
283 | |||
284 | /** |
||
285 | * @inheritdoc |
||
286 | */ |
||
287 | public function getIdentity() |
||
295 | |||
296 | /** |
||
297 | * @inheritdoc |
||
298 | */ |
||
299 | public function getFilters(): array |
||
307 | 3 | ||
308 | /** |
||
309 | * @inheritdoc |
||
310 | */ |
||
311 | public function getFields(): array |
||
320 | 16 | ||
321 | /** |
||
322 | * @inheritdoc |
||
323 | */ |
||
324 | public function getSorts(): array |
||
333 | 16 | ||
334 | /** |
||
335 | * @inheritdoc |
||
336 | */ |
||
337 | public function getIncludes(): iterable |
||
346 | |||
347 | 17 | /** |
|
348 | * @inheritdoc |
||
349 | 17 | */ |
|
350 | public function getPagingOffset(): ?int |
||
354 | |||
355 | /** |
||
356 | * @inheritdoc |
||
357 | 38 | */ |
|
358 | public function getPagingLimit(): ?int |
||
362 | |||
363 | /** |
||
364 | * @param array $parameters |
||
365 | * |
||
366 | * @return self |
||
367 | 35 | */ |
|
368 | protected function setParameters(array $parameters): self |
||
374 | |||
375 | /** |
||
376 | * @return array |
||
377 | 38 | */ |
|
378 | protected function getParameters(): array |
||
382 | |||
383 | /** |
||
384 | * @param array $messages |
||
385 | * |
||
386 | * @return self |
||
387 | */ |
||
388 | protected function setMessages(?array $messages): self |
||
394 | |||
395 | /** |
||
396 | * @param string $message |
||
397 | * |
||
398 | * @return string |
||
399 | 6 | */ |
|
400 | protected function getMessage(string $message): string |
||
406 | |||
407 | 38 | /** |
|
408 | * @return JsonApiErrorCollection |
||
409 | 38 | */ |
|
410 | protected function getJsonErrors(): JsonApiErrorCollection |
||
414 | |||
415 | 38 | /** |
|
416 | * @return ErrorAggregatorInterface |
||
417 | 38 | */ |
|
418 | protected function getValidationErrors(): ErrorAggregatorInterface |
||
422 | |||
423 | 34 | /** |
|
424 | * @return CaptureAggregatorInterface |
||
425 | 34 | */ |
|
426 | protected function getCaptures(): CaptureAggregatorInterface |
||
430 | |||
431 | 34 | /** |
|
432 | * @return ContextStorageInterface |
||
433 | 34 | */ |
|
434 | protected function getContext(): ContextStorageInterface |
||
438 | |||
439 | 35 | /** |
|
440 | * @return array |
||
441 | 35 | */ |
|
442 | protected function getValidationBlocks(): array |
||
446 | |||
447 | 1 | /** |
|
448 | * @return array |
||
449 | 1 | */ |
|
450 | protected function getSerializedRuleSet(): array |
||
454 | |||
455 | 1 | /** |
|
456 | * @return FormatterFactoryInterface |
||
457 | 1 | */ |
|
458 | 1 | protected function getFormatterFactory(): FormatterFactoryInterface |
|
462 | |||
463 | /** |
||
464 | * @return FormatterInterface |
||
465 | */ |
||
466 | protected function getFormatter(): FormatterInterface |
||
474 | |||
475 | /** |
||
476 | * @param string $name |
||
477 | 5 | * |
|
478 | * @return bool |
||
479 | */ |
||
480 | 5 | protected function hasParameter(string $name): bool |
|
484 | |||
485 | 5 | /** |
|
486 | * @return mixed |
||
487 | */ |
||
488 | 5 | private function getValidatedIdentity() |
|
508 | |||
509 | 1 | /** |
|
510 | 1 | * @return iterable |
|
511 | * |
||
512 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
513 | */ |
||
514 | 21 | private function getValidatedFilters(): iterable |
|
559 | 3 | ||
560 | /** |
||
561 | 3 | * @param iterable $fieldsFromParent |
|
562 | * |
||
563 | 1 | * @return iterable |
|
564 | 1 | * |
|
565 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
566 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
567 | */ |
||
568 | 2 | private function getValidatedFields(iterable $fieldsFromParent): iterable |
|
600 | 16 | ||
601 | /** |
||
602 | 16 | * @param iterable $sortsFromParent |
|
603 | * |
||
604 | 1 | * @return iterable |
|
605 | 1 | * |
|
606 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
607 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
608 | */ |
||
609 | 15 | private function getValidatedSorts(iterable $sortsFromParent): iterable |
|
632 | 16 | ||
633 | /** |
||
634 | 16 | * @param iterable $includesFromParent |
|
635 | * |
||
636 | 1 | * @return iterable |
|
637 | 1 | * |
|
638 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
639 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
640 | */ |
||
641 | 15 | private function getValidatedIncludes(iterable $includesFromParent): iterable |
|
664 | 19 | ||
665 | /** |
||
666 | * @param iterable $iterable |
||
667 | 21 | * |
|
668 | * @return array |
||
669 | */ |
||
670 | private function iterableToArray(iterable $iterable): array |
||
680 | 35 | ||
681 | /** |
||
682 | * @param mixed $value |
||
683 | * |
||
684 | * @return int |
||
685 | */ |
||
686 | private function validatePageOffset($value): int |
||
693 | 35 | ||
694 | /** |
||
695 | * @param mixed $value |
||
696 | * |
||
697 | * @return int |
||
698 | */ |
||
699 | private function validatePageLimit($value): int |
||
706 | 1 | ||
707 | /** |
||
708 | * @param mixed $value |
||
709 | 34 | * @param array $ruleIndexes |
|
710 | * |
||
711 | 34 | * @return int |
|
712 | 34 | */ |
|
713 | 34 | private function validatePaginationValue($value, ?array $ruleIndexes): int |
|
730 | 34 | ||
731 | 34 | /** |
|
732 | * @param string $paramName |
||
733 | 34 | * @param array $ruleIndexes |
|
734 | 34 | * |
|
735 | 34 | * @return void |
|
736 | 34 | * |
|
737 | 34 | * @SuppressWarnings(PHPMD.StaticAccess) |
|
738 | */ |
||
739 | 34 | private function validationStarts(string $paramName, array $ruleIndexes): void |
|
752 | |||
753 | 34 | /** |
|
754 | 34 | * @param string $paramName |
|
755 | 34 | * @param mixed $value |
|
756 | 34 | * @param int $ruleIndex |
|
757 | 34 | * |
|
758 | 34 | * @return void |
|
759 | 34 | * |
|
760 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
761 | 34 | */ |
|
762 | private function validateAndThrowOnError(string $paramName, $value, int $ruleIndex): void |
||
774 | 16 | ||
775 | 16 | /** |
|
776 | 16 | * @param mixed $value |
|
777 | 16 | * @param int $ruleIndex |
|
778 | 16 | * |
|
779 | 16 | * @return bool |
|
780 | 16 | * |
|
781 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
782 | */ |
||
783 | private function validateAndAccumulateError($value, int $ruleIndex): bool |
||
794 | 34 | ||
795 | 34 | /** |
|
796 | 34 | * @param string $paramName |
|
797 | 34 | * @param array $ruleIndexes |
|
798 | 34 | * |
|
799 | * @return void |
||
800 | 34 | * |
|
801 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
802 | */ |
||
803 | private function validateEnds(string $paramName, array $ruleIndexes): void |
||
813 | |||
814 | /** |
||
815 | * @return mixed |
||
816 | */ |
||
817 | private function readSingleCapturedValue() |
||
824 | 9 | ||
825 | 9 | /** |
|
826 | 9 | * @param int $ruleIndex |
|
827 | * @param iterable $values |
||
828 | * |
||
829 | * @return iterable |
||
830 | */ |
||
831 | private function validateValues(int $ruleIndex, iterable $values): iterable |
||
841 | |||
842 | /** |
||
843 | * @param int $ruleIndex |
||
844 | * @param iterable $opsAndArgs |
||
845 | * |
||
846 | * @return iterable |
||
847 | 35 | */ |
|
848 | private function validateFilterArguments(int $ruleIndex, iterable $opsAndArgs): iterable |
||
854 | 35 | ||
855 | /** |
||
856 | 35 | * @return self |
|
857 | 35 | */ |
|
858 | private function parsePagingParameters(): self |
||
872 | 6 | ||
873 | 6 | /** |
|
874 | * @param string $paramName |
||
875 | * |
||
876 | 6 | * @return void |
|
877 | * |
||
878 | * @throws JsonApiException |
||
879 | */ |
||
880 | private function checkValidationQueueErrors(string $paramName): void |
||
890 | |||
891 | /** |
||
892 | * @param string|null $value |
||
893 | * |
||
894 | * @return self |
||
895 | 5 | */ |
|
896 | private function setIdentityParameter(?string $value): self |
||
902 | |||
903 | /** |
||
904 | * @return null|string |
||
905 | 31 | */ |
|
906 | private function getIdentityParameter(): ?string |
||
910 | |||
911 | /** |
||
912 | * @param array $values |
||
913 | * |
||
914 | * @return self |
||
915 | 22 | */ |
|
916 | private function setFilterParameters(array $values): self |
||
922 | |||
923 | 29 | /** |
|
924 | * @return array |
||
925 | 29 | */ |
|
926 | private function getFilterParameters(): array |
||
930 | |||
931 | /** |
||
932 | * @return self |
||
933 | 2 | */ |
|
934 | private function setFiltersWithAnd(): self |
||
940 | |||
941 | /** |
||
942 | * @return self |
||
943 | 38 | */ |
|
944 | private function setFiltersWithOr(): self |
||
950 | |||
951 | 38 | /** |
|
952 | 38 | * @return self |
|
953 | 38 | */ |
|
954 | 38 | private function clear(): self |
|
973 | 35 | ||
974 | 17 | /** |
|
975 | * Pre-parsing for filter parameters. |
||
976 | 17 | * |
|
977 | * @return self |
||
978 | * |
||
979 | 18 | * @SuppressWarnings(PHPMD.ElseExpression) |
|
980 | 18 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
|
981 | 2 | */ |
|
982 | 2 | private function parseFilterLink(): self |
|
1027 | |||
1028 | 11 | /** |
|
1029 | 11 | * @param string $parameterName |
|
1030 | 11 | * @param array $value |
|
1031 | * |
||
1032 | 1 | * @return iterable |
|
1033 | 1 | * |
|
1034 | 1 | * @SuppressWarnings(PHPMD.ElseExpression) |
|
1035 | */ |
||
1036 | private function parseOperationsAndArguments(string $parameterName, array $value): iterable |
||
1059 | |||
1060 | 1 | /** |
|
1061 | * @param string $paramName |
||
1062 | * @param string $errorTitle |
||
1063 | * |
||
1064 | * @return ErrorInterface |
||
1065 | */ |
||
1066 | private function createQueryError(string $paramName, string $errorTitle): ErrorInterface |
||
1073 | |||
1074 | /** |
||
1075 | * |
||
1076 | * @return string |
||
1077 | */ |
||
1078 | private function getInvalidParamMessage(): string |
||
1082 | } |
||
1083 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.