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

FederatedUser::getBasedOn()   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
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
	/** @var Membership[] */
85
	private $memberships = null;
86
87
88
	/**
89
	 * FederatedUser constructor.
90
	 */
91
	public function __construct() {
92
	}
93
94
95
	/**
96
	 * @param string $userId
97
	 * @param string $instance
98
	 * @param int $type
99
	 * @param Circle|null $basedOn
100
	 *
101
	 * @return $this
102
	 */
103
	public function set(
104
		string $userId,
105
		$instance = '',
106
		int $type = Member::TYPE_USER,
107
		?Circle $basedOn = null
108
	): self {
109
110
		$this->userId = $userId;
111
		$this->setInstance($instance);
112
		$this->userType = $type;
113
		$this->basedOn = $basedOn;
114
115
		return $this;
116
	}
117
118
119
	/**
120
	 * @param string $singleId
121
	 *
122
	 * @return self
123
	 */
124
	public function setSingleId(string $singleId): self {
125
		$this->singleId = $singleId;
126
127
		return $this;
128
	}
129
130
	/**
131
	 * @return string
132
	 */
133
	public function getSingleId(): string {
134
		return $this->singleId;
135
	}
136
137
138
	/**
139
	 * @param string $userId
140
	 *
141
	 * @return self
142
	 */
143
	public function setUserId(string $userId): self {
144
		$this->userId = $userId;
145
146
		return $this;
147
	}
148
149
	/**
150
	 * @return string
151
	 */
152
	public function getUserId(): string {
153
		return $this->userId;
154
	}
155
156
157
	/**
158
	 * @param int $userType
159
	 *
160
	 * @return self
161
	 */
162
	public function setUserType(int $userType): self {
163
		$this->userType = $userType;
164
165
		return $this;
166
	}
167
168
169
	/**
170
	 * @return int
171
	 */
172
	public function getUserType(): int {
173
		return $this->userType;
174
	}
175
176
177
	/**
178
	 * @return bool
179
	 */
180
	public function hasBasedOn(): bool {
181
		return !is_null($this->basedOn);
182
	}
183
184
	/**
185
	 * @param Circle|null $basedOn
186
	 *
187
	 * @return $this
188
	 */
189
	public function setBasedOn(?Circle $basedOn): self {
190
		$this->basedOn = $basedOn;
191
192
		return $this;
193
	}
194
195
	/**
196
	 * @return Circle
197
	 */
198
	public function getBasedOn(): Circle {
199
		return $this->basedOn;
200
	}
201
202
203
	/**
204
	 * @param int $config
205
	 *
206
	 * @return self
207
	 */
208
	public function setConfig(int $config): self {
209
		$this->config = $config;
210
211
		return $this;
212
	}
213
214
	/**
215
	 * @return int
216
	 */
217
	public function getConfig(): int {
218
		return $this->config;
219
	}
220
221
222
	/**
223
	 * @param string $instance
224
	 *
225
	 * @return self
226
	 */
227
	public function setInstance(string $instance): self {
228
		if ($instance === '') {
229
			$instance = $this->getManager()->getLocalInstance();
230
		}
231
232
		$this->instance = $instance;
233
234
		return $this;
235
	}
236
237
	/**
238
	 * @return string
239
	 */
240
	public function getInstance(): string {
241
		return $this->instance;
242
	}
243
244
245
	/**
246
	 * @return bool
247
	 */
248
	public function isLocal(): bool {
249
		return $this->getManager()->isLocalInstance($this->getInstance());
250
	}
251
252
253
	/**
254
	 * @return bool
255
	 */
256
	public function hasMemberships(): bool {
257
		return !is_null($this->memberships);
258
	}
259
260
	/**
261
	 * @param array $memberships
262
	 *
263
	 * @return self
264
	 */
265
	public function setMemberships(array $memberships): IMemberships {
266
		$this->memberships = $memberships;
267
268
		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...
269
	}
270
271
	/**
272
	 * @return Membership[]
273
	 */
274
	public function getMemberships(): array {
275
		if (!$this->hasMemberships()) {
276
			$this->getManager()->getMemberships($this);
277
		}
278
279
		return $this->memberships;
280
	}
281
282
283
	/**
284
	 * @return bool
285
	 */
286
	public function hasLink(): bool {
287
		return !is_null($this->link);
288
	}
289
290
	/**
291
	 * @param Membership $link
292
	 *
293
	 * @return $this
294
	 */
295
	public function setLink(Membership $link): self {
296
		$this->link = $link;
297
298
		return $this;
299
	}
300
301
	/**
302
	 * @return Membership
303
	 */
304
	public function getLink(): Membership {
305
		return $this->link;
306
	}
307
308
309
	/**
310
	 * @param array $data
311
	 *
312
	 * @return $this
313
	 * @throws InvalidItemException
314
	 */
315
	public function import(array $data): IDeserializable {
316
		if ($this->get('user_id', $data) === '') {
317
			throw new InvalidItemException();
318
		}
319
320
		$this->setSingleId($this->get('id', $data));
321
		$this->setUserId($this->get('user_id', $data));
322
		$this->setUserType($this->getInt('user_type', $data));
323
		$this->setInstance($this->get('instance', $data));
324
		//$this->setMemberships($this->getArray('memberships'));
325
326
		try {
327
			/** @var Circle $circle */
328
			$circle = $this->deserialize($this->getArray('basedOn', $data), Circle::class);
329
			$this->setBasedOn($circle);
330
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
331
		}
332
333
		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...
334
	}
335
336
337
	/**
338
	 * @param Circle $circle
339
	 *
340
	 * @return FederatedUser
341
	 * @throws OwnerNotFoundException
342
	 */
343
	public function importFromCircle(Circle $circle): self {
344
		$this->setSingleId($circle->getSingleId());
345
346
		if ($circle->isConfig(Circle::CFG_SINGLE)) {
347
			$owner = $circle->getOwner();
348
			$this->set($owner->getUserId(), $owner->getInstance(), $owner->getUserType(), $circle);
349
		} else {
350
			$this->set($circle->getDisplayName(), $circle->getInstance(), Member::TYPE_CIRCLE, $circle);
351
		}
352
353
		return $this;
354
	}
355
356
357
	/**
358
	 * @param array $data
359
	 * @param string $prefix
360
	 *
361
	 * @return INC22QueryRow
362
	 * @throws FederatedUserNotFoundException
363
	 */
364
	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
365
		if ($this->get($prefix . 'single_id', $data) === '') {
366
			throw new FederatedUserNotFoundException();
367
		}
368
369
		$this->setSingleId($this->get($prefix . 'single_id', $data));
370
		$this->setUserId($this->get($prefix . 'user_id', $data));
371
		$this->setUserType($this->getInt($prefix . 'user_type', $data));
372
		$this->setInstance($this->get($prefix . 'instance', $data));
373
374
		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
375
376
		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...
377
	}
378
379
380
	/**
381
	 * @return string[]
382
	 */
383
	public function jsonSerialize(): array {
384
		$arr = [
385
			'id'        => $this->getSingleId(),
386
			'user_id'   => $this->getUserId(),
387
			'user_type' => $this->getUserType(),
388
			'instance'  => $this->getInstance()
389
		];
390
391
		if ($this->hasBasedOn()) {
392
			$arr['basedOn'] = $this->getBasedOn();
393
		}
394
395
		if ($this->hasLink()) {
396
			$arr['link'] = $this->getLink();
397
		}
398
399
		if (!is_null($this->memberships)) {
400
			$arr['memberships'] = $this->getMemberships();
401
		}
402
403
		return $arr;
404
	}
405
406
407
	/**
408
	 * @param IFederatedUser $member
409
	 *
410
	 * @return bool
411
	 */
412
	public function compareWith(IFederatedUser $member): bool {
413
		$local = ($this->getManager()->isLocalInstance($this->getInstance())
414
				  && $this->getManager()->isLocalInstance($member->getInstance()));
415
416
		return !($this->getSingleId() !== $member->getSingleId()
417
				 || $this->getUserId() !== $member->getUserId()
418
				 || $this->getUserType() <> $member->getUserType()
419
				 || (!$local && $this->getInstance() !== $member->getInstance()));
420
	}
421
422
}
423
424