Complex classes like Member 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 Member, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
55 | class Member extends ManagedModel implements |
||
56 | IMemberships, |
||
57 | IFederatedUser, |
||
58 | IDeserializable, |
||
59 | INC22QueryRow, |
||
60 | JsonSerializable { |
||
61 | |||
62 | |||
63 | use TArrayTools; |
||
64 | use TNC22Deserialize; |
||
65 | |||
66 | |||
67 | const LEVEL_NONE = 0; |
||
68 | const LEVEL_MEMBER = 1; |
||
69 | const LEVEL_MODERATOR = 4; |
||
70 | const LEVEL_ADMIN = 8; |
||
71 | const LEVEL_OWNER = 9; |
||
72 | |||
73 | const TYPE_SINGLE = 0; |
||
74 | const TYPE_USER = 1; |
||
75 | const TYPE_GROUP = 2; |
||
76 | const TYPE_MAIL = 4; |
||
77 | const TYPE_CONTACT = 8; |
||
78 | const TYPE_CIRCLE = 16; |
||
79 | const TYPE_APP = 10000; |
||
80 | const APP_CIRCLES = 10001; |
||
81 | |||
82 | |||
83 | public static $TYPE = [ |
||
84 | 0 => 'single', |
||
85 | 1 => 'user', |
||
86 | 2 => 'group', |
||
87 | 4 => 'mail', |
||
88 | 8 => 'contact', |
||
89 | 16 => 'circle', |
||
90 | 10000 => 'app' |
||
91 | ]; |
||
92 | |||
93 | /** |
||
94 | * Note: When editing those values, update lib/Application/Capabilities.php |
||
95 | * |
||
96 | * @see Capabilities::generateConstantsMember() |
||
97 | */ |
||
98 | const STATUS_INVITED = 'Invited'; |
||
99 | const STATUS_REQUEST = 'Requesting'; |
||
100 | const STATUS_MEMBER = 'Member'; |
||
101 | const STATUS_BLOCKED = 'Blocked'; |
||
102 | |||
103 | |||
104 | /** |
||
105 | * Note: When editing those values, update lib/Application/Capabilities.php |
||
106 | * |
||
107 | * @see Capabilities::generateConstantsMember() |
||
108 | * @var array |
||
109 | */ |
||
110 | public static $DEF_LEVEL = [ |
||
111 | 1 => 'Member', |
||
112 | 4 => 'Moderator', |
||
113 | 8 => 'Admin', |
||
114 | 9 => 'Owner' |
||
115 | ]; |
||
116 | |||
117 | |||
118 | public static $DEF_TYPE_MAX = 31; |
||
119 | |||
120 | |||
121 | /** @var string */ |
||
122 | private $id = ''; |
||
123 | |||
124 | /** @var string */ |
||
125 | private $circleId = ''; |
||
126 | |||
127 | /** @var string */ |
||
128 | private $singleId = ''; |
||
129 | |||
130 | /** @var string */ |
||
131 | private $userId = ''; |
||
132 | |||
133 | /** @var int */ |
||
134 | private $userType = 0; |
||
135 | |||
136 | /** @var Circle */ |
||
137 | private $basedOn; |
||
138 | |||
139 | /** @var Member */ |
||
140 | private $inheritanceFrom; |
||
141 | |||
142 | /** @var FederatedUser */ |
||
143 | private $inheritedBy; |
||
144 | |||
145 | /** @var string */ |
||
146 | private $instance = ''; |
||
147 | |||
148 | /** @var RemoteInstance */ |
||
149 | private $remoteInstance; |
||
150 | |||
151 | /** @var bool */ |
||
152 | private $local = false; |
||
153 | |||
154 | /** @var int */ |
||
155 | private $level = 0; |
||
156 | |||
157 | /** @var string */ |
||
158 | private $status = 'Unknown'; |
||
159 | |||
160 | /** @var string */ |
||
161 | private $note = ''; |
||
162 | |||
163 | /** @var string */ |
||
164 | private $displayName = ''; |
||
165 | |||
166 | /** @var int */ |
||
167 | private $displayUpdate = 0; |
||
168 | |||
169 | /** @var string */ |
||
170 | private $contactId = ''; |
||
171 | |||
172 | /** @var string */ |
||
173 | private $contactMeta = ''; |
||
174 | |||
175 | /** @var Circle */ |
||
176 | private $circle; |
||
177 | |||
178 | /** @var int */ |
||
179 | private $joined = 0; |
||
180 | |||
181 | /** @var Membership[] */ |
||
182 | private $memberships = null; |
||
183 | |||
184 | |||
185 | /** |
||
186 | * Member constructor. |
||
187 | */ |
||
188 | public function __construct() { |
||
190 | |||
191 | |||
192 | /** |
||
193 | * @param string $id |
||
194 | * |
||
195 | * @return $this |
||
196 | */ |
||
197 | public function setId(string $id): self { |
||
202 | |||
203 | /** |
||
204 | * @return string |
||
205 | */ |
||
206 | public function getId(): string { |
||
209 | |||
210 | |||
211 | /** |
||
212 | * @param string $circleId |
||
213 | * |
||
214 | * @return Member |
||
215 | */ |
||
216 | public function setCircleId(string $circleId): self { |
||
221 | |||
222 | /** |
||
223 | * @return string |
||
224 | */ |
||
225 | public function getCircleId(): string { |
||
228 | |||
229 | |||
230 | /** |
||
231 | * This should replace user_id, user_type and instance; and will use the data from Circle with |
||
232 | * Config=CFG_SINGLE |
||
233 | * |
||
234 | * @param string $singleId |
||
235 | * |
||
236 | * @return $this |
||
237 | */ |
||
238 | public function setSingleId(string $singleId): self { |
||
243 | |||
244 | /** |
||
245 | * @return string |
||
246 | */ |
||
247 | public function getSingleId(): string { |
||
250 | |||
251 | |||
252 | /** |
||
253 | * @param string $userId |
||
254 | * |
||
255 | * @return Member |
||
256 | */ |
||
257 | public function setUserId(string $userId): self { |
||
265 | |||
266 | /** |
||
267 | * @return string |
||
268 | */ |
||
269 | public function getUserId(): string { |
||
272 | |||
273 | |||
274 | /** |
||
275 | * @param int $userType |
||
276 | * |
||
277 | * @return Member |
||
278 | */ |
||
279 | public function setUserType(int $userType): self { |
||
284 | |||
285 | /** |
||
286 | * @return int |
||
287 | */ |
||
288 | public function getUserType(): int { |
||
291 | |||
292 | |||
293 | /** |
||
294 | * @param string $instance |
||
295 | * |
||
296 | * @return Member |
||
297 | */ |
||
298 | public function setInstance(string $instance): self { |
||
303 | |||
304 | /** |
||
305 | * @return string |
||
306 | */ |
||
307 | public function getInstance(): string { |
||
310 | |||
311 | |||
312 | /** |
||
313 | * @return bool |
||
314 | */ |
||
315 | public function hasRemoteInstance(): bool { |
||
318 | |||
319 | /** |
||
320 | * @param RemoteInstance $remoteInstance |
||
321 | * |
||
322 | * @return Member |
||
323 | */ |
||
324 | public function setRemoteInstance(RemoteInstance $remoteInstance): self { |
||
329 | |||
330 | /** |
||
331 | * @return RemoteInstance |
||
332 | */ |
||
333 | public function getRemoteInstance(): RemoteInstance { |
||
336 | |||
337 | |||
338 | /** |
||
339 | * @return bool |
||
340 | */ |
||
341 | public function hasBasedOn(): bool { |
||
344 | |||
345 | /** |
||
346 | * @param Circle $basedOn |
||
347 | * |
||
348 | * @return $this |
||
349 | */ |
||
350 | public function setBasedOn(Circle $basedOn): self { |
||
355 | |||
356 | /** |
||
357 | * @return Circle |
||
358 | */ |
||
359 | public function getBasedOn(): Circle { |
||
362 | |||
363 | |||
364 | /** |
||
365 | * @return bool |
||
366 | */ |
||
367 | public function hasInheritedBy(): bool { |
||
370 | |||
371 | /** |
||
372 | * @param FederatedUser $inheritedBy |
||
373 | * |
||
374 | * @return $this |
||
375 | */ |
||
376 | public function setInheritedBy(FederatedUser $inheritedBy): self { |
||
381 | |||
382 | /** |
||
383 | * @return FederatedUser |
||
384 | */ |
||
385 | public function getInheritedBy(): FederatedUser { |
||
388 | |||
389 | |||
390 | /** |
||
391 | * @return bool |
||
392 | */ |
||
393 | public function hasInheritanceFrom(): bool { |
||
396 | |||
397 | /** |
||
398 | * @param Member $inheritanceFrom |
||
399 | * |
||
400 | * @return $this |
||
401 | */ |
||
402 | public function setInheritanceFrom(Member $inheritanceFrom): self { |
||
407 | |||
408 | /** |
||
409 | * @return Member|null |
||
410 | */ |
||
411 | public function getInheritanceFrom(): ?Member { |
||
414 | |||
415 | |||
416 | /** |
||
417 | * @param bool $local |
||
418 | * |
||
419 | * @return Member |
||
420 | */ |
||
421 | public function setLocal(bool $local): self { |
||
426 | |||
427 | /** |
||
428 | * @return bool |
||
429 | */ |
||
430 | public function isLocal(): bool { |
||
433 | |||
434 | |||
435 | /** |
||
436 | * @param int $level |
||
437 | * |
||
438 | * @return Member |
||
439 | */ |
||
440 | public function setLevel(int $level): self { |
||
445 | |||
446 | /** |
||
447 | * @return int |
||
448 | */ |
||
449 | public function getLevel(): int { |
||
452 | |||
453 | |||
454 | /** |
||
455 | * @param string $status |
||
456 | * |
||
457 | * @return Member |
||
458 | */ |
||
459 | public function setStatus(string $status): self { |
||
464 | |||
465 | /** |
||
466 | * @return string |
||
467 | */ |
||
468 | public function getStatus(): string { |
||
471 | |||
472 | |||
473 | /** |
||
474 | * @param string $note |
||
475 | * |
||
476 | * @return Member |
||
477 | */ |
||
478 | public function setNote(string $note): self { |
||
483 | |||
484 | /** |
||
485 | * @return string |
||
486 | */ |
||
487 | public function getNote(): string { |
||
490 | |||
491 | |||
492 | /** |
||
493 | * @param string $displayName |
||
494 | * |
||
495 | * @return Member |
||
496 | */ |
||
497 | public function setDisplayName(string $displayName): self { |
||
504 | |||
505 | |||
506 | /** |
||
507 | * @param int $displayUpdate |
||
508 | * |
||
509 | * @return Member |
||
510 | */ |
||
511 | public function setDisplayUpdate(int $displayUpdate): self { |
||
516 | |||
517 | /** |
||
518 | * @return int |
||
519 | */ |
||
520 | public function getDisplayUpdate(): int { |
||
523 | |||
524 | |||
525 | /** |
||
526 | * @return string |
||
527 | */ |
||
528 | public function getDisplayName(): string { |
||
531 | |||
532 | |||
533 | /** |
||
534 | * @param string $contactId |
||
535 | * |
||
536 | * @return Member |
||
537 | */ |
||
538 | public function setContactId(string $contactId): self { |
||
543 | |||
544 | /** |
||
545 | * @return string |
||
546 | */ |
||
547 | public function getContactId(): string { |
||
550 | |||
551 | |||
552 | /** |
||
553 | * @param string $contactMeta |
||
554 | * |
||
555 | * @return Member |
||
556 | */ |
||
557 | public function setContactMeta(string $contactMeta): self { |
||
562 | |||
563 | /** |
||
564 | * @return string |
||
565 | */ |
||
566 | public function getContactMeta(): string { |
||
569 | |||
570 | |||
571 | /** |
||
572 | * @param Circle $circle |
||
573 | * |
||
574 | * @return self |
||
575 | */ |
||
576 | public function setCircle(Circle $circle): self { |
||
581 | |||
582 | /** |
||
583 | * @return Circle |
||
584 | */ |
||
585 | public function getCircle(): Circle { |
||
588 | |||
589 | /** |
||
590 | * @return bool |
||
591 | */ |
||
592 | public function hasCircle(): bool { |
||
595 | |||
596 | |||
597 | /** |
||
598 | * @param int $joined |
||
599 | * |
||
600 | * @return Member |
||
601 | */ |
||
602 | public function setJoined(int $joined): self { |
||
607 | |||
608 | /** |
||
609 | * @return int |
||
610 | */ |
||
611 | public function getJoined(): int { |
||
614 | |||
615 | |||
616 | /** |
||
617 | * @return bool |
||
618 | */ |
||
619 | public function hasMemberships(): bool { |
||
622 | |||
623 | /** |
||
624 | * @param array $memberships |
||
625 | * |
||
626 | * @return self |
||
627 | */ |
||
628 | public function setMemberships(array $memberships): IMemberships { |
||
633 | |||
634 | /** |
||
635 | * @return Membership[] |
||
636 | */ |
||
637 | public function getMemberships(): array { |
||
644 | |||
645 | |||
646 | /** |
||
647 | * @param Member $member |
||
648 | * @param bool $full |
||
649 | * |
||
650 | * @return bool |
||
651 | */ |
||
652 | public function compareWith(Member $member, bool $full = true): bool { |
||
670 | |||
671 | |||
672 | /** |
||
673 | * @param array $data |
||
674 | * |
||
675 | * @return $this |
||
676 | * @throws InvalidItemException |
||
677 | */ |
||
678 | public function import(array $data): IDeserializable { |
||
722 | |||
723 | |||
724 | /** |
||
725 | * @param array $data |
||
726 | * @param string $prefix |
||
727 | * |
||
728 | * @return INC22QueryRow |
||
729 | * @throws MemberNotFoundException |
||
730 | */ |
||
731 | public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow { |
||
768 | |||
769 | |||
770 | /** |
||
771 | * @return string[] |
||
772 | */ |
||
773 | public function jsonSerialize(): array { |
||
818 | |||
819 | |||
820 | /** |
||
821 | * @param int $level |
||
822 | * |
||
823 | * @return int |
||
824 | * @throws ParseMemberLevelException |
||
825 | */ |
||
826 | public static function parseLevelInt(int $level): int { |
||
834 | |||
835 | |||
836 | /** |
||
837 | * @param string $levelString |
||
838 | * |
||
839 | * @return int |
||
840 | * @throws ParseMemberLevelException |
||
841 | */ |
||
842 | public static function parseLevelString(string $levelString): int { |
||
853 | |||
854 | /** |
||
855 | * @param string $typeString |
||
856 | * |
||
857 | * @return int |
||
858 | * @throws UserTypeNotFoundException |
||
859 | */ |
||
860 | public static function parseTypeString(string $typeString): int { |
||
871 | |||
872 | } |
||
873 | |||
874 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.