Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
UserIdentity
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
5 / 5
6
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 provider
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 subject
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 userId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createdAt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace App\Identity\Domain;
6
7use App\Identity\Domain\ValueObject\IdentityProvider;
8use App\Identity\Domain\ValueObject\UserId;
9use DateTimeImmutable;
10use Doctrine\ORM\Mapping as ORM;
11use InvalidArgumentException;
12
13/**
14 * Links a local user to their account at an external provider. The provider's
15 * subject ("sub") is stable and unique per provider, so (provider, subject) is a
16 * natural key and nothing references an identity row: ponytail: composite PK
17 * over a surrogate id, same call as TripMember.
18 *
19 * The FK to users is declared in ForeignKeyConstraintListener (project rule:
20 * reference by id value object, never an ORM association).
21 */
22#[ORM\Entity]
23#[ORM\Table(name: 'user_identities')]
24#[ORM\Index(name: 'idx_user_identity_user', columns: ['user_id'])]
25final class UserIdentity
26{
27    public function __construct(
28        #[ORM\Id]
29        #[ORM\Column(type: 'string', length: 20, enumType: IdentityProvider::class)]
30        private readonly IdentityProvider $provider,
31        #[ORM\Id]
32        #[ORM\Column(length: 255)]
33        private readonly string $subject,
34        #[ORM\Column(name: 'user_id', type: 'user_id')]
35        private readonly UserId $userId,
36        #[ORM\Column(name: 'created_at', type: 'datetime_immutable')]
37        private readonly DateTimeImmutable $createdAt = new DateTimeImmutable(),
38    ) {
39        if (trim($subject) === '') {
40            throw new InvalidArgumentException('An identity subject cannot be empty.');
41        }
42    }
43
44    public function provider(): IdentityProvider
45    {
46        return $this->provider;
47    }
48
49    public function subject(): string
50    {
51        return $this->subject;
52    }
53
54    public function userId(): UserId
55    {
56        return $this->userId;
57    }
58
59    public function createdAt(): DateTimeImmutable
60    {
61        return $this->createdAt;
62    }
63}