Complex classes like DocumentEntity 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 DocumentEntity, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
46 | abstract class DocumentEntity extends SchematicEntity implements CompositableInterface |
||
47 | { |
||
48 | use SaturateTrait, SolidableTrait; |
||
49 | |||
50 | /* |
||
51 | * Begin set of behaviour and description constants. |
||
52 | * ================================================ |
||
53 | */ |
||
54 | |||
55 | /** |
||
56 | * Set of schema sections needed to describe entity behaviour. |
||
57 | */ |
||
58 | const SH_INSTANTIATION = 0; |
||
59 | const SH_DEFAULTS = 1; |
||
60 | const SH_COMPOSITIONS = 5; |
||
61 | const SH_AGGREGATIONS = 6; |
||
62 | |||
63 | /** |
||
64 | * Constants used to describe aggregation relations (also used internally to identify |
||
65 | * composition). |
||
66 | * |
||
67 | * Example: |
||
68 | * 'items' => [self::MANY => Item::class, ['parentID' => 'key::_id']] |
||
69 | * |
||
70 | * @see DocumentEntity::SCHEMA |
||
71 | */ |
||
72 | const MANY = 778; |
||
73 | const ONE = 899; |
||
74 | |||
75 | /* |
||
76 | * ================================================ |
||
77 | * End set of behaviour and description constants. |
||
78 | */ |
||
79 | |||
80 | /** |
||
81 | * Class responsible for instance construction. |
||
82 | */ |
||
83 | const INSTANTIATOR = DocumentInstantiator::class; |
||
84 | |||
85 | /** |
||
86 | * Document fields, accessors and relations. ODM will generate setters and getters for some |
||
87 | * fields based on their types. |
||
88 | * |
||
89 | * Example, fields: |
||
90 | * const SCHEMA = [ |
||
91 | * '_id' => 'MongoId', //Primary key field |
||
92 | * 'value' => 'string', //Default string field |
||
93 | * 'values' => ['string'] //ScalarArray accessor will be applied for fields like that |
||
94 | * ]; |
||
95 | * |
||
96 | * Compositions: |
||
97 | * const SCHEMA = [ |
||
98 | * ..., |
||
99 | * 'child' => Child::class, //One document are composited, for example user Profile |
||
100 | * 'many' => [Child::class] //Compositor accessor will be applied, allows to |
||
101 | * //composite many document instances |
||
102 | * ]; |
||
103 | * |
||
104 | * Documents can extend each other, in this case schema will also be inherited. |
||
105 | * |
||
106 | * Attention, make sure you properly set FILLABLE option in parent class to use constructions |
||
107 | * like: |
||
108 | * $parent->child = [...]; |
||
109 | * |
||
110 | * or |
||
111 | * $parent->setFields(['child'=>[...]]); |
||
112 | * |
||
113 | * @var array |
||
114 | */ |
||
115 | const SCHEMA = []; |
||
116 | |||
117 | /** |
||
118 | * Default field values. |
||
119 | * |
||
120 | * @var array |
||
121 | */ |
||
122 | const DEFAULTS = []; |
||
123 | |||
124 | /** |
||
125 | * Model behaviour configurations. |
||
126 | */ |
||
127 | const SECURED = '*'; |
||
128 | const FILLABLE = []; |
||
129 | const SETTERS = []; |
||
130 | const GETTERS = []; |
||
131 | const ACCESSORS = []; |
||
132 | |||
133 | /** |
||
134 | * Document behaviour schema. |
||
135 | * |
||
136 | * @var array |
||
137 | */ |
||
138 | private $documentSchema = []; |
||
139 | |||
140 | /** |
||
141 | * Document field updates (changed values). |
||
142 | * |
||
143 | * @var array |
||
144 | */ |
||
145 | private $changes = []; |
||
146 | |||
147 | /** |
||
148 | * Parent ODM instance, responsible for aggregations and lazy loading operations. |
||
149 | * |
||
150 | * @invisible |
||
151 | * @var ODMInterface |
||
152 | */ |
||
153 | protected $odm; |
||
154 | |||
155 | /** |
||
156 | * {@inheritdoc} |
||
157 | * |
||
158 | * @param ODMInterface $odm To lazy create nested document ang aggregations. |
||
159 | * |
||
160 | * @throws ScopeException When no ODM instance can be resolved. |
||
161 | */ |
||
162 | public function __construct(array $data = [], ODMInterface $odm = null, array $schema = null) |
||
181 | |||
182 | /** |
||
183 | * {@inheritdoc} |
||
184 | */ |
||
185 | public function getField(string $name, $default = null, bool $filter = true) |
||
191 | |||
192 | /** |
||
193 | * {@inheritdoc} |
||
194 | * |
||
195 | * Tracks field changes. |
||
196 | */ |
||
197 | public function setField(string $name, $value, bool $filter = true) |
||
204 | |||
205 | /** |
||
206 | * {@inheritdoc} |
||
207 | * |
||
208 | * Will restore default value if presented. |
||
209 | */ |
||
210 | public function __unset($offset) |
||
218 | |||
219 | /** |
||
220 | * Provides ability to invoke document aggregation. |
||
221 | * |
||
222 | * @param string $method |
||
223 | * @param array $arguments |
||
224 | * |
||
225 | * @return mixed|null|AccessorInterface|CompositableInterface|Document|Entities\DocumentSelector |
||
226 | */ |
||
227 | public function __call($method, array $arguments) |
||
241 | |||
242 | /** |
||
243 | * {@inheritdoc} |
||
244 | * |
||
245 | * @param string $field Check once specific field changes. |
||
246 | */ |
||
247 | public function hasChanges(string $field = null): bool |
||
278 | |||
279 | /** |
||
280 | * {@inheritdoc} |
||
281 | */ |
||
282 | public function buildAtomics(string $container = null): array |
||
326 | |||
327 | /** |
||
328 | * {@inheritdoc} |
||
329 | */ |
||
330 | public function flushChanges() |
||
340 | |||
341 | /** |
||
342 | * {@inheritdoc} |
||
343 | * |
||
344 | * @param bool $includeID Set to false to exclude _id from packed fields. |
||
345 | */ |
||
346 | public function packValue(bool $includeID = true) |
||
356 | |||
357 | /** |
||
358 | * Since most of ODM documents might contain ObjectIDs and other fields we will try to normalize |
||
359 | * them into string values. |
||
360 | * |
||
361 | * @return array |
||
362 | */ |
||
363 | public function publicValue(): array |
||
375 | |||
376 | /** |
||
377 | * Cloning will be called when object will be embedded into another document. |
||
378 | */ |
||
379 | public function __clone() |
||
388 | |||
389 | /** |
||
390 | * @return array |
||
391 | */ |
||
392 | public function __debugInfo() |
||
399 | |||
400 | /** |
||
401 | * {@inheritdoc} |
||
402 | * |
||
403 | * @see CompositionDefinition |
||
404 | */ |
||
405 | protected function getMutator(string $field, string $mutator) |
||
416 | |||
417 | /** |
||
418 | * {@inheritdoc} |
||
419 | */ |
||
420 | protected function isNullable(string $field): bool |
||
430 | |||
431 | /** |
||
432 | * {@inheritdoc} |
||
433 | * |
||
434 | * DocumentEntity will pass ODM instance as part of accessor context. |
||
435 | * |
||
436 | * @see CompositionDefinition |
||
437 | */ |
||
438 | protected function createAccessor( |
||
460 | |||
461 | /** |
||
462 | * {@inheritdoc} |
||
463 | */ |
||
464 | protected function iocContainer() |
||
473 | |||
474 | /** |
||
475 | * @param string $name |
||
476 | */ |
||
477 | private function registerChange(string $name) |
||
488 | |||
489 | /** |
||
490 | * @param string $name |
||
491 | * |
||
492 | * @throws AccessException |
||
493 | */ |
||
494 | private function assertField(string $name) |
||
504 | } |
||
505 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.