Completed
Pull Request — master (#586)
by Maxence
02:16
created

FederatedUser::hasMemberships()   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 hasMemberships(): bool {
249
		return !is_null($this->memberships);
250
	}
251
252
	/**
253
	 * @param array $memberships
254
	 *
255
	 * @return self
256
	 */
257
	public function setMemberships(array $memberships): IMemberships {
258
		$this->memberships = $memberships;
259
260
		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...
261
	}
262
263
	/**
264
	 * @return Membership[]
265
	 */
266
	public function getMemberships(): array {
267
		if (!$this->hasMemberships()) {
268
			$this->getManager()->getMemberships($this);
269
		}
270
271
		return $this->memberships;
272
	}
273
274
275
	/**
276
	 * @return bool
277
	 */
278
	public function hasLink(): bool {
279
		return !is_null($this->link);
280
	}
281
282
	/**
283
	 * @param Membership $link
284
	 *
285
	 * @return $this
286
	 */
287
	public function setLink(Membership $link): self {
288
		$this->link = $link;
289
290
		return $this;
291
	}
292
293
	/**
294
	 * @return Membership
295
	 */
296
	public function getLink(): Membership {
297
		return $this->link;
298
	}
299
300
301
	/**
302
	 * @param array $data
303
	 *
304
	 * @return $this
305
	 * @throws InvalidItemException
306
	 */
307
	public function import(array $data): IDeserializable {
308
		if ($this->get('user_id', $data) === '') {
309
			throw new InvalidItemException();
310
		}
311
312
		$this->setSingleId($this->get('id', $data));
313
		$this->setUserId($this->get('user_id', $data));
314
		$this->setUserType($this->getInt('user_type', $data));
315
		$this->setInstance($this->get('instance', $data));
316
		//$this->setMemberships($this->getArray('memberships'));
317
318
		try {
319
			/** @var Circle $circle */
320
			$circle = $this->deserialize($this->getArray('basedOn', $data), Circle::class);
321
			$this->setBasedOn($circle);
322
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
323
		}
324
325
		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...
326
	}
327
328
329
	/**
330
	 * @param Circle $circle
331
	 *
332
	 * @return FederatedUser
333
	 * @throws OwnerNotFoundException
334
	 */
335
	public function importFromCircle(Circle $circle): self {
336
		$this->setSingleId($circle->getSingleId());
337
338
		if ($circle->isConfig(Circle::CFG_SINGLE)) {
339
			$owner = $circle->getOwner();
340
			$this->set($owner->getUserId(), $owner->getInstance(), $owner->getUserType(), $circle);
341
		} else {
342
			$this->set($circle->getDisplayName(), $circle->getInstance(), Member::TYPE_CIRCLE, $circle);
343
		}
344
345
		return $this;
346
	}
347
348
349
	/**
350
	 * @param array $data
351
	 * @param string $prefix
352
	 *
353
	 * @return INC22QueryRow
354
	 * @throws FederatedUserNotFoundException
355
	 */
356
	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
357
		if ($this->get($prefix . 'single_id', $data) === '') {
358
			throw new FederatedUserNotFoundException();
359
		}
360
361
		$this->setSingleId($this->get($prefix . 'single_id', $data));
362
		$this->setUserId($this->get($prefix . 'user_id', $data));
363
		$this->setUserType($this->getInt($prefix . 'user_type', $data));
364
		$this->setInstance($this->get($prefix . 'instance', $data));
365
366
		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
367
368
		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...
369
	}
370
371
372
	/**
373
	 * @return string[]
374
	 */
375
	public function jsonSerialize(): array {
376
		$arr = [
377
			'id'        => $this->getSingleId(),
378
			'user_id'   => $this->getUserId(),
379
			'user_type' => $this->getUserType(),
380
			'instance'  => $this->getInstance()
381
		];
382
383
		if ($this->hasBasedOn()) {
384
			$arr['basedOn'] = $this->getBasedOn();
385
		}
386
387
		if ($this->hasLink()) {
388
			$arr['link'] = $this->getLink();
389
		}
390
391
		if (!is_null($this->memberships)) {
392
			$arr['memberships'] = $this->getMemberships();
393
		}
394
395
		return $arr;
396
	}
397
398
399
	/**
400
	 * @param IFederatedUser $member
401
	 *
402
	 * @return bool
403
	 */
404
	public function compareWith(IFederatedUser $member): bool {
405
		return !($this->getSingleId() !== $member->getSingleId()
406
				 || $this->getUserId() !== $member->getUserId()
407
				 || $this->getUserType() <> $member->getUserType()
408
				 || $this->getInstance() !== $member->getInstance());
409
	}
410
411
}
412
413