Completed
Push — master ( fd9fb9...4b5f01 )
by Jesse
05:34
created

IdentityMap::hasThe()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\IdentityMap;
5
6
use function array_keys;
7
use function assert as makeSureThat;
8
use function get_class as theClassOfThe;
9
use function is_object as itIsAn;
10
use function spl_object_id as theInstanceIdOf;
11
12
/**
13
 * Contains objects by class and id.
14
 *
15
 * @author Stratadox
16
 */
17
final class IdentityMap implements MapsObjectsByIdentity
18
{
19
    private $objectWith;
20
    private $entityIdFor;
21
22
    private function __construct(array $objectsByClassAndId, array $idsByObject)
23
    {
24
        $this->objectWith = $objectsByClassAndId;
25
        $this->entityIdFor = $idsByObject;
26
    }
27
28
    /**
29
     * Produces a new identity map that contains the objects.
30
     *
31
     * @param object[] $theseObjects The objects to add, as [id => object]
32
     * @return MapsObjectsByIdentity The map of objects.
33
     */
34
    public static function with(array $theseObjects): MapsObjectsByIdentity
35
    {
36
        $objects = [];
37
        $entityIds = [];
38
        foreach ($theseObjects as $id => $object) {
39
            $objects = IdentityMap::addTo($objects, (string) $id, $object);
40
            $entityIds[theInstanceIdOf($object)] = (string) $id;
41
        }
42
        return new self($objects, $entityIds);
43
    }
44
45
    /**
46
     * Produces an empty identity map.
47
     *
48
     * @return MapsObjectsByIdentity The empty map of objects.
49
     */
50
    public static function startEmpty(): MapsObjectsByIdentity
51
    {
52
        return new self([], []);
53
    }
54
55
    /** @inheritdoc */
56
    public function has(string $class, string $id): bool
57
    {
58
        return isset($this->objectWith[$class][$id]);
59
    }
60
61
    /** @inheritdoc */
62
    public function hasThe(object $object): bool
63
    {
64
        return isset($this->entityIdFor[theInstanceIdOf($object)]);
65
    }
66
67
    /** @inheritdoc */
68
    public function get(string $class, string $id): object
69
    {
70
        $this->mustHave($class, $id);
71
        return $this->objectWith[$class][$id];
72
    }
73
74
    /** @inheritdoc */
75
    public function add(string $id, object $object): MapsObjectsByIdentity
76
    {
77
        $class = theClassOfThe($object);
78
        $this->mayNotAlreadyHave($class, $id);
79
80
        $new = clone $this;
81
        $new->objectWith[$class][$id] = $object;
82
        $new->entityIdFor[theInstanceIdOf($object)] = $id;
83
        return $new;
84
    }
85
86
    /** @inheritdoc */
87
    public function remove(string $class, string $id): MapsObjectsByIdentity
88
    {
89
        $this->mustHave($class, $id);
90
        $entityIdFor = $this->entityIdFor;
91
        $objectWith = $this->objectWith;
92
        unset(
93
            $entityIdFor[theInstanceIdOf($objectWith[$class][$id])],
94
            $objectWith[$class][$id]
95
        );
96
        return new IdentityMap($objectWith, $entityIdFor);
97
    }
98
99
    /** @inheritdoc */
100
    public function removeThe(object $object): MapsObjectsByIdentity
101
    {
102
        return $this->remove(theClassOfThe($object), $this->idOf($object));
103
    }
104
105
    /** @inheritdoc */
106
    public function removeAllObjectsOfThe(string $class): MapsObjectsByIdentity
107
    {
108
        $objectsOf = $this->objectWith;
109
        if (!isset($objectsOf[$class])) {
110
            return $this;
111
        }
112
        $entityIdFor = $this->entityIdFor;
113
        foreach ($objectsOf[$class] as $object) {
114
            makeSureThat(itIsAn($object));
115
            unset($entityIdFor[theInstanceIdOf($object)]);
116
        }
117
        unset($objectsOf[$class]);
118
        return new IdentityMap($objectsOf, $entityIdFor);
119
    }
120
121
    /** @inheritdoc */
122
    public function idOf(object $object): string
123
    {
124
        if (!isset($this->entityIdFor[theInstanceIdOf($object)])) {
125
            throw IdentityNotFound::forThe($object);
126
        }
127
        return $this->entityIdFor[theInstanceIdOf($object)];
128
    }
129
130
    /** @inheritdoc */
131
    public function classes(): array
132
    {
133
        return array_keys($this->objectWith);
134
    }
135
136
    /** @throws NoSuchObject */
137
    private function mustHave(string $class, string $id): void
138
    {
139
        if ($this->has($class, $id)) {
140
            return;
141
        }
142
        throw IdentityNotFound::requesting($class, $id);
143
    }
144
145
    /** @throws AlreadyThere */
146
    private function mayNotAlreadyHave(string $class, string $id): void
147
    {
148
        if ($this->has($class, $id)) {
149
            throw DuplicationDetected::in($class, $id);
150
        }
151
    }
152
153
    private static function addTo(
154
        array $objectsBy,
155
        string $withId,
156
        object $object
157
    ): array {
158
        $objectsBy[theClassOfThe($object)][$withId] = $object;
159
        return $objectsBy;
160
    }
161
}
162