Completed
Pull Request — master (#586)
by Maxence
03:47
created

FederatedUser::setLink()   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
use daita\MySmallPhpTools\Db\Nextcloud\nc22\INC22QueryRow;
35
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
36
use daita\MySmallPhpTools\IDeserializable;
37
use daita\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize;
38
use daita\MySmallPhpTools\Traits\TArrayTools;
39
use JsonSerializable;
40
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
41
use OCA\Circles\Exceptions\OwnerNotFoundException;
42
use OCA\Circles\IFederatedUser;
43
use OCA\Circles\IMemberships;
44
45
46
/**
47
 * Class FederatedUser
48
 *
49
 * @package OCA\Circles\Model
50
 */
51
class FederatedUser extends ManagedModel implements
52
	IFederatedUser,
53
	IMemberships,
54
	IDeserializable,
55
	INC22QueryRow,
56
	JsonSerializable {
57
58
59
	use TArrayTools;
60
	use TNC22Deserialize;
61
62
63
	/** @var string */
64
	private $singleId = '';
65
66
	/** @var string */
67
	private $userId;
68
69
	/** @var int */
70
	private $userType;
71
72
	/** @var Circle */
73
	private $basedOn;
74
75
	/** @var int */
76
	private $config = 0;
77
78
	/** @var string */
79
	private $instance;
80
81
	/** @var Membership */
82
	private $link;
83
84
85
	/** @var Member[] */
86
	private $members = null;
87
88
	/** @var Member[] */
89
	private $inheritedMembers = null;
90
91
	/** @var bool */
92
	private $detailedInheritedMember = false;
93
94
	/** @var Membership[] */
95
	private $memberships = null;
96
97
98
	/**
99
	 * FederatedUser constructor.
100
	 */
101
	public function __construct() {
102
	}
103
104
105
	/**
106
	 * @param string $userId
107
	 * @param string $instance
108
	 * @param int $type
109
	 * @param Circle|null $basedOn
110
	 *
111
	 * @return $this
112
	 */
113
	public function set(
114
		string $userId,
115
		$instance = '',
116
		int $type = Member::TYPE_USER,
117
		?Circle $basedOn = null
118
	): self {
119
120
		$this->userId = $userId;
121
		$this->setInstance($instance);
122
		$this->userType = $type;
123
		$this->basedOn = $basedOn;
124
125
		return $this;
126
	}
127
128
129
	/**
130
	 * @param string $singleId
131
	 *
132
	 * @return self
133
	 */
134
	public function setSingleId(string $singleId): self {
135
		$this->singleId = $singleId;
136
137
		return $this;
138
	}
139
140
	/**
141
	 * @return string
142
	 */
143
	public function getSingleId(): string {
144
		return $this->singleId;
145
	}
146
147
148
	/**
149
	 * @param string $userId
150
	 *
151
	 * @return self
152
	 */
153
	public function setUserId(string $userId): self {
154
		$this->userId = $userId;
155
156
		return $this;
157
	}
158
159
	/**
160
	 * @return string
161
	 */
162
	public function getUserId(): string {
163
		return $this->userId;
164
	}
165
166
167
	/**
168
	 * @param int $userType
169
	 *
170
	 * @return self
171
	 */
172
	public function setUserType(int $userType): self {
173
		$this->userType = $userType;
174
175
		return $this;
176
	}
177
178
179
	/**
180
	 * @return int
181
	 */
182
	public function getUserType(): int {
183
		return $this->userType;
184
	}
185
186
187
	/**
188
	 * @return bool
189
	 */
190
	public function hasBasedOn(): bool {
191
		return !is_null($this->basedOn);
192
	}
193
194
	/**
195
	 * @param Circle|null $basedOn
196
	 *
197
	 * @return $this
198
	 */
199
	public function setBasedOn(?Circle $basedOn): self {
200
		$this->basedOn = $basedOn;
201
202
		return $this;
203
	}
204
205
	/**
206
	 * @return Circle
207
	 */
208
	public function getBasedOn(): Circle {
209
		return $this->basedOn;
210
	}
211
212
213
	/**
214
	 * @param int $config
215
	 *
216
	 * @return self
217
	 */
218
	public function setConfig(int $config): self {
219
		$this->config = $config;
220
221
		return $this;
222
	}
223
224
	/**
225
	 * @return int
226
	 */
227
	public function getConfig(): int {
228
		return $this->config;
229
	}
230
231
232
	/**
233
	 * @param string $instance
234
	 *
235
	 * @return self
236
	 */
237
	public function setInstance(string $instance): self {
238
		if ($instance === '') {
239
			$instance = $this->getManager()->getLocalInstance();
240
		}
241
242
		$this->instance = $instance;
243
244
		return $this;
245
	}
246
247
	/**
248
	 * @return string
249
	 */
250
	public function getInstance(): string {
251
		return $this->instance;
252
	}
253
254
255
	/**
256
	 * @return bool
257
	 */
258
	public function hasMembers(): bool {
259
		return !is_null($this->members);
260
	}
261
262
	/**
263
	 * @param array $members
264
	 *
265
	 * @return self
266
	 */
267
	public function setMembers(array $members): IMemberships {
268
		$this->members = $members;
269
270
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\FederatedUser) is incompatible with the return type declared by the interface OCA\Circles\IMemberships::setMembers 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...
271
	}
272
273
	/**
274
	 * @return array
275
	 */
276
	public function getMembers(): array {
277
		if (!$this->hasMembers()) {
278
			$this->getManager()->getMembers($this);
279
		}
280
281
		return $this->members;
282
	}
283
284
285
	/**
286
	 * @return bool
287
	 */
288
	public function hasInheritedMembers(): bool {
289
		return !is_null($this->inheritedMembers);
290
	}
291
292
	/**
293
	 * @param array $members
294
	 * @param bool $detailed
295
	 *
296
	 * @return self
297
	 */
298
	public function setInheritedMembers(array $members, bool $detailed): IMemberships {
299
		$this->inheritedMembers = $members;
300
		$this->detailedInheritedMember = $detailed;
301
302
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\FederatedUser) is incompatible with the return type declared by the interface OCA\Circles\IMemberships::setInheritedMembers 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...
303
	}
304
305
	/**
306
	 * @param bool $detailed
307
	 *
308
	 * @return array
309
	 */
310
	public function getInheritedMembers(bool $detailed = false): array {
311
		if (is_null($this->inheritedMembers)
312
			|| ($detailed && !$this->detailedInheritedMember)) {
313
			$this->getManager()->getInheritedMembers($this, $detailed);
314
		}
315
316
		return $this->inheritedMembers;
317
	}
318
319
320
	/**
321
	 * @param array $memberships
322
	 *
323
	 * @return self
324
	 */
325
	public function setMemberships(array $memberships): IMemberships {
326
		$this->memberships = $memberships;
327
328
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\FederatedUser) 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...
329
	}
330
331
	/**
332
	 * @return Membership[]
333
	 */
334
	public function getMemberships(): array {
335
		if (is_null($this->memberships)) {
336
			$this->getManager()->getMemberships($this);
337
		}
338
339
		return $this->memberships;
340
	}
341
342
343
	/**
344
	 * @return bool
345
	 */
346
	public function hasLink(): bool {
347
		return !is_null($this->link);
348
	}
349
350
	/**
351
	 * @param Membership $link
352
	 *
353
	 * @return $this
354
	 */
355
	public function setLink(Membership $link): self {
356
		$this->link = $link;
357
358
		return $this;
359
	}
360
361
	/**
362
	 * @return Membership
363
	 */
364
	public function getLink(): Membership {
365
		return $this->link;
366
	}
367
368
369
	/**
370
	 * @param array $data
371
	 *
372
	 * @return $this
373
	 * @throws InvalidItemException
374
	 */
375
	public function import(array $data): IDeserializable {
376
		if ($this->get('user_id', $data) === '') {
377
			throw new InvalidItemException();
378
		}
379
380
		$this->setSingleId($this->get('id', $data));
381
		$this->setUserId($this->get('user_id', $data));
382
		$this->setUserType($this->getInt('user_type', $data));
383
		$this->setInstance($this->get('instance', $data));
384
		//$this->setMemberships($this->getArray('memberships'));
385
386
		try {
387
			/** @var Circle $circle */
388
			$circle = $this->deserialize($this->getArray('basedOn', $data), Circle::class);
389
			$this->setBasedOn($circle);
390
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
391
		}
392
393
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\FederatedUser) 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...
394
	}
395
396
397
	/**
398
	 * @param Circle $circle
399
	 *
400
	 * @return FederatedUser
401
	 * @throws OwnerNotFoundException
402
	 */
403
	public function importFromCircle(Circle $circle): self {
404
		$this->setSingleId($circle->getSingleId());
405
406
		if ($circle->isConfig(Circle::CFG_SINGLE)) {
407
			$owner = $circle->getOwner();
408
			$this->set($owner->getUserId(), $owner->getInstance(), $owner->getUserType(), $circle);
409
		} else {
410
			$this->set($circle->getDisplayName(), $circle->getInstance(), Member::TYPE_CIRCLE, $circle);
411
		}
412
413
		return $this;
414
	}
415
416
417
	/**
418
	 * @param array $data
419
	 * @param string $prefix
420
	 *
421
	 * @return INC22QueryRow
422
	 * @throws FederatedUserNotFoundException
423
	 */
424
	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
425
		if ($this->get($prefix . 'single_id', $data) === '') {
426
			throw new FederatedUserNotFoundException();
427
		}
428
429
		$this->setSingleId($this->get($prefix . 'single_id', $data));
430
		$this->setUserId($this->get($prefix . 'user_id', $data));
431
		$this->setUserType($this->getInt($prefix . 'user_type', $data));
432
		$this->setInstance($this->get($prefix . 'instance', $data));
433
434
		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
435
436
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\FederatedUser) 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...
437
	}
438
439
440
	/**
441
	 * @return string[]
442
	 */
443
	public function jsonSerialize(): array {
444
		$arr = [
445
			'id'        => $this->getSingleId(),
446
			'user_id'   => $this->getUserId(),
447
			'user_type' => $this->getUserType(),
448
			'instance'  => $this->getInstance()
449
		];
450
451
		if ($this->hasBasedOn()) {
452
			$arr['basedOn'] = $this->getBasedOn();
453
		}
454
455
		if ($this->hasLink()) {
456
			$arr['link'] = $this->getLink();
457
		}
458
459
		if ($this->hasMembers()) {
460
			$arr['members'] = $this->getMembers();
461
		}
462
463
		if ($this->hasInheritedMembers()) {
464
			$arr['inheritedMembers'] = $this->getInheritedMembers();
465
		}
466
467
		if (!is_null($this->memberships)) {
468
			$arr['memberships'] = $this->getMemberships();
469
		}
470
471
		return $arr;
472
	}
473
474
475
	/**
476
	 * @param IFederatedUser $member
477
	 *
478
	 * @return bool
479
	 */
480
	public function compareWith(IFederatedUser $member): bool {
481
		return !($this->getSingleId() !== $member->getSingleId()
482
				 || $this->getUserId() !== $member->getUserId()
483
				 || $this->getUserType() <> $member->getUserType()
484
				 || $this->getInstance() !== $member->getInstance());
485
	}
486
487
}
488
489