Complex classes like DataParser 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 DataParser, and based on these observations, apply Extract Interface, too.
1 | <?php namespace Limoncello\Flute\Validation\JsonApi; |
||
41 | class DataParser extends BaseValidator implements JsonApiDataValidatingParserInterface |
||
42 | { |
||
43 | use RelationshipRulesTrait; |
||
44 | |||
45 | /** Rule description index */ |
||
46 | const RULE_INDEX = 0; |
||
47 | |||
48 | /** Rule description index */ |
||
49 | const RULE_ATTRIBUTES = self::RULE_INDEX + 1; |
||
50 | |||
51 | /** Rule description index */ |
||
52 | const RULE_TO_ONE = self::RULE_ATTRIBUTES + 1; |
||
53 | |||
54 | /** Rule description index */ |
||
55 | const RULE_TO_MANY = self::RULE_TO_ONE + 1; |
||
56 | |||
57 | /** Rule description index */ |
||
58 | const RULE_UNLISTED_ATTRIBUTE = self::RULE_TO_MANY + 1; |
||
59 | |||
60 | /** Rule description index */ |
||
61 | const RULE_UNLISTED_RELATIONSHIP = self::RULE_UNLISTED_ATTRIBUTE + 1; |
||
62 | |||
63 | /** |
||
64 | * NOTE: Despite the type it is just a string so only static methods can be called from the interface. |
||
65 | * |
||
66 | * @var JsonApiDataRulesSerializerInterface|string |
||
67 | */ |
||
68 | private $serializerClass; |
||
69 | |||
70 | /** |
||
71 | * @var int |
||
72 | */ |
||
73 | private $errorStatus; |
||
74 | |||
75 | /** |
||
76 | * @var ContextStorageInterface |
||
77 | */ |
||
78 | private $context; |
||
79 | |||
80 | /** |
||
81 | * @var JsonApiErrorCollection |
||
82 | */ |
||
83 | private $jsonApiErrors; |
||
84 | |||
85 | /** |
||
86 | * @var array |
||
87 | */ |
||
88 | private $blocks; |
||
89 | |||
90 | /** |
||
91 | * @var array |
||
92 | */ |
||
93 | private $idRule; |
||
94 | |||
95 | /** |
||
96 | * @var array |
||
97 | */ |
||
98 | private $typeRule; |
||
99 | |||
100 | /** |
||
101 | * @var int[] |
||
102 | */ |
||
103 | private $attributeRules; |
||
104 | |||
105 | /** |
||
106 | * @var int[] |
||
107 | */ |
||
108 | private $toOneRules; |
||
109 | |||
110 | /** |
||
111 | * @var int[] |
||
112 | */ |
||
113 | private $toManyRules; |
||
114 | |||
115 | /** |
||
116 | * @var bool |
||
117 | */ |
||
118 | private $isIgnoreUnknowns; |
||
119 | |||
120 | /** |
||
121 | * @var FormatterInterface|null |
||
122 | */ |
||
123 | private $formatter; |
||
124 | |||
125 | /** |
||
126 | * @var FormatterFactoryInterface |
||
127 | */ |
||
128 | private $formatterFactory; |
||
129 | |||
130 | /** |
||
131 | * @param string $rulesClass |
||
132 | * @param string $serializerClass |
||
133 | * @param array $serializedData |
||
134 | * @param ContextStorageInterface $context |
||
135 | * @param JsonApiErrorCollection $jsonErrors |
||
136 | * @param FormatterFactoryInterface $formatterFactory |
||
137 | * @param int $errorStatus |
||
138 | * |
||
139 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
140 | */ |
||
141 | 26 | public function __construct( |
|
170 | |||
171 | /** |
||
172 | * @inheritdoc |
||
173 | */ |
||
174 | 11 | public function assert($jsonData): JsonApiDataValidatingParserInterface |
|
182 | |||
183 | /** |
||
184 | * @inheritdoc |
||
185 | */ |
||
186 | 11 | public function validate($input): bool |
|
198 | |||
199 | /** |
||
200 | * @inheritdoc |
||
201 | * |
||
202 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
203 | */ |
||
204 | 14 | public function parse(array $input): bool |
|
218 | |||
219 | /** |
||
220 | * @inheritdoc |
||
221 | * |
||
222 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
223 | */ |
||
224 | 7 | public function parseRelationship(string $index, string $name, array $jsonData): bool |
|
264 | |||
265 | /** |
||
266 | * @inheritdoc |
||
267 | */ |
||
268 | 7 | public function assertRelationship( |
|
279 | |||
280 | /** |
||
281 | * @inheritdoc |
||
282 | */ |
||
283 | 6 | public function getJsonApiErrors(): array |
|
287 | |||
288 | /** |
||
289 | * @inheritdoc |
||
290 | */ |
||
291 | 13 | public function getJsonApiCaptures(): array |
|
295 | |||
296 | /** |
||
297 | * @return BaseValidator |
||
|
|||
298 | */ |
||
299 | 26 | protected function resetAggregators(): BaseValidator |
|
307 | |||
308 | /** |
||
309 | * @param string $serializerClass |
||
310 | * |
||
311 | * @return self |
||
312 | */ |
||
313 | 26 | protected function setSerializerClass(string $serializerClass): self |
|
324 | |||
325 | /** |
||
326 | * @return JsonApiDataRulesSerializerInterface|string |
||
327 | */ |
||
328 | 26 | protected function getSerializer() |
|
332 | |||
333 | /** |
||
334 | * @param array $jsonData |
||
335 | * |
||
336 | * @return self |
||
337 | * |
||
338 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
339 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
340 | */ |
||
341 | 14 | private function validateType(array $jsonData): self |
|
374 | |||
375 | /** |
||
376 | * @param array $jsonData |
||
377 | * |
||
378 | * @return self |
||
379 | * |
||
380 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
381 | */ |
||
382 | 14 | private function validateId(array $jsonData): self |
|
411 | |||
412 | /** |
||
413 | * @param array $jsonData |
||
414 | * |
||
415 | * @return self |
||
416 | * |
||
417 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
418 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
419 | */ |
||
420 | 14 | private function validateAttributes(array $jsonData): self |
|
461 | |||
462 | /** |
||
463 | * @param array $jsonData |
||
464 | * |
||
465 | * @return self |
||
466 | * |
||
467 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
468 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
469 | */ |
||
470 | 14 | private function validateRelationships(array $jsonData): self |
|
525 | |||
526 | /** |
||
527 | * @param int $index |
||
528 | * @param string $name |
||
529 | * @param mixed $mightBeRelationship |
||
530 | * |
||
531 | * @return void |
||
532 | * |
||
533 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
534 | */ |
||
535 | 10 | private function validateAsToOneRelationship(int $index, string $name, $mightBeRelationship): void |
|
549 | |||
550 | /** |
||
551 | * @param int $index |
||
552 | * @param string $name |
||
553 | * @param mixed $mightBeRelationship |
||
554 | * |
||
555 | * @return void |
||
556 | * |
||
557 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
558 | */ |
||
559 | 12 | private function validateAsToManyRelationship(int $index, string $name, $mightBeRelationship): void |
|
589 | |||
590 | /** |
||
591 | * @param mixed $data |
||
592 | * |
||
593 | * @return array|null|false Either `array` ($type => $id), or `null`, or `false` on error. |
||
594 | * |
||
595 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
596 | */ |
||
597 | 13 | private function parseSingleRelationship($data) |
|
614 | |||
615 | /** |
||
616 | * Re-initializes internal aggregators for captures, errors, etc. |
||
617 | */ |
||
618 | 21 | private function reInitAggregatorsIfNeeded(): void |
|
622 | |||
623 | /** |
||
624 | * @param mixed $input |
||
625 | * @param int $index |
||
626 | * |
||
627 | * @return void |
||
628 | * |
||
629 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
630 | */ |
||
631 | 19 | private function executeBlock($input, int $index): void |
|
642 | |||
643 | /** |
||
644 | * @param array $indexes |
||
645 | * |
||
646 | * @return void |
||
647 | * |
||
648 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
649 | */ |
||
650 | 20 | private function executeStarts(array $indexes): void |
|
659 | |||
660 | /** |
||
661 | * @param array $indexes |
||
662 | * |
||
663 | * @return void |
||
664 | * |
||
665 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
666 | */ |
||
667 | 20 | private function executeEnds(array $indexes): void |
|
676 | |||
677 | /** |
||
678 | * @param ErrorInterface $error |
||
679 | * |
||
680 | * @return string |
||
681 | */ |
||
682 | 3 | private function getMessage(ErrorInterface $error): string |
|
690 | |||
691 | /** |
||
692 | * @return array |
||
693 | */ |
||
694 | 14 | protected function getIdRule(): array |
|
698 | |||
699 | /** |
||
700 | * @return array |
||
701 | */ |
||
702 | 14 | protected function getTypeRule(): array |
|
706 | |||
707 | /** |
||
708 | * @return ContextStorageInterface |
||
709 | */ |
||
710 | 26 | protected function getContext(): ContextStorageInterface |
|
714 | |||
715 | /** |
||
716 | * @param ContextStorageInterface $context |
||
717 | * |
||
718 | * @return self |
||
719 | */ |
||
720 | 26 | protected function setContext(ContextStorageInterface $context): self |
|
726 | |||
727 | /** |
||
728 | * @return JsonApiErrorCollection |
||
729 | */ |
||
730 | 22 | protected function getJsonApiErrorCollection(): JsonApiErrorCollection |
|
734 | |||
735 | /** |
||
736 | * @param JsonApiErrorCollection $errors |
||
737 | * |
||
738 | * @return self |
||
739 | */ |
||
740 | 26 | protected function setJsonApiErrors(JsonApiErrorCollection $errors): self |
|
746 | |||
747 | /** |
||
748 | * @return int |
||
749 | */ |
||
750 | 12 | protected function getErrorStatus(): int |
|
754 | |||
755 | /** |
||
756 | * @return bool |
||
757 | */ |
||
758 | 1 | protected function isIgnoreUnknowns(): bool |
|
762 | |||
763 | /** |
||
764 | * @return self |
||
765 | */ |
||
766 | 1 | protected function enableIgnoreUnknowns(): self |
|
772 | |||
773 | /** |
||
774 | * @return self |
||
775 | */ |
||
776 | 26 | protected function disableIgnoreUnknowns(): self |
|
782 | |||
783 | /** |
||
784 | * @param array $rules |
||
785 | * |
||
786 | * @return self |
||
787 | */ |
||
788 | 26 | private function setAttributeRules(array $rules): self |
|
796 | |||
797 | /** |
||
798 | * @param array $rules |
||
799 | * |
||
800 | * @return self |
||
801 | */ |
||
802 | 26 | private function setToOneIndexes(array $rules): self |
|
810 | |||
811 | /** |
||
812 | * @param array $rules |
||
813 | * |
||
814 | * @return self |
||
815 | */ |
||
816 | 26 | private function setToManyIndexes(array $rules): self |
|
824 | |||
825 | /** |
||
826 | * @return int[] |
||
827 | */ |
||
828 | 14 | protected function getAttributeRules(): array |
|
832 | |||
833 | /** |
||
834 | * @return int[] |
||
835 | */ |
||
836 | 21 | protected function getToOneRules(): array |
|
840 | |||
841 | /** |
||
842 | * @return int[] |
||
843 | */ |
||
844 | 19 | protected function getToManyRules(): array |
|
848 | |||
849 | /** |
||
850 | * @return array |
||
851 | */ |
||
852 | 23 | private function getBlocks(): array |
|
856 | |||
857 | /** |
||
858 | * @return FormatterInterface |
||
859 | */ |
||
860 | 10 | protected function getFormatter(): FormatterInterface |
|
868 | |||
869 | /** |
||
870 | * @param FormatterFactoryInterface $formatterFactory |
||
871 | * |
||
872 | * @return self |
||
873 | */ |
||
874 | 26 | protected function setFormatterFactory(FormatterFactoryInterface $formatterFactory): self |
|
880 | |||
881 | /** |
||
882 | * @param string $name |
||
883 | * |
||
884 | * @return int|null |
||
885 | * |
||
886 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
887 | */ |
||
888 | 8 | private function getAttributeIndex(string $name): ?int |
|
895 | |||
896 | /** |
||
897 | * @param int $messageId |
||
898 | * @param array $args |
||
899 | * |
||
900 | * @return string |
||
901 | */ |
||
902 | 10 | private function formatMessage(int $messageId, array $args = []): string |
|
908 | |||
909 | /** |
||
910 | * @param array $rules |
||
911 | * |
||
912 | * @return bool |
||
913 | * |
||
914 | * @SuppressWarnings(PHPMD.StaticAccess) |
||
915 | */ |
||
916 | 26 | private function debugCheckIndexesExist(array $rules): bool |
|
932 | } |
||
933 |
This check looks for the generic type
array
as a return type and suggests a more specific type. This type is inferred from the actual code.