Completed
Push — master ( 3ddca8...414a73 )
by Maxence
02:57
created

Circle::getName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Model;
33
34
35
use daita\MySmallPhpTools\Db\Nextcloud\nc22\INC22QueryRow;
36
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
37
use daita\MySmallPhpTools\IDeserializable;
38
use daita\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize;
39
use daita\MySmallPhpTools\Traits\TArrayTools;
40
use DateTime;
41
use JsonSerializable;
42
use OCA\Circles\Exceptions\CircleNotFoundException;
43
use OCA\Circles\Exceptions\OwnerNotFoundException;
44
use OCA\Circles\IMemberships;
45
46
47
/**
48
 * Class Circle
49
 *
50
 * ** examples of use of bitwise flags for members management:
51
 *      CFG_OPEN, CFG_REQUEST, CFG_INVITE, CFG_FRIEND
52
 *
53
 * - CFG_OPEN                             => everyone can enter. moderator can add members.
54
 * - CFG_OPEN | CFG_REQUEST               => anyone can initiate a request to join the circle, moderator can
55
 *                                           add members
56
 * - CFG_OPEN | CFG_INVITE                => every one can enter, moderator must send invitation.
57
 * - CFG_OPEN | CFG_INVITE | CFG_REQUEST  => every one send a request, moderator must send invitation.
58
 * - CFG_OPEN | CFG_FRIEND                => useless
59
 * - CFG_OPEN | CFG_FRIEND | *            => useless
60
 *
61
 * - CFG_CIRCLE                           => no one can enter, moderator can add members.
62
 *                                           default config, this is only for code readability.
63
 * - CFG_INVITE                           => no one can enter, moderator must send invitation.
64
 * - CFG_FRIEND                           => no one can enter, but all members can add new member.
65
 * - CFG_REQUEST                          => useless (use CFG_OPEN | CFG_REQUEST)
66
 * - CFG_FRIEND | CFG_REQUEST             => no one can join the circle, but all members can request a
67
 *                                           moderator to accept new member
68
 * - CFG_FRIEND | CFG_INVITE              => no one can join the circle, but all members can add new member.
69
 *                                           An invitation will be generated
70
 * - CFG_FRIEND | CFG_INVITE | CFG_REQUEST  => no one can join the circle, but all members can request a
71
 *                                             moderator to accept new member. An invitation will be generated
72
 *
73
 * @package OCA\Circles\Model
74
 */
75
class Circle extends ManagedModel implements IMemberships, IDeserializable, INC22QueryRow, JsonSerializable {
76
77
78
	use TArrayTools;
79
	use TNC22Deserialize;
80
81
82
	const FLAGS_SHORT = 1;
83
	const FLAGS_LONG = 2;
84
85
86
	// specific value
87
	const CFG_CIRCLE = 0;        // only for code readability. Circle is locked by default.
88
	const CFG_SINGLE = 1;        // Circle with only one single member.
89
	const CFG_PERSONAL = 2;      // Personal circle, only the owner can see it.
90
91
	// bitwise
92
	const CFG_SYSTEM = 4;            // System Circle (not managed by the official front-end). Meaning some config are limited
93
	const CFG_VISIBLE = 8;           // Visible to everyone, if not visible, people have to know its name to be able to find it
94
	const CFG_OPEN = 16;             // Circle is open, people can join
95
	const CFG_INVITE = 32;           // Adding a member generate an invitation that needs to be accepted
96
	const CFG_REQUEST = 64;          // Request to join Circles needs to be confirmed by a moderator
97
	const CFG_FRIEND = 128;          // Members of the circle can invite their friends
98
	const CFG_PROTECTED = 256;       // Password protected to join/request
99
	const CFG_NO_OWNER = 512;        // no owner, only members
100
	const CFG_HIDDEN = 1024;         // hidden from listing, but available as a share entity
101
	const CFG_BACKEND = 2048;            // Fully hidden, only backend Circles
102
	const CFG_LOCAL = 4096;              // Local even on GlobalScale
103
	const CFG_ROOT = 8192;               // Circle cannot be inside another Circle
104
	const CFG_CIRCLE_INVITE = 16384;     // Circle must confirm when invited in another circle
105
	const CFG_FEDERATED = 32768;         // Federated
106
	const CFG_MOUNTPOINT = 65536;        // Generate a Files folder for this Circle
107
108
	public static $DEF_CFG_MAX = 131071;
109
110
111
	/**
112
	 * Note: When editing those values, update lib/Application/Capabilities.php
113
	 *
114
	 * @see Capabilities::getCapabilitiesCircleConstants()
115
	 * @var array
116
	 */
117
	public static $DEF_CFG = [
118
		1     => 'S|Single',
119
		2     => 'P|Personal',
120
		4     => 'Y|System',
121
		8     => 'V|Visible',
122
		16    => 'O|Open',
123
		32    => 'I|Invite',
124
		64    => 'JR|Join Request',
125
		128   => 'F|Friends',
126
		256   => 'PP|Password Protected',
127
		512   => 'NO|No Owner',
128
		1024  => 'H|Hidden',
129
		2048  => 'T|Backend',
130
		4096  => 'L|Local',
131
		8192  => 'T|Root',
132
		16384 => 'CI|Circle Invite',
133
		32768 => 'F|Federated',
134
		65536 => 'M|Nountpoint'
135
	];
136
137
138
	/**
139
	 * Note: When editing those values, update lib/Application/Capabilities.php
140
	 *
141
	 * @see Capabilities::getCapabilitiesCircleConstants()
142
	 * @var array
143
	 */
144
	public static $DEF_SOURCE = [
145
		1     => 'Nextcloud User',
146
		2     => 'Nextcloud Group',
147
		4     => 'Mail Address',
148
		8     => 'Contact',
149
		16    => 'Circle',
150
		10001 => 'Circles App'
151
	];
152
153
154
	public static $DEF_CFG_CORE_FILTER = [
155
		1,
156
		2,
157
		4
158
	];
159
160
	public static $DEF_CFG_SYSTEM_FILTER = [
161
		512,
162
		1024,
163
		2048
164
	];
165
166
167
	/** @var string */
168
	private $singleId = '';
169
170
	/** @var int */
171
	private $config = 0;
172
173
	/** @var string */
174
	private $name = '';
175
176
	/** @var string */
177
	private $displayName = '';
178
179
	/** @var int */
180
	private $source = 0;
181
182
	/** @var Member */
183
	private $owner;
184
185
	/** @var Member */
186
	private $initiator;
187
188
	/** @var array */
189
	private $settings = [];
190
191
	/** @var string */
192
	private $description = '';
193
194
	/** @var int */
195
	private $contactAddressBook = 0;
196
197
	/** @var string */
198
	private $contactGroupName = '';
199
200
	/** @var string */
201
	private $instance = '';
202
203
//	/** @var bool */
204
//	private $hidden = false;
205
206
	/** @var int */
207
	private $creation = 0;
208
209
210
	/** @var Member[] */
211
	private $members = null;
212
213
	/** @var Member[] */
214
	private $inheritedMembers = null;
215
216
	/** @var bool */
217
	private $detailedInheritedMember = false;
218
219
	/** @var Membership[] */
220
	private $memberships = null;
221
222
223
	/**
224
	 * Circle constructor.
225
	 */
226
	public function __construct() {
227
	}
228
229
	/**
230
	 * @param string $singleId
231
	 *
232
	 * @return self
233
	 */
234
	public function setSingleId(string $singleId): self {
235
		$this->singleId = $singleId;
236
237
		return $this;
238
	}
239
240
	/**
241
	 * @return string
242
	 */
243
	public function getSingleId(): string {
244
		return $this->singleId;
245
	}
246
247
248
	/**
249
	 * @param int $config
250
	 *
251
	 * @return self
252
	 */
253
	public function setConfig(int $config): self {
254
		$this->config = $config;
255
256
		return $this;
257
	}
258
259
	/**
260
	 * @return int
261
	 */
262
	public function getConfig(): int {
263
		return $this->config;
264
	}
265
266
	/**
267
	 * @param int $flag
268
	 * @param int $test
269
	 *
270
	 * @return bool
271
	 */
272
	public function isConfig(int $flag, int $test = 0): bool {
273
		if ($test === 0) {
274
			$test = $this->getConfig();
275
		}
276
277
		return (($test & $flag) !== 0);
278
	}
279
280
	/**
281
	 * @param int $flag
282
	 */
283
	public function addConfig(int $flag): void {
284
		if (!$this->isConfig($flag)) {
285
			$this->config += $flag;
286
		}
287
	}
288
289
	/**
290
	 * @param int $flag
291
	 */
292
	public function remConfig(int $flag): void {
293
		if ($this->isConfig($flag)) {
294
			$this->config -= $flag;
295
		}
296
	}
297
298
299
	/**
300
	 * @param string $name
301
	 *
302
	 * @return self
303
	 */
304
	public function setName(string $name): self {
305
		$this->name = $name;
306
		if ($this->displayName === '') {
307
			$this->displayName = $name;
308
		}
309
310
		return $this;
311
	}
312
313
	/**
314
	 * @return string
315
	 */
316
	public function getName(): string {
317
		return $this->name;
318
	}
319
320
321
	/**
322
	 * @param string $displayName
323
	 *
324
	 * @return self
325
	 */
326
	public function setDisplayName(string $displayName): self {
327
		if ($displayName !== '') {
328
			$this->displayName = $displayName;
329
		}
330
331
		return $this;
332
	}
333
334
	/**
335
	 * @return string
336
	 */
337
	public function getDisplayName(): string {
338
		return $this->displayName;
339
	}
340
341
342
	/**
343
	 * @param int $source
344
	 *
345
	 * @return Circle
346
	 */
347
	public function setSource(int $source): self {
348
		$this->source = $source;
349
350
		return $this;
351
	}
352
353
	/**
354
	 * @return int
355
	 */
356
	public function getSource(): int {
357
		return $this->source;
358
	}
359
360
361
	/**
362
	 * @param ?Member $owner
0 ignored issues
show
Documentation introduced by
The doc-type ?Member could not be parsed: Unknown type name "?Member" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
363
	 *
364
	 * @return self
365
	 */
366
	public function setOwner(?Member $owner): self {
367
		$this->owner = $owner;
368
369
		return $this;
370
	}
371
372
	/**
373
	 * @return Member
374
	 */
375
	public function getOwner(): Member {
376
		return $this->owner;
377
	}
378
379
	/**
380
	 * @return bool
381
	 */
382
	public function hasOwner(): bool {
383
		return ($this->owner !== null);
384
	}
385
386
387
	/**
388
	 * @return bool
389
	 */
390
	public function hasMembers(): bool {
391
		return !is_null($this->members);
392
	}
393
394
	/**
395
	 * @param array $members
396
	 *
397
	 * @return self
398
	 */
399
	public function setMembers(array $members): IMemberships {
400
		$this->members = $members;
401
402
		return $this;
403
	}
404
405
	/**
406
	 * @return array
407
	 */
408
	public function getMembers(): array {
409
		if (!$this->hasMembers()) {
410
			$this->getManager()->getMembers($this);
411
		}
412
413
		return $this->members;
414
	}
415
416
417
	/**
418
	 * @param array $members
419
	 * @param bool $detailed
420
	 *
421
	 * @return self
422
	 */
423
	public function setInheritedMembers(array $members, bool $detailed): IMemberships {
424
		$this->inheritedMembers = $members;
425
		$this->detailedInheritedMember = $detailed;
426
427
		return $this;
428
	}
429
430
	/**
431
	 * @param bool $detailed
432
	 *
433
	 * @return array
434
	 */
435
	public function getInheritedMembers(bool $detailed = false): array {
436
		if (is_null($this->inheritedMembers)
437
			|| ($detailed && !$this->detailedInheritedMember)) {
438
			$this->getManager()->getInheritedMembers($this, $detailed);
439
		}
440
441
		return $this->inheritedMembers;
442
	}
443
444
445
	/**
446
	 * @return bool
447
	 */
448
	public function hasMemberships(): bool {
449
		return !is_null($this->memberships);
450
	}
451
452
	/**
453
	 * @param array $memberships
454
	 *
455
	 * @return self
456
	 */
457
	public function setMemberships(array $memberships): IMemberships {
458
		$this->memberships = $memberships;
459
460
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\Circle) is incompatible with the return type declared by the interface OCA\Circles\IMemberships::setMemberships of type self.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
461
	}
462
463
	/**
464
	 * @return Membership[]
465
	 */
466
	public function getMemberships(): array {
467
		if (!$this->hasMemberships()) {
468
			$this->getManager()->getMemberships($this);
469
		}
470
471
		return $this->memberships;
472
	}
473
474
475
	/**
476
	 * @param Member|null $initiator
477
	 *
478
	 * @return Circle
479
	 */
480
	public function setInitiator(?Member $initiator): self {
481
		$this->initiator = $initiator;
482
483
		return $this;
484
	}
485
486
	/**
487
	 * @return Member
488
	 */
489
	public function getInitiator(): Member {
490
		return $this->initiator;
491
	}
492
493
	/**
494
	 * @return bool
495
	 */
496
	public function hasInitiator(): bool {
497
		return ($this->initiator !== null);
498
	}
499
500
	/**
501
	 * @param string $instance
502
	 *
503
	 * @return Circle
504
	 */
505
	public function setInstance(string $instance): self {
506
		if ($this->isConfig(self::CFG_NO_OWNER)) {
507
			$this->instance = $instance;
508
		}
509
510
		return $this;
511
	}
512
513
	/**
514
	 * @return string
515
	 * @throws OwnerNotFoundException
516
	 */
517
	public function getInstance(): string {
518
		if (!$this->hasOwner()) {
519
			throw new OwnerNotFoundException('circle has no owner');
520
		}
521
522
		return $this->getOwner()->getInstance();
523
	}
524
525
526
	/**
527
	 * @param array $settings
528
	 *
529
	 * @return self
530
	 */
531
	public function setSettings(array $settings): self {
532
		$this->settings = $settings;
533
534
		return $this;
535
	}
536
537
	/**
538
	 * @return array
539
	 */
540
	public function getSettings(): array {
541
		return $this->settings;
542
	}
543
544
545
	/**
546
	 * @param string $description
547
	 *
548
	 * @return self
549
	 */
550
	public function setDescription(string $description): self {
551
		$this->description = $description;
552
553
		return $this;
554
	}
555
556
	/**
557
	 * @return string
558
	 */
559
	public function getDescription(): string {
560
		return $this->description;
561
	}
562
563
564
	/**
565
	 * @return string
566
	 */
567
	public function getLink(): string {
568
		return $this->getManager()->generateLinkToCircle($this->getSingleId());
569
	}
570
571
572
	/**
573
	 * @param int $contactAddressBook
574
	 *
575
	 * @return self
576
	 */
577
	public function setContactAddressBook(int $contactAddressBook): self {
578
		$this->contactAddressBook = $contactAddressBook;
579
580
		return $this;
581
	}
582
583
	/**
584
	 * @return int
585
	 */
586
	public function getContactAddressBook(): int {
587
		return $this->contactAddressBook;
588
	}
589
590
591
	/**
592
	 * @param string $contactGroupName
593
	 *
594
	 * @return self
595
	 */
596
	public function setContactGroupName(string $contactGroupName): self {
597
		$this->contactGroupName = $contactGroupName;
598
599
		return $this;
600
	}
601
602
	/**
603
	 * @return string
604
	 */
605
	public function getContactGroupName(): string {
606
		return $this->contactGroupName;
607
	}
608
609
610
	/**
611
	 * @param int $creation
612
	 *
613
	 * @return self
614
	 */
615
	public function setCreation(int $creation): self {
616
		$this->creation = $creation;
617
618
		return $this;
619
	}
620
621
	/**
622
	 * @return int
623
	 */
624
	public function getCreation(): int {
625
		return $this->creation;
626
	}
627
628
629
	/**
630
	 * @param array $data
631
	 *
632
	 * @return $this
633
	 * @throws InvalidItemException
634
	 */
635
	public function import(array $data): IDeserializable {
636
		if ($this->get('id', $data) === '') {
637
			throw new InvalidItemException();
638
		}
639
640
		$this->setSingleId($this->get('id', $data))
641
			 ->setName($this->get('name', $data))
642
			 ->setDisplayName($this->get('displayName', $data))
643
			 ->setSource($this->getInt('source', $data))
644
			 ->setConfig($this->getInt('config', $data))
645
			 ->setSettings($this->getArray('settings', $data))
646
//			 ->setContactAddressBook($this->get('contact_addressbook', $data))
647
//			 ->setContactGroupName($this->get('contact_groupname', $data))
648
			 ->setDescription($this->get('description', $data))
649
			 ->setCreation($this->getInt('creation', $data));
650
651
		try {
652
			/** @var Member $owner */
653
			$owner = $this->deserialize($this->getArray('owner', $data), Member::class);
654
			$this->setOwner($owner);
655
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
656
		}
657
658
		try {
659
			/** @var Member $initiator */
660
			$initiator = $this->deserialize($this->getArray('initiator', $data), Member::class);
661
			$this->setInitiator($initiator);
662
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
663
		}
664
665
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\Circle) is incompatible with the return type declared by the interface daita\MySmallPhpTools\IDeserializable::import of type self.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
666
	}
667
668
669
	/**
670
	 * @return array
671
	 */
672
	public function jsonSerialize(): array {
673
		$arr = [
674
			'id'          => $this->getSingleId(),
675
			'name'        => $this->getName(),
676
			'displayName' => $this->getDisplayName(),
677
			'source'      => $this->getSource(),
678
			'config'      => $this->getConfig(),
679
			'description' => $this->getDescription(),
680
			'settings'    => $this->getSettings(),
681
			'link'        => $this->getLink(),
682
			'creation'    => $this->getCreation(),
683
			'initiator'   => ($this->hasInitiator()) ? $this->getInitiator() : null
684
		];
685
686
		if ($this->hasOwner()) {
687
			$arr['owner'] = $this->getOwner();
688
		}
689
690
		if ($this->hasMembers()) {
691
			$arr['members'] = $this->getMembers();
692
		}
693
694
		if (!is_null($this->inheritedMembers)) {
695
			$arr['inheritedMembers'] = $this->getInheritedMembers();
696
		}
697
698
		if ($this->hasMemberships()) {
699
			$arr['memberships'] = $this->getMemberships();
700
		}
701
702
		return $arr;
703
	}
704
705
706
	/**
707
	 * @param array $data
708
	 * @param string $prefix
709
	 *
710
	 * @return INC22QueryRow
711
	 * @throws CircleNotFoundException
712
	 */
713
	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
714
		if ($this->get($prefix . 'unique_id', $data) === '') {
715
			throw new CircleNotFoundException();
716
		}
717
718
		$this->setSingleId($this->get($prefix . 'unique_id', $data))
719
			 ->setName($this->get($prefix . 'name', $data))
720
			 ->setDisplayName($this->get($prefix . 'display_name', $data))
721
			 ->setConfig($this->getInt($prefix . 'config', $data))
722
			 ->setSource($this->getInt($prefix . 'source', $data))
723
			 ->setInstance($this->get($prefix . 'instance', $data))
724
			 ->setSettings($this->getArray($prefix . 'settings', $data))
725
			 ->setContactAddressBook($this->getInt($prefix . 'contact_addressbook', $data))
726
			 ->setContactGroupName($this->get($prefix . 'contact_groupname', $data))
727
			 ->setDescription($this->get($prefix . 'description', $data));
728
729
		$creation = $this->get($prefix . 'creation', $data);
730
		$this->setCreation(DateTime::createFromFormat('Y-m-d H:i:s', $creation)->getTimestamp());
731
732
		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
733
734
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\Circle) is incompatible with the return type declared by the interface daita\MySmallPhpTools\Db...Row::importFromDatabase of type self.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
735
	}
736
737
738
	/**
739
	 * @param Circle $circle
740
	 *
741
	 * @return bool
742
	 * @throws OwnerNotFoundException
743
	 */
744
	public function compareWith(Circle $circle): bool {
745
		if ($this->getSingleId() !== $circle->getSingleId()
746
			|| $this->getInstance() !== $circle->getInstance()
747
			|| $this->getConfig() !== $circle->getConfig()) {
748
			return false;
749
		}
750
751
		if ($this->hasOwner()
752
			&& (!$circle->hasOwner()
753
				|| !$this->getOwner()->compareWith($circle->getOwner()))) {
754
			return false;
755
		}
756
757
		if ($this->hasInitiator()
758
			&& (!$circle->hasInitiator()
759
				|| !$this->getInitiator()->compareWith($circle->getInitiator()))) {
760
			return false;
761
		}
762
763
		return true;
764
	}
765
766
767
	/**
768
	 * @param Circle $circle
769
	 * @param int $display
770
	 *
771
	 * @return array
772
	 */
773
	public static function getCircleFlags(Circle $circle, int $display = self::FLAGS_LONG): array {
774
		$config = [];
775
		foreach (array_keys(Circle::$DEF_CFG) as $def) {
776
			if ($circle->isConfig($def)) {
777
				list($short, $long) = explode('|', Circle::$DEF_CFG[$def]);
778
				switch ($display) {
779
780
					case self::FLAGS_SHORT:
781
						$config[] = $short;
782
						break;
783
784
					case self::FLAGS_LONG:
785
						$config[] = $long;
786
						break;
787
				}
788
			}
789
		}
790
791
		return $config;
792
	}
793
794
}
795
796