Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.23% covered (success)
94.23%
49 / 52
89.47% covered (warning)
89.47%
17 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
Account
94.23% covered (success)
94.23%
49 / 52
89.47% covered (warning)
89.47%
17 / 19
30.17
0.00% covered (danger)
0.00%
0 / 1
 hasPermission
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
5.58
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGroups
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGroupIds
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addGroup
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasGroup
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getEmail
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setEmail
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setStatus
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setType
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getLastActive
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 generatePassword
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 updateLastActive
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toArray
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 jsonSerialize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Account
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Account;
16
17use phpOMS\Localization\Localization;
18use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
19use phpOMS\Validation\Network\Email;
20
21/**
22 * Account class.
23 *
24 * The account class is the base model for accounts. This model contains the most common account
25 * information. This model is not comparable to a profile which contains much more information.
26 *
27 * @package phpOMS\Account
28 * @license OMS License 2.0
29 * @link    https://jingga.app
30 * @since   1.0.0
31 */
32class Account implements \JsonSerializable
33{
34    /**
35     * Id.
36     *
37     * @var int
38     * @since 1.0.0
39     */
40    public int $id = 0;
41
42    /**
43     * Names.
44     *
45     * @var string
46     * @since 1.0.0
47     */
48    public string $name1 = '';
49
50    /**
51     * Names.
52     *
53     * @var string
54     * @since 1.0.0
55     */
56    public string $name2 = '';
57
58    /**
59     * Names.
60     *
61     * @var string
62     * @since 1.0.0
63     */
64    public string $name3 = '';
65
66    /**
67     * Email.
68     *
69     * @var string
70     * @since 1.0.0
71     */
72    public string $email = '';
73
74    /**
75     * Ip.
76     *
77     * Used in order to make sure ips don't change
78     *
79     * @var string
80     * @since 1.0.0
81     */
82    public string $origin = '';
83
84    /**
85     * Login.
86     *
87     * @var null|string
88     * @since 1.0.0
89     */
90    public ?string $login = null;
91
92    /**
93     * Last activity.
94     *
95     * @var \DateTime
96     * @since 1.0.0
97     */
98    public \DateTime $lastActive;
99
100    /**
101     * Last activity.
102     *
103     * @var \DateTimeImmutable
104     * @since 1.0.0
105     */
106    public \DateTimeImmutable $createdAt;
107
108    /**
109     * Groups.
110     *
111     * @var Group[]
112     * @since 1.0.0
113     */
114    public array $groups = [];
115
116    /**
117     * Password.
118     *
119     * @var string
120     * @since 1.0.0
121     */
122    public string $password = '';
123
124    /**
125     * Account type.
126     *
127     * @var int
128     * @since 1.0.0
129     */
130    public int $type = AccountType::USER;
131
132    /**
133     * Account status.
134     *
135     * @var int
136     * @since 1.0.0
137     */
138    public int $status = AccountStatus::INACTIVE;
139
140    /**
141     * Localization.
142     *
143     * @var Localization
144     * @since 1.0.0
145     */
146    public Localization $l11n;
147
148    use PermissionHandlingTrait;
149
150    /**
151     * Has permission.
152     *
153     * @param int         $permission Permission
154     * @param int|null    $unit       Unit
155     * @param int|null    $app        App
156     * @param string|null $module     Module
157     * @param int|null    $category   Category
158     * @param int|null    $element    Element
159     * @param int|null    $component  Component
160     *
161     * @return bool
162     *
163     * @since 1.0.0
164     */
165    public function hasPermission(
166        int $permission,
167        int $unit = null,
168        int $app = null,
169        string $module = null,
170        int $category = null,
171        int $element = null,
172        int $component = null
173    ) : bool
174    {
175        foreach ($this->groups as $group) {
176            if ($group->hasPermission($permission, $unit, $app, $module, $category, $element, $component)) {
177                return true;
178            }
179        }
180
181        foreach ($this->permissions as $p) {
182            if ($p->hasPermission($permission, $unit, $app, $module, $category, $element, $component)) {
183                return true;
184            }
185        }
186
187        return false;
188    }
189
190    /**
191     * Constructor.
192     *
193     * The constructor automatically sets the created date as well as the last activity to now.
194     *
195     * @param int $id Account id
196     *
197     * @since 1.0.0
198     */
199    public function __construct(int $id = 0)
200    {
201        $this->createdAt  = new \DateTimeImmutable('now');
202        $this->lastActive = new \DateTime('now');
203        $this->id         = $id;
204        $this->l11n       = new Localization();
205    }
206
207    /**
208     * Get account id.
209     *
210     * @return int Account id
211     *
212     * @since 1.0.0
213     */
214    public function getId() : int
215    {
216        return $this->id;
217    }
218
219    /**
220     * Get groups.
221     *
222     * Every account can belong to multiple groups.
223     * These groups usually are used for permissions and categorize accounts.
224     *
225     * @return Group[] Returns array of all groups
226     *
227     * @since 1.0.0
228     */
229    public function getGroups() : array
230    {
231        return $this->groups;
232    }
233
234    /**
235     * Get ids of groups
236     *
237     * @return int[]
238     *
239     * @since 1.0.0
240     */
241    public function getGroupIds() : array
242    {
243        /*
244        $ids = [];
245        foreach ($this->groups as $group) {
246            $ids[] = $group->id;
247        }
248
249        return $ids;
250        */
251        return \array_keys($this->groups);
252    }
253
254    /**
255     * Add group.
256     *
257     * @param Group $group Group to add
258     *
259     * @return void
260     *
261     * @since 1.0.0
262     */
263    public function addGroup(Group $group) : void
264    {
265        $this->groups[] = $group;
266    }
267
268    /**
269     * User has group.
270     *
271     * @param int $id Group id
272     *
273     * @return bool
274     *
275     * @since 1.0.0
276     */
277    public function hasGroup(int $id) : bool
278    {
279        foreach ($this->groups as $group) {
280            if ($group->id === $id) {
281                return true;
282            }
283        }
284
285        return false;
286    }
287
288    /**
289     * Get email.
290     *
291     * @return string Returns the email address
292     *
293     * @since 1.0.0
294     */
295    public function getEmail() : string
296    {
297        return $this->email;
298    }
299
300    /**
301     * Set email.
302     *
303     * @param string $email Email
304     *
305     * @return void
306     *
307     * @throws \InvalidArgumentException Exception is thrown if the provided string is not a valid email
308     *
309     * @since 1.0.0
310     */
311    public function setEmail(string $email) : void
312    {
313        if ($email !== '' && !Email::isValid($email)) {
314            throw new \InvalidArgumentException();
315        }
316
317        $this->email = \mb_strtolower($email);
318    }
319
320    /**
321     * Get status.
322     *
323     * @return int Returns the status (AccountStatus)
324     *
325     * @since 1.0.0
326     */
327    public function getStatus() : int
328    {
329        return $this->status;
330    }
331
332    /**
333     * Get status.
334     *
335     * @param int $status Status
336     *
337     * @return void
338     *
339     * @throws InvalidEnumValue This exception is thrown if a invalid status is used
340     *
341     * @since 1.0.0
342     */
343    public function setStatus(int $status) : void
344    {
345        if (!AccountStatus::isValidValue($status)) {
346            throw new InvalidEnumValue($status);
347        }
348
349        $this->status = $status;
350    }
351
352    /**
353     * Get type.
354     *
355     * @return int Returns the type (AccountType)
356     *
357     * @since 1.0.0
358     */
359    public function getType() : int
360    {
361        return $this->type;
362    }
363
364    /**
365     * Get type.
366     *
367     * @param int $type Type
368     *
369     * @return void
370     *
371     * @throws InvalidEnumValue This exception is thrown if an invalid type is used
372     *
373     * @since 1.0.0
374     */
375    public function setType(int $type) : void
376    {
377        if (!AccountType::isValidValue($type)) {
378            throw new InvalidEnumValue($type);
379        }
380
381        $this->type = $type;
382    }
383
384    /**
385     * Get last activity.
386     *
387     * @return \DateTimeInterface
388     *
389     * @since 1.0.0
390     */
391    public function getLastActive() : \DateTimeInterface
392    {
393        return $this->lastActive ?? $this->createdAt;
394    }
395
396    /**
397     * Generate password.
398     *
399     * @param string $password Password
400     *
401     * @return void
402     *
403     * @throws \Exception Throws this exception if the password_hash function fails
404     *
405     * @since 1.0.0
406     */
407    public function generatePassword(string $password) : void
408    {
409        $temp = \password_hash($password, \PASSWORD_BCRYPT);
410
411        if ($temp === false) {
412            throw new \Exception('Internal password_hash error.'); // @codeCoverageIgnore
413        }
414
415        $this->password = $temp;
416    }
417
418    /**
419     * Update last activity.
420     *
421     * @return void
422     *
423     * @since 1.0.0
424     */
425    public function updateLastActive() : void
426    {
427        $this->lastActive = new \DateTime('now');
428    }
429
430    /**
431     * Get string representation.
432     *
433     * @return string Returns the json_encode of this object
434     *
435     * @since 1.0.0
436     */
437    public function __toString() : string
438    {
439        return (string) \json_encode($this->toArray());
440    }
441
442    /**
443     * {@inheritdoc}
444     */
445    public function toArray() : array
446    {
447        return [
448            'id'          => $this->id,
449            'name'        => [
450                $this->name1,
451                $this->name2,
452                $this->name3,
453            ],
454            'email'       => $this->email,
455            'login'       => $this->login,
456            'groups'      => $this->groups,
457            'permissions' => $this->permissions,
458            'type'        => $this->type,
459            'status'      => $this->status,
460        ];
461    }
462
463    /**
464     * {@inheritdoc}
465     */
466    public function jsonSerialize() : mixed
467    {
468        return $this->toArray();
469    }
470}