Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
79.63% covered (warning)
79.63%
43 / 54
93.33% covered (success)
93.33%
14 / 15
92.86% covered (success)
92.86%
13 / 14
92.31% covered (success)
92.31%
12 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Identity
79.63% covered (warning)
79.63%
43 / 54
93.33% covered (success)
93.33%
14 / 15
92.86% covered (success)
92.86%
13 / 14
92.31% covered (success)
92.31%
12 / 13
14.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
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
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEmail
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUsername
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPasswordHash
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRoles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isComplete
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getValidationToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 pullEvents
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 complete
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 changeEmail
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 generateValidationToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Auth\Domain\Model;
4
5use App\Auth\Domain\Event\EmailChangedEvent;
6use App\Auth\Domain\Event\IdentityCompletedEvent;
7use App\Auth\Domain\Event\IdentityCreatedEvent;
8use App\Auth\Domain\Exception\AuthErrorCode;
9use App\Shared\Domain\Event\DomainEvent;
10use App\Shared\Domain\Exception\ValidationException;
11use App\Shared\Domain\Model\EntityId;
12use App\Shared\Domain\Model\ProducesDomainEvents;
13use App\Shared\Domain\Validation\Validator;
14
15final class Identity implements ProducesDomainEvents
16{
17
18    /**
19     * @var array<DomainEvent>
20     */
21    private array $events = [];
22
23    /**
24     * @param EntityId $id
25     * @param string $email
26     * @param string $username
27     * @param string $passwordHash
28     * @param list<string> $roles
29     * @param boolean $isComplete
30     * @param string $validationToken
31     * @throws ValidationException
32    */
33    public function __construct(
34        private readonly EntityId $id,
35        public readonly string    $email,
36        private readonly string   $username,
37        private readonly string   $passwordHash,
38        private readonly array    $roles = ['ROLE_USER'],
39        private readonly bool $isComplete = false,
40        private readonly string $validationToken = ''
41    ) {
42        $validator = new Validator();
43        $validator
44            ->requireNotEmpty('id', $this->id)
45            ->requireNotEmpty('email', $this->email)
46            ->requireValidEmail('email', $this->email)
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
48            ->requireNotEmpty('passwordHash', $this->passwordHash)
49            ->requireNotEmpty('roles', $this->roles)
50            ->validate();
51    }
52
53    /**
54     * @param EntityId $id
55     * @param string $email
56     * @param string $username
57     * @param string $passwordHash
58     * @param list<string> $roles
59     * @return self
60     */
61    public static function create(
62        EntityId $id,
63        string    $email,
64        string   $username,
65        string   $passwordHash,
66        array    $roles = ['ROLE_USER']
67    ): self {
68        $newUser = new self(
69            id: $id,
70            email: $email,
71            username: $username,
72            passwordHash: $passwordHash,
73            roles: $roles,
74            isComplete: false,
75        );
76        $newUser->events = [new IdentityCreatedEvent($newUser)];
77        return $newUser;
78    }
79
80    public function getId(): EntityId
81    {
82        return $this->id;
83    }
84
85    public function getEmail(): string
86    {
87        return $this->email;
88    }
89    public function getUsername(): string
90    {
91        return $this->username;
92    }
93    public function getPasswordHash(): string
94    {
95        return $this->passwordHash;
96    }
97
98    /**
99     * @return list<string>
100     */
101    public function getRoles(): array
102    {
103        return $this->roles;
104    }
105
106    public function isComplete(): bool
107    {
108        return $this->isComplete;
109    }
110
111    public function getValidationToken(): string
112    {
113        return $this->validationToken;
114    }
115
116    /**
117     * @return array<DomainEvent>
118     */
119    public function pullEvents(): array
120    {
121        $events = $this->events;
122        $this->events = [];
123        return $events;
124    }
125
126    public function complete(): self
127    {
128        if ($this->isComplete()) {
129            return $this;
130        }
131
132        $new = new self(
133            id: $this->id,
134            email: $this->email,
135            username: $this->username,
136            passwordHash: $this->passwordHash,
137            roles: $this->roles,
138            isComplete: true,
139            validationToken: $this->generateValidationToken()
140        );
141        $new->events = [new IdentityCompletedEvent($new)];
142        return $new;
143    }
144
145    public function changeEmail(string $email): self
146    {
147        $new = new self(
148            id: $this->id,
149            email: $email,
150            username: $this->username,
151            passwordHash: $this->passwordHash,
152            roles: $this->roles,
153            isComplete: true,
154            validationToken: $this->generateValidationToken()
155        );
156        $new->events = [new EmailChangedEvent($new)];
157        return $new;
158    }
159
160    private function generateValidationToken(): string
161    {
162        return EntityId::generate();
163    }
164}

Paths

Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

Identity->__construct
33    public function __construct(
34        private readonly EntityId $id,
35        public readonly string    $email,
36        private readonly string   $username,
37        private readonly string   $passwordHash,
38        private readonly array    $roles = ['ROLE_USER'],
39        private readonly bool $isComplete = false,
40        private readonly string $validationToken = ''
41    ) {
42        $validator = new Validator();
43        $validator
44            ->requireNotEmpty('id', $this->id)
45            ->requireNotEmpty('email', $this->email)
46            ->requireValidEmail('email', $this->email)
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
48            ->requireNotEmpty('passwordHash', $this->passwordHash)
49            ->requireNotEmpty('roles', $this->roles)
50            ->validate();
51    }
Identity->changeEmail
145    public function changeEmail(string $email): self
146    {
147        $new = new self(
148            id: $this->id,
149            email: $email,
150            username: $this->username,
151            passwordHash: $this->passwordHash,
152            roles: $this->roles,
153            isComplete: true,
154            validationToken: $this->generateValidationToken()
155        );
156        $new->events = [new EmailChangedEvent($new)];
157        return $new;
158    }
Identity->complete
128        if ($this->isComplete()) {
 
129            return $this;
128        if ($this->isComplete()) {
 
132        $new = new self(
133            id: $this->id,
134            email: $this->email,
135            username: $this->username,
136            passwordHash: $this->passwordHash,
137            roles: $this->roles,
138            isComplete: true,
139            validationToken: $this->generateValidationToken()
140        );
141        $new->events = [new IdentityCompletedEvent($new)];
142        return $new;
143    }
Identity->create
61    public static function create(
62        EntityId $id,
63        string    $email,
64        string   $username,
65        string   $passwordHash,
66        array    $roles = ['ROLE_USER']
67    ): self {
68        $newUser = new self(
69            id: $id,
70            email: $email,
71            username: $username,
72            passwordHash: $passwordHash,
73            roles: $roles,
74            isComplete: false,
75        );
76        $newUser->events = [new IdentityCreatedEvent($newUser)];
77        return $newUser;
78    }
Identity->generateValidationToken
162        return EntityId::generate();
163    }
Identity->getEmail
87        return $this->email;
88    }
Identity->getId
82        return $this->id;
83    }
Identity->getPasswordHash
95        return $this->passwordHash;
96    }
Identity->getRoles
103        return $this->roles;
104    }
Identity->getUsername
91        return $this->username;
92    }
Identity->getValidationToken
113        return $this->validationToken;
114    }
Identity->isComplete
108        return $this->isComplete;
109    }
Identity->pullEvents
121        $events = $this->events;
122        $this->events = [];
123        return $events;
124    }
{closure:/home/runner/work/my-lego-collection/my-lego-collection/back/src/Auth/Domain/Model/Identity.php:47-47}
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
 
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
 
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
 
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
 
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
{main}
3namespace App\Auth\Domain\Model;
4
5use App\Auth\Domain\Event\EmailChangedEvent;
6use App\Auth\Domain\Event\IdentityCompletedEvent;
7use App\Auth\Domain\Event\IdentityCreatedEvent;
8use App\Auth\Domain\Exception\AuthErrorCode;
9use App\Shared\Domain\Event\DomainEvent;
10use App\Shared\Domain\Exception\ValidationException;
11use App\Shared\Domain\Model\EntityId;
12use App\Shared\Domain\Model\ProducesDomainEvents;
13use App\Shared\Domain\Validation\Validator;
14
15final class Identity implements ProducesDomainEvents
16{
17
18    /**
19     * @var array<DomainEvent>
20     */
21    private array $events = [];
22
23    /**
24     * @param EntityId $id
25     * @param string $email
26     * @param string $username
27     * @param string $passwordHash
28     * @param list<string> $roles
29     * @param boolean $isComplete
30     * @param string $validationToken
31     * @throws ValidationException
32    */
33    public function __construct(
34        private readonly EntityId $id,
35        public readonly string    $email,
36        private readonly string   $username,
37        private readonly string   $passwordHash,
38        private readonly array    $roles = ['ROLE_USER'],
39        private readonly bool $isComplete = false,
40        private readonly string $validationToken = ''
41    ) {
42        $validator = new Validator();
43        $validator
44            ->requireNotEmpty('id', $this->id)
45            ->requireNotEmpty('email', $this->email)
46            ->requireValidEmail('email', $this->email)
47            ->require('username', fn () => (bool)preg_match('/^[a-zA-Z0-9_-]+$/', $this->username), AuthErrorCode::INVALID_USERNAME)
48            ->requireNotEmpty('passwordHash', $this->passwordHash)
49            ->requireNotEmpty('roles', $this->roles)
50            ->validate();
51    }
52
53    /**
54     * @param EntityId $id
55     * @param string $email
56     * @param string $username
57     * @param string $passwordHash
58     * @param list<string> $roles
59     * @return self
60     */
61    public static function create(
62        EntityId $id,
63        string    $email,
64        string   $username,
65        string   $passwordHash,
66        array    $roles = ['ROLE_USER']
67    ): self {
68        $newUser = new self(
69            id: $id,
70            email: $email,
71            username: $username,
72            passwordHash: $passwordHash,
73            roles: $roles,
74            isComplete: false,
75        );
76        $newUser->events = [new IdentityCreatedEvent($newUser)];
77        return $newUser;
78    }
79
80    public function getId(): EntityId
81    {
82        return $this->id;
83    }
84
85    public function getEmail(): string
86    {
87        return $this->email;
88    }
89    public function getUsername(): string
90    {
91        return $this->username;
92    }
93    public function getPasswordHash(): string
94    {
95        return $this->passwordHash;
96    }
97
98    /**
99     * @return list<string>
100     */
101    public function getRoles(): array
102    {
103        return $this->roles;
104    }
105
106    public function isComplete(): bool
107    {
108        return $this->isComplete;
109    }
110
111    public function getValidationToken(): string
112    {
113        return $this->validationToken;
114    }
115
116    /**
117     * @return array<DomainEvent>
118     */
119    public function pullEvents(): array
120    {
121        $events = $this->events;
122        $this->events = [];
123        return $events;
124    }
125
126    public function complete(): self
127    {
128        if ($this->isComplete()) {
129            return $this;
130        }
131
132        $new = new self(
133            id: $this->id,
134            email: $this->email,
135            username: $this->username,
136            passwordHash: $this->passwordHash,
137            roles: $this->roles,
138            isComplete: true,
139            validationToken: $this->generateValidationToken()
140        );
141        $new->events = [new IdentityCompletedEvent($new)];
142        return $new;
143    }
144
145    public function changeEmail(string $email): self
146    {
147        $new = new self(
148            id: $this->id,
149            email: $email,
150            username: $this->username,
151            passwordHash: $this->passwordHash,
152            roles: $this->roles,
153            isComplete: true,
154            validationToken: $this->generateValidationToken()
155        );
156        $new->events = [new EmailChangedEvent($new)];
157        return $new;
158    }
159
160    private function generateValidationToken(): string
161    {
162        return EntityId::generate();
163    }