Complex classes like RecordEntity 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 RecordEntity, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
29 | abstract class RecordEntity extends SchematicEntity implements RecordInterface |
||
30 | { |
||
31 | use SaturateTrait, SolidableTrait; |
||
32 | |||
33 | /* |
||
34 | * Begin set of behaviour and description constants. |
||
35 | * ================================================ |
||
36 | */ |
||
37 | |||
38 | /** |
||
39 | * Set of schema sections needed to describe entity behaviour. |
||
40 | */ |
||
41 | const SH_PRIMARIES = 0; |
||
42 | const SH_DEFAULTS = 1; |
||
43 | const SH_RELATIONS = 6; |
||
44 | |||
45 | /** |
||
46 | * Default ORM relation types, see ORM configuration and documentation for more information. |
||
47 | * |
||
48 | * @see RelationSchemaInterface |
||
49 | * @see RelationSchema |
||
50 | */ |
||
51 | const HAS_ONE = 101; |
||
52 | const HAS_MANY = 102; |
||
53 | const BELONGS_TO = 103; |
||
54 | const MANY_TO_MANY = 104; |
||
55 | |||
56 | /** |
||
57 | * Morphed relation types are usually created by inversion or equivalent of primary relation |
||
58 | * types. |
||
59 | * |
||
60 | * @see RelationSchemaInterface |
||
61 | * @see RelationSchema |
||
62 | * @see MorphedRelation |
||
63 | */ |
||
64 | const BELONGS_TO_MORPHED = 108; |
||
65 | const MANY_TO_MORPHED = 109; |
||
66 | |||
67 | /** |
||
68 | * Constants used to declare relations in record schema, used in normalized relation schema. |
||
69 | * |
||
70 | * @see RelationSchemaInterface |
||
71 | */ |
||
72 | const OUTER_KEY = 901; //Outer key name |
||
73 | const INNER_KEY = 902; //Inner key name |
||
74 | const MORPH_KEY = 903; //Morph key name |
||
75 | const PIVOT_TABLE = 904; //Pivot table name |
||
76 | const PIVOT_COLUMNS = 905; //Pre-defined pivot table columns |
||
77 | const PIVOT_DEFAULTS = 906; //Pre-defined pivot table default values |
||
78 | const THOUGHT_INNER_KEY = 907; //Pivot table options |
||
79 | const THOUGHT_OUTER_KEY = 908; //Pivot table options |
||
80 | const WHERE = 909; //Where conditions |
||
81 | const WHERE_PIVOT = 910; //Where pivot conditions |
||
82 | |||
83 | /** |
||
84 | * Additional constants used to control relation schema behaviour. |
||
85 | * |
||
86 | * @see RecordEntity::SCHEMA |
||
87 | * @see RelationSchemaInterface |
||
88 | */ |
||
89 | const INVERSE = 1001; //Relation should be inverted to parent record |
||
90 | const CREATE_CONSTRAINT = 1002; //Relation should create foreign keys (default) |
||
91 | const CONSTRAINT_ACTION = 1003; //Default relation foreign key delete/update action (CASCADE) |
||
92 | const CREATE_PIVOT = 1004; //Many-to-Many should create pivot table automatically (default) |
||
93 | const NULLABLE = 1005; //Relation can be nullable (default) |
||
94 | const CREATE_INDEXES = 1006; //Indication that relation is allowed to create required indexes |
||
95 | const MORPHED_ALIASES = 1007; //Aliases for morphed sub-relations |
||
96 | |||
97 | /** |
||
98 | * Set of columns to be used in relation (attention, make sure that loaded records are set as |
||
99 | * NON SOLID if you planning to modify their data). |
||
100 | */ |
||
101 | const RELATION_COLUMNS = 1009; |
||
102 | |||
103 | /** |
||
104 | * Constants used to declare indexes in record schema. |
||
105 | * |
||
106 | * @see Record::INDEXES |
||
107 | */ |
||
108 | const INDEX = 1000; //Default index type |
||
109 | const UNIQUE = 2000; //Unique index definition |
||
110 | |||
111 | /* |
||
112 | * ================================================ |
||
113 | * End set of behaviour and description constants. |
||
114 | */ |
||
115 | |||
116 | /** |
||
117 | * Model behaviour configurations. |
||
118 | */ |
||
119 | const SECURED = '*'; |
||
120 | const HIDDEN = []; |
||
121 | const FILLABLE = []; |
||
122 | const SETTERS = []; |
||
123 | const GETTERS = []; |
||
124 | const ACCESSORS = []; |
||
125 | |||
126 | /** |
||
127 | * Record relations and columns can be described in one place - record schema. |
||
128 | * Attention: while defining table structure make sure that ACTIVE_SCHEMA constant is set to t |
||
129 | * rue. |
||
130 | * |
||
131 | * Example: |
||
132 | * const SCHEMA = [ |
||
133 | * 'id' => 'primary', |
||
134 | * 'name' => 'string', |
||
135 | * 'biography' => 'text' |
||
136 | * ]; |
||
137 | * |
||
138 | * You can pass additional options for some of your columns: |
||
139 | * const SCHEMA = [ |
||
140 | * 'pinCode' => 'string(128)', //String length |
||
141 | * 'status' => 'enum(active, hidden)', //Enum values |
||
142 | * 'balance' => 'decimal(10, 2)' //Decimal size and precision |
||
143 | * ]; |
||
144 | * |
||
145 | * Every created column will be stated as NOT NULL with forced default value, if you want to |
||
146 | * have nullable columns, specify special data key: protected $schema = [ |
||
147 | * 'name' => 'string, nullable' |
||
148 | * ]; |
||
149 | * |
||
150 | * You can easily combine table and relations definition in one schema: |
||
151 | * const SCHEMA = [ |
||
152 | * 'id' => 'bigPrimary', |
||
153 | * 'name' => 'string', |
||
154 | * 'email' => 'string', |
||
155 | * 'phoneNumber' => 'string(32)', |
||
156 | * |
||
157 | * //Relations |
||
158 | * 'profile' => [ |
||
159 | * self::HAS_ONE => 'Records\Profile', |
||
160 | * self::INVERSE => 'user' |
||
161 | * ], |
||
162 | * 'roles' => [ |
||
163 | * self::MANY_TO_MANY => 'Records\Role', |
||
164 | * self::INVERSE => 'users' |
||
165 | * ] |
||
166 | * ]; |
||
167 | * |
||
168 | * @var array |
||
169 | */ |
||
170 | const SCHEMA = []; |
||
171 | |||
172 | /** |
||
173 | * Default field values. |
||
174 | * |
||
175 | * @var array |
||
176 | */ |
||
177 | const DEFAULTS = []; |
||
178 | |||
179 | /** |
||
180 | * Set of indexes to be created for associated record table, indexes only created when record is |
||
181 | * not abstract and has active schema set to true. |
||
182 | * |
||
183 | * Use constants INDEX and UNIQUE to describe indexes, you can also create compound indexes: |
||
184 | * const INDEXES = [ |
||
185 | * [self::UNIQUE, 'email'], |
||
186 | * [self::INDEX, 'board_id'], |
||
187 | * [self::INDEX, 'board_id', 'check_id'] |
||
188 | * ]; |
||
189 | * |
||
190 | * @var array |
||
191 | */ |
||
192 | const INDEXES = []; |
||
193 | |||
194 | /** |
||
195 | * Record behaviour definition. |
||
196 | * |
||
197 | * @var array |
||
198 | */ |
||
199 | private $recordSchema = []; |
||
200 | |||
201 | /** |
||
202 | * Record state. |
||
203 | * |
||
204 | * @var int |
||
205 | */ |
||
206 | private $state; |
||
207 | |||
208 | /** |
||
209 | * Record field updates (changed values). This array contain set of initial property values if |
||
210 | * any of them changed. |
||
211 | * |
||
212 | * @var array |
||
213 | */ |
||
214 | private $changes = []; |
||
215 | |||
216 | /** |
||
217 | * Associated relation instances and/or initial loaded data. |
||
218 | * |
||
219 | * @var array |
||
220 | */ |
||
221 | private $relations = []; |
||
222 | |||
223 | /** |
||
224 | * Parent ORM instance, responsible for relation initialization and lazy loading operations. |
||
225 | * |
||
226 | * @invisible |
||
227 | * @var ORMInterface |
||
228 | */ |
||
229 | protected $orm; |
||
230 | |||
231 | /** |
||
232 | * Initiate entity inside or outside of ORM scope using given fields and state. |
||
233 | * |
||
234 | * @param array $fields |
||
235 | * @param int $state |
||
236 | * @param ORMInterface|null $orm |
||
237 | * @param array|null $schema |
||
238 | */ |
||
239 | public function __construct( |
||
262 | |||
263 | /** |
||
264 | * Check if entity been loaded (non new). |
||
265 | * |
||
266 | * @return bool |
||
267 | */ |
||
268 | public function isLoaded(): bool |
||
272 | |||
273 | /** |
||
274 | * Current model state. |
||
275 | * |
||
276 | * @return int |
||
277 | */ |
||
278 | public function getState(): int |
||
282 | |||
283 | /** |
||
284 | * {@inheritdoc} |
||
285 | */ |
||
286 | public function getField(string $name, $default = null, bool $filter = true) |
||
300 | |||
301 | /** |
||
302 | * {@inheritdoc} |
||
303 | * |
||
304 | * Tracks field changes. |
||
305 | */ |
||
306 | public function setField(string $name, $value, bool $filter = true) |
||
323 | |||
324 | /** |
||
325 | * {@inheritdoc} |
||
326 | */ |
||
327 | public function __isset($name) |
||
333 | |||
334 | /** |
||
335 | * {@inheritdoc} |
||
336 | * |
||
337 | * @throws FieldException |
||
338 | */ |
||
339 | public function __unset($offset) |
||
347 | |||
348 | /** |
||
349 | * {@inheritdoc} |
||
350 | * |
||
351 | * Method does not check updates in nested relation, but only in primary record. |
||
352 | * |
||
353 | * @param string $field Check once specific field changes. |
||
354 | */ |
||
355 | public function hasUpdates(string $field = null): bool |
||
386 | |||
387 | /** |
||
388 | * {@inheritdoc} |
||
389 | * |
||
390 | * @param bool $queueRelations |
||
391 | */ |
||
392 | public function queueSave(bool $queueRelations = true): CommandInterface |
||
412 | |||
413 | /** |
||
414 | * {@inheritdoc} |
||
415 | */ |
||
416 | public function queueDelete(): CommandInterface |
||
425 | |||
426 | /** |
||
427 | * @return array |
||
428 | */ |
||
429 | public function __debugInfo() |
||
438 | |||
439 | /** |
||
440 | * {@inheritdoc} |
||
441 | * |
||
442 | * DocumentEntity will pass ODM instance as part of accessor context. |
||
443 | * |
||
444 | * @see CompositionDefinition |
||
445 | */ |
||
446 | protected function createAccessor( |
||
455 | |||
456 | /** |
||
457 | * {@inheritdoc} |
||
458 | */ |
||
459 | protected function iocContainer() |
||
468 | |||
469 | /* |
||
470 | * Code below used to generate transaction commands. |
||
471 | */ |
||
472 | |||
473 | /** |
||
474 | * Change object state. |
||
475 | * |
||
476 | * @param int $state |
||
477 | */ |
||
478 | private function setState(int $state) |
||
482 | |||
483 | /** |
||
484 | * @return InsertCommand |
||
485 | */ |
||
486 | private function prepareInsert(): InsertCommand |
||
507 | |||
508 | /** |
||
509 | * @return UpdateCommand |
||
510 | */ |
||
511 | private function prepareUpdate(): UpdateCommand |
||
533 | |||
534 | /** |
||
535 | * @return DeleteCommand |
||
536 | */ |
||
537 | private function prepareDelete(): DeleteCommand |
||
557 | |||
558 | /** |
||
559 | * Get WHERE array to be used to perform record data update or deletion. Usually will include |
||
560 | * record primary key. |
||
561 | * |
||
562 | * Usually just [ID => value] array. |
||
563 | * |
||
564 | * @return array |
||
565 | */ |
||
566 | private function stateCriteria() |
||
582 | |||
583 | /** |
||
584 | * Create set of fields to be sent to UPDATE statement. |
||
585 | * |
||
586 | * @param bool $skipPrimaries Remove primary keys from update statement. |
||
587 | * |
||
588 | * @return array |
||
589 | */ |
||
590 | private function compileUpdates(bool $skipPrimaries = false): array |
||
628 | |||
629 | /** |
||
630 | * Indicate that all updates done, reset dirty state. |
||
631 | */ |
||
632 | private function flushUpdates() |
||
642 | |||
643 | /** |
||
644 | * @param string $name |
||
645 | */ |
||
646 | private function registerChange(string $name) |
||
657 | |||
658 | /** |
||
659 | * Extract relations data from given entity fields. |
||
660 | * |
||
661 | * @param array $data |
||
662 | */ |
||
663 | private function extractRelations(array &$data) |
||
673 | } |
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.