Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.74% covered (warning)
89.74%
35 / 39
75.00% covered (warning)
75.00%
6 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
User
89.74% covered (warning)
89.74%
35 / 39
75.00% covered (warning)
75.00%
6 / 8
23.57
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 loginName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 initials
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
6.07
 data
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 content
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 array
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 roleNames
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 displayName
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray;
6
7class User
8{
9    public readonly int $id;
10    public readonly string $uid;
11    public readonly string $type;
12    public readonly string $username;
13    public readonly string $email;
14    public readonly string $password;
15    /** @var list<string> */
16    public readonly array $roles;
17    public readonly bool $active;
18    public readonly ?string $name;
19    public readonly ?string $panelLocale;
20    public readonly string $created;
21    public readonly string $changed;
22    public readonly ?string $deleted;
23    public readonly ?string $expires;
24
25    /** @param array<string, mixed> $data */
26    public function __construct(
27        protected readonly array $data,
28    ) {
29        $this->id = $data['usr'];
30        $this->uid = $data['uid'];
31        $this->type = $data['type'] ?? 'user';
32        $this->username = $data['username'] ?? '';
33        $this->email = $data['email'];
34        $this->password = $data['password'];
35        $this->roles = self::roleNames($data['roles'] ?? []);
36        $this->active = $data['active'];
37        $this->name = self::displayName($data['data'] ?? null);
38        $this->panelLocale = $data['panel_locale'] ?? null;
39        $this->created = $data['created'];
40        $this->changed = $data['changed'];
41        $this->deleted = $data['deleted'];
42        $this->expires = $data['expires'] ?? null;
43    }
44
45    /** The username, or the email for accounts without one; both log in. */
46    public function loginName(): string
47    {
48        return $this->username !== '' ? $this->username : $this->email;
49    }
50
51    /**
52     * First and last word of the name, or of the username or the email's local
53     * part when there is none ("m.keller" â†’ "MK"). A single word gives its
54     * first two letters.
55     */
56    public function initials(): string
57    {
58        $source = $this->name ?? ($this->username !== '' ? $this->username : strstr($this->email, '@', true));
59        $words = preg_split('/[\s._-]+/u', (string) $source, -1, PREG_SPLIT_NO_EMPTY) ?: [];
60
61        $initials = match (count($words)) {
62            0 => '',
63            1 => mb_substr($words[0], 0, 2),
64            default => mb_substr($words[0], 0, 1) . mb_substr($words[array_key_last($words)], 0, 1),
65        };
66
67        return mb_strtoupper($initials);
68    }
69
70    /** @return array<string, mixed> the `users.data` document */
71    public function data(): array
72    {
73        $data = $this->data['data'] ?? [];
74
75        if (is_string($data)) {
76            $data = json_decode($data, true);
77        }
78
79        return is_array($data) ? $data : [];
80    }
81
82    /** @return array<string, array<mixed>> the stored values of the fields a user model declares */
83    public function content(): array
84    {
85        $content = $this->data()['content'] ?? [];
86
87        return is_array($content) ? $content : [];
88    }
89
90    /** @return array<string, mixed> */
91    public function array(): array
92    {
93        $data = $this->data;
94        unset($data['password']);
95
96        return $data;
97    }
98
99    /** @return list<string> */
100    private static function roleNames(mixed $roles): array
101    {
102        if (is_string($roles)) {
103            $roles = json_decode($roles, true);
104        }
105
106        return is_array($roles) ? array_values(array_filter($roles, is_string(...))) : [];
107    }
108
109    private static function displayName(mixed $data): ?string
110    {
111        if (is_string($data)) {
112            $data = json_decode($data, true);
113        }
114
115        $name = is_array($data) ? $data['name'] ?? null : null;
116
117        return is_string($name) && trim($name) !== '' ? trim($name) : null;
118    }
119}