Completed
Pull Request — master (#633)
by Maxence
03:06
created

Circle::setSanitizedName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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 ArtificialOwl\MySmallPhpTools\Db\Nextcloud\nc22\INC22QueryRow;
36
use ArtificialOwl\MySmallPhpTools\Exceptions\InvalidItemException;
37
use ArtificialOwl\MySmallPhpTools\IDeserializable;
38
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize;
39
use ArtificialOwl\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     => 'Email Address',
148
		8     => 'Contact',
149
		16    => 'Circle',
150
		10001 => 'Circles App',
151
		10002 => 'Admin Command Line'
152
	];
153
154
155
	public static $DEF_CFG_CORE_FILTER = [
156
		1,
157
		2,
158
		4
159
	];
160
161
	public static $DEF_CFG_SYSTEM_FILTER = [
162
		512,
163
		1024,
164
		2048
165
	];
166
167
168
	/** @var string */
169
	private $singleId = '';
170
171
	/** @var int */
172
	private $config = 0;
173
174
	/** @var string */
175
	private $name = '';
176
177
	/** @var string */
178
	private $displayName = '';
179
180
	/** @var string */
181
	private $sanitizedName = '';
182
183
	/** @var int */
184
	private $source = 0;
185
186
	/** @var Member */
187
	private $owner;
188
189
	/** @var Member */
190
	private $initiator;
191
192
	/** @var array */
193
	private $settings = [];
194
195
	/** @var string */
196
	private $description = '';
197
198
	/** @var int */
199
	private $contactAddressBook = 0;
200
201
	/** @var string */
202
	private $contactGroupName = '';
203
204
	/** @var string */
205
	private $instance = '';
206
207
	/** @var int */
208
	private $population = 0;
209
210
//	/** @var bool */
211
//	private $hidden = false;
212
213
	/** @var int */
214
	private $creation = 0;
215
216
217
	/** @var Member[] */
218
	private $members = null;
219
220
	/** @var Member[] */
221
	private $inheritedMembers = null;
222
223
	/** @var bool */
224
	private $detailedInheritedMember = false;
225
226
	/** @var Membership[] */
227
	private $memberships = null;
228
229
230
	/**
231
	 * Circle constructor.
232
	 */
233
	public function __construct() {
234
	}
235
236
	/**
237
	 * @param string $singleId
238
	 *
239
	 * @return self
240
	 */
241
	public function setSingleId(string $singleId): self {
242
		$this->singleId = $singleId;
243
244
		return $this;
245
	}
246
247
	/**
248
	 * @return string
249
	 */
250
	public function getSingleId(): string {
251
		return $this->singleId;
252
	}
253
254
	/**
255
	 * @return string
256
	 * @deprecated - removed in NC23
257
	 */
258
	public function getUniqueId(): string {
259
		return $this->getSingleId();
260
	}
261
262
263
	/**
264
	 * @param int $config
265
	 *
266
	 * @return self
267
	 */
268
	public function setConfig(int $config): self {
269
		$this->config = $config;
270
271
		return $this;
272
	}
273
274
	/**
275
	 * @return int
276
	 */
277
	public function getConfig(): int {
278
		return $this->config;
279
	}
280
281
	/**
282
	 * @param int $flag
283
	 * @param int $test
284
	 *
285
	 * @return bool
286
	 */
287
	public function isConfig(int $flag, int $test = 0): bool {
288
		if ($test === 0) {
289
			$test = $this->getConfig();
290
		}
291
292
		return (($test & $flag) !== 0);
293
	}
294
295
	/**
296
	 * @param int $flag
297
	 */
298
	public function addConfig(int $flag): void {
299
		if (!$this->isConfig($flag)) {
300
			$this->config += $flag;
301
		}
302
	}
303
304
	/**
305
	 * @param int $flag
306
	 */
307
	public function remConfig(int $flag): void {
308
		if ($this->isConfig($flag)) {
309
			$this->config -= $flag;
310
		}
311
	}
312
313
314
	/**
315
	 * @param string $name
316
	 *
317
	 * @return self
318
	 */
319
	public function setName(string $name): self {
320
		$this->name = $name;
321
322
		return $this;
323
	}
324
325
	/**
326
	 * @return string
327
	 */
328
	public function getName(): string {
329
		return $this->name;
330
	}
331
332
333
	/**
334
	 * @param string $displayName
335
	 *
336
	 * @return self
337
	 */
338
	public function setDisplayName(string $displayName): self {
339
		$this->displayName = $displayName;
340
341
		return $this;
342
	}
343
344
	/**
345
	 * @return string
346
	 */
347
	public function getDisplayName(): string {
348
		return $this->displayName;
349
	}
350
351
352
	/**
353
	 * @param string $sanitizedName
354
	 *
355
	 * @return Circle
356
	 */
357
	public function setSanitizedName(string $sanitizedName): self {
358
		$this->sanitizedName = $sanitizedName;
359
360
		return $this;
361
	}
362
363
	/**
364
	 * @return string
365
	 */
366
	public function getSanitizedName(): string {
367
		return $this->sanitizedName;
368
	}
369
370
371
	/**
372
	 * @param int $source
373
	 *
374
	 * @return Circle
375
	 */
376
	public function setSource(int $source): self {
377
		$this->source = $source;
378
379
		return $this;
380
	}
381
382
	/**
383
	 * @return int
384
	 */
385
	public function getSource(): int {
386
		return $this->source;
387
	}
388
389
390
	/**
391
	 * @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...
392
	 *
393
	 * @return self
394
	 */
395
	public function setOwner(?Member $owner): self {
396
		$this->owner = $owner;
397
398
		return $this;
399
	}
400
401
	/**
402
	 * @return Member
403
	 */
404
	public function getOwner(): Member {
405
		return $this->owner;
406
	}
407
408
	/**
409
	 * @return bool
410
	 */
411
	public function hasOwner(): bool {
412
		return !is_null($this->owner);
413
	}
414
415
416
	/**
417
	 * @return bool
418
	 */
419
	public function hasMembers(): bool {
420
		return !is_null($this->members);
421
	}
422
423
	/**
424
	 * @param array $members
425
	 *
426
	 * @return self
427
	 */
428
	public function setMembers(array $members): IMemberships {
429
		$this->members = $members;
430
431
		return $this;
432
	}
433
434
	/**
435
	 * @return array
436
	 */
437
	public function getMembers(): array {
438
		if (!$this->hasMembers()) {
439
			$this->getManager()->getMembers($this);
440
		}
441
442
		return $this->members;
443
	}
444
445
446
	/**
447
	 * @param array $members
448
	 * @param bool $detailed
449
	 *
450
	 * @return self
451
	 */
452
	public function setInheritedMembers(array $members, bool $detailed): IMemberships {
453
		$this->inheritedMembers = $members;
454
		$this->detailedInheritedMember = $detailed;
455
456
		return $this;
457
	}
458
459
	/**
460
	 * @param bool $detailed
461
	 *
462
	 * @return Member[]
463
	 */
464
	public function getInheritedMembers(bool $detailed = false): array {
465
		if (is_null($this->inheritedMembers)
466
			|| ($detailed && !$this->detailedInheritedMember)) {
467
			$this->getManager()->getInheritedMembers($this, $detailed);
468
		}
469
470
		return $this->inheritedMembers;
471
	}
472
473
474
	/**
475
	 * @return bool
476
	 */
477
	public function hasMemberships(): bool {
478
		return !is_null($this->memberships);
479
	}
480
481
	/**
482
	 * @param array $memberships
483
	 *
484
	 * @return self
485
	 */
486
	public function setMemberships(array $memberships): IMemberships {
487
		$this->memberships = $memberships;
488
489
		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...
490
	}
491
492
	/**
493
	 * @return Membership[]
494
	 */
495
	public function getMemberships(): array {
496
		if (!$this->hasMemberships()) {
497
			$this->getManager()->getMemberships($this);
498
		}
499
500
		return $this->memberships;
501
	}
502
503
504
	/**
505
	 * @param Member|null $initiator
506
	 *
507
	 * @return Circle
508
	 */
509
	public function setInitiator(?Member $initiator): self {
510
		$this->initiator = $initiator;
511
512
		return $this;
513
	}
514
515
	/**
516
	 * @return Member
517
	 */
518
	public function getInitiator(): Member {
519
		return $this->initiator;
520
	}
521
522
	/**
523
	 * @return bool
524
	 */
525
	public function hasInitiator(): bool {
526
		return ($this->initiator !== null);
527
	}
528
529
	/**
530
	 * @param string $instance
531
	 *
532
	 * @return Circle
533
	 */
534
	public function setInstance(string $instance): self {
535
		if ($this->isConfig(self::CFG_NO_OWNER)) {
536
			$this->instance = $instance;
537
		}
538
539
		return $this;
540
	}
541
542
	/**
543
	 * @return string
544
	 * @throws OwnerNotFoundException
545
	 */
546
	public function getInstance(): string {
547
		if (!$this->hasOwner()) {
548
			throw new OwnerNotFoundException('circle has no owner');
549
		}
550
551
		return $this->getOwner()->getInstance();
552
	}
553
554
555
	/**
556
	 * @param int $population
557
	 *
558
	 * @return Circle
559
	 */
560
	public function setPopulation(int $population): self {
561
		$this->population = $population;
562
563
		return $this;
564
	}
565
566
	/**
567
	 * @return int
568
	 */
569
	public function getPopulation(): int {
570
		return $this->population;
571
	}
572
573
574
	/**
575
	 * @param array $settings
576
	 *
577
	 * @return self
578
	 */
579
	public function setSettings(array $settings): self {
580
		$this->settings = $settings;
581
582
		return $this;
583
	}
584
585
	/**
586
	 * @return array
587
	 */
588
	public function getSettings(): array {
589
		return $this->settings;
590
	}
591
592
593
	/**
594
	 * @param string $description
595
	 *
596
	 * @return self
597
	 */
598
	public function setDescription(string $description): self {
599
		$this->description = $description;
600
601
		return $this;
602
	}
603
604
	/**
605
	 * @return string
606
	 */
607
	public function getDescription(): string {
608
		return $this->description;
609
	}
610
611
612
	/**
613
	 * @return string
614
	 */
615
	public function getUrl(): string {
616
		return $this->getManager()->generateLinkToCircle($this->getSingleId());
617
	}
618
619
620
	/**
621
	 * @param int $contactAddressBook
622
	 *
623
	 * @return self
624
	 */
625
	public function setContactAddressBook(int $contactAddressBook): self {
626
		$this->contactAddressBook = $contactAddressBook;
627
628
		return $this;
629
	}
630
631
	/**
632
	 * @return int
633
	 */
634
	public function getContactAddressBook(): int {
635
		return $this->contactAddressBook;
636
	}
637
638
639
	/**
640
	 * @param string $contactGroupName
641
	 *
642
	 * @return self
643
	 */
644
	public function setContactGroupName(string $contactGroupName): self {
645
		$this->contactGroupName = $contactGroupName;
646
647
		return $this;
648
	}
649
650
	/**
651
	 * @return string
652
	 */
653
	public function getContactGroupName(): string {
654
		return $this->contactGroupName;
655
	}
656
657
658
	/**
659
	 * @param int $creation
660
	 *
661
	 * @return self
662
	 */
663
	public function setCreation(int $creation): self {
664
		$this->creation = $creation;
665
666
		return $this;
667
	}
668
669
	/**
670
	 * @return int
671
	 */
672
	public function getCreation(): int {
673
		return $this->creation;
674
	}
675
676
677
	/**
678
	 * @param array $data
679
	 *
680
	 * @return $this
681
	 * @throws InvalidItemException
682
	 */
683
	public function import(array $data): IDeserializable {
684
		if ($this->get('id', $data) === '') {
685
			throw new InvalidItemException();
686
		}
687
688
		$this->setSingleId($this->get('id', $data))
689
			 ->setName($this->get('name', $data))
690
			 ->setDisplayName($this->get('displayName', $data))
691
			 ->setSanitizedName($this->get('sanitizedName', $data))
692
			 ->setSource($this->getInt('source', $data))
693
			 ->setConfig($this->getInt('config', $data))
694
			 ->setPopulation($this->getInt('population', $data))
695
			 ->setSettings($this->getArray('settings', $data))
696
//			 ->setContactAddressBook($this->get('contact_addressbook', $data))
697
//			 ->setContactGroupName($this->get('contact_groupname', $data))
698
			 ->setDescription($this->get('description', $data))
699
			 ->setCreation($this->getInt('creation', $data));
700
701
		try {
702
			/** @var Member $owner */
703
			$owner = $this->deserialize($this->getArray('owner', $data), Member::class);
704
			$this->setOwner($owner);
705
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
706
		}
707
708
		try {
709
			/** @var Member $initiator */
710
			$initiator = $this->deserialize($this->getArray('initiator', $data), Member::class);
711
			$this->setInitiator($initiator);
712
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
713
		}
714
715
		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 ArtificialOwl\MySmallPhp...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...
716
	}
717
718
719
	/**
720
	 * @return array
721
	 */
722
	public function jsonSerialize(): array {
723
		$arr = [
724
			'id'            => $this->getSingleId(),
725
			'name'          => $this->getName(),
726
			'displayName'   => $this->getDisplayName(),
727
			'sanitizedName' => $this->getSanitizedName(),
728
			'source'        => $this->getSource(),
729
			'population'    => $this->getPopulation(),
730
			'config'        => $this->getConfig(),
731
			'description'   => $this->getDescription(),
732
			'settings'      => $this->getSettings(),
733
			'url'           => $this->getUrl(),
734
			'creation'      => $this->getCreation(),
735
			'initiator'     => ($this->hasInitiator()) ? $this->getInitiator() : null
736
		];
737
738
		if ($this->hasOwner()) {
739
			$arr['owner'] = $this->getOwner();
740
		}
741
742
		if ($this->hasMembers()) {
743
			$arr['members'] = $this->getMembers();
744
		}
745
746
		if (!is_null($this->inheritedMembers)) {
747
			$arr['inheritedMembers'] = $this->getInheritedMembers();
748
		}
749
750
		if ($this->hasMemberships()) {
751
			$arr['memberships'] = $this->getMemberships();
752
		}
753
754
		return $arr;
755
	}
756
757
758
	/**
759
	 * @param array $data
760
	 * @param string $prefix
761
	 *
762
	 * @return INC22QueryRow
763
	 * @throws CircleNotFoundException
764
	 */
765
	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
766
		if ($this->get($prefix . 'unique_id', $data) === '') {
767
			throw new CircleNotFoundException();
768
		}
769
770
		$this->setSingleId($this->get($prefix . 'unique_id', $data))
771
			 ->setName($this->get($prefix . 'name', $data))
772
			 ->setDisplayName($this->get($prefix . 'display_name', $data))
773
			 ->setSanitizedName($this->get($prefix . 'sanitized_name', $data))
774
			 ->setConfig($this->getInt($prefix . 'config', $data))
775
			 ->setSource($this->getInt($prefix . 'source', $data))
776
			 ->setInstance($this->get($prefix . 'instance', $data))
777
			 ->setPopulation($this->getInt($prefix . 'population', $data))
778
			 ->setSettings($this->getArray($prefix . 'settings', $data))
779
			 ->setContactAddressBook($this->getInt($prefix . 'contact_addressbook', $data))
780
			 ->setContactGroupName($this->get($prefix . 'contact_groupname', $data))
781
			 ->setDescription($this->get($prefix . 'description', $data));
782
783
		$creation = $this->get($prefix . 'creation', $data);
784
		$this->setCreation(DateTime::createFromFormat('Y-m-d H:i:s', $creation)->getTimestamp());
785
786
		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
787
788
		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 ArtificialOwl\MySmallPhp...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...
789
	}
790
791
792
	/**
793
	 * @param Circle $circle
794
	 *
795
	 * @return bool
796
	 * @throws OwnerNotFoundException
797
	 */
798
	public function compareWith(Circle $circle): bool {
799
		if ($this->getSingleId() !== $circle->getSingleId()
800
			|| $this->getInstance() !== $circle->getInstance()
801
			|| $this->getConfig() !== $circle->getConfig()) {
802
			return false;
803
		}
804
805
		if ($this->hasOwner()
806
			&& (!$circle->hasOwner()
807
				|| !$this->getOwner()->compareWith($circle->getOwner()))) {
808
			return false;
809
		}
810
811
		if ($this->hasInitiator()
812
			&& (!$circle->hasInitiator()
813
				|| !$this->getInitiator()->compareWith($circle->getInitiator()))) {
814
			return false;
815
		}
816
817
		return true;
818
	}
819
820
821
	/**
822
	 * @param Circle $circle
823
	 * @param int $display
824
	 *
825
	 * @return array
826
	 */
827
	public static function getCircleFlags(Circle $circle, int $display = self::FLAGS_LONG): array {
828
		$config = [];
829
		foreach (array_keys(Circle::$DEF_CFG) as $def) {
830
			if ($circle->isConfig($def)) {
831
				list($short, $long) = explode('|', Circle::$DEF_CFG[$def]);
832
				switch ($display) {
833
834
					case self::FLAGS_SHORT:
835
						$config[] = $short;
836
						break;
837
838
					case self::FLAGS_LONG:
839
						$config[] = $long;
840
						break;
841
				}
842
			}
843
		}
844
845
		return $config;
846
	}
847
848
}
849
850