Issues (590)

src/Relations/Polymorph.php (4 issues)

1
<?php
2
3
namespace Bdf\Prime\Relations;
4
5
use InvalidArgumentException;
6
7
/**
8
 * Polymorph
9
 *
10
 * @template E as object
11
 */
12
trait Polymorph
13
{
14
    /**
15
     * Map of entities
16
     *
17
     * @var array
18
     */
19
    protected $map = [];
20
21
    /**
22
     * The discriminator property name for polymorphic relation
23
     *
24
     * @var string
25
     */
26
    protected $discriminator;
27
28
    /**
29
     * The discriminator value for polymorphic relation
30
     *
31
     * @var int|string|null
32
     */
33
    protected $discriminatorValue;
34
35
    /**
36
     * Set the polymorphic map
37
     *
38
     * @param array $map
39
     *
40
     * @return $this
41
     */
42 96
    public function setMap(array $map)
43
    {
44 96
        $this->map = $map;
45
46 96
        return $this;
47
    }
48
49
    /**
50
     * Get the map from the discriminator value
51
     *
52
     * @param string|int|null $value The discriminator value. Can be null
53
     *
54
     * @return array{entity:class-string,distantKey:string,constraints?:mixed}|null Resolved parameters, or null if the relation is not set
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{entity:class-strin...onstraints?:mixed}|null at position 4 could not be parsed: Unknown type name 'class-string' at position 4 in array{entity:class-string,distantKey:string,constraints?:mixed}|null.
Loading history...
55
     *
56
     * @throws InvalidArgumentException If the value has no map
57
     */
58 140
    public function map($value)
59
    {
60
        // empty string are considered as null due to the implicit cast of null key in array
61
        // do not use empty() to allow 0 as discriminator value
62 140
        if ($value === null || $value === '') {
63 1
            return null;
64
        }
65
66 140
        if (empty($this->map[$value])) {
67
            throw new InvalidArgumentException('Unknown discriminator type "'.$value.'"');
68
        }
69
70 140
        return $this->resolveEntity($this->map[$value]);
71
    }
72
73
    /**
74
     * Set the discriminator property name
75
     *
76
     * @param string $discriminator
77
     *
78
     * @return $this
79
     */
80 112
    public function setDiscriminator($discriminator)
81
    {
82 112
        $this->discriminator = $discriminator;
83
84 112
        return $this;
85
    }
86
87
    /**
88
     * Set the discriminator value
89
     *
90
     * @param string|int|null $value
91
     *
92
     * @return $this
93
     */
94 16
    public function setDiscriminatorValue($value)
95
    {
96 16
        $this->discriminatorValue = $value;
97
98 16
        return $this;
99
    }
100
101
    /**
102
     * Is the relation polymorphic
103
     *
104
     * @return bool
105
     */
106 262
    public function isPolymorphic()
107
    {
108 262
        return $this->discriminator !== null;
109
    }
110
111
    /**
112
     * Get the map from the discriminator value
113
     *
114
     * @param class-string $className
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
115
     *
116
     * @return string|int The discriminator value
117
     *
118
     * @throws InvalidArgumentException   If the class name has no discriminator
119
     */
120 4
    public function discriminator($className)
121
    {
122 4
        foreach ($this->map as $type => &$value) {
123 4
            $this->resolveEntity($value);
124
125 4
            if ($value['entity'] === $className) {
126 4
                return $type;
127
            }
128
        }
129
130
        throw new InvalidArgumentException('Unknown map for the class "'.$className.'"');
131
    }
132
133
    /**
134
     * Resolve the entity name for meta relation
135
     *
136
     * @param string|array{entity:class-string,distantKey:string,constraints?:mixed} $value
0 ignored issues
show
Documentation Bug introduced by
The doc comment string|array{entity:clas...ing,constraints?:mixed} at position 6 could not be parsed: Unknown type name 'class-string' at position 6 in string|array{entity:class-string,distantKey:string,constraints?:mixed}.
Loading history...
137
     *
138
     * @return array{entity:class-string,distantKey:string,constraints?:mixed}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{entity:class-strin...ing,constraints?:mixed} at position 4 could not be parsed: Unknown type name 'class-string' at position 4 in array{entity:class-string,distantKey:string,constraints?:mixed}.
Loading history...
139
     */
140 140
    protected function resolveEntity(&$value): array
141
    {
142 140
        if (is_string($value)) {
143 62
            list($entity, $distantKey) = Relation::parseEntity($value);
144
145 62
            $value = [
146 62
                'entity'     => $entity,
147 62
                'distantKey' => $distantKey,
148 62
            ];
149
        }
150
151 140
        return $value;
152
    }
153
154
    /**
155
     * @param array $with
156
     *
157
     * @return array
158
     */
159 123
    protected function rearrangeWith(array $with): array
160
    {
161 123
        $rearrangedWith = [];
162
163 123
        foreach ($this->map as $discriminator => $meta) {
164 123
            $rearrangedWith[$discriminator] = [];
165
        }
166
167 123
        foreach ($with as $relationName => $relations) {
168 52
            $parts = explode('#', $relationName, 2);
169
170 52
            if (count($parts) > 1) {
171 36
                $rearrangedWith[$parts[0]][$parts[1]] = $relations;
172
            } else {
173 22
                foreach ($rearrangedWith as $discriminator => $values) {
174 22
                    $rearrangedWith[$discriminator][$relationName] = $relations;
175
                }
176
            }
177
        }
178
179 123
        return $rearrangedWith;
180
    }
181
182
    /**
183
     * @param array $without
184
     *
185
     * @return array
186
     */
187 120
    protected function rearrangeWithout(array $without): array
188
    {
189 120
        $rearranged = [];
190
191 120
        foreach ($this->map as $discriminator => $meta) {
192 120
            $rearranged[$discriminator] = [];
193
        }
194
195 120
        foreach ($without as $relationName) {
196 16
            $parts = explode('#', $relationName, 2);
197
198 16
            if (count($parts) > 1) {
199 1
                $rearranged[$parts[0]][] = $parts[1];
200
            } else {
201 15
                foreach ($rearranged as $discriminator => $values) {
202 15
                    $rearranged[$discriminator][] = $relationName;
203
                }
204
            }
205
        }
206
207 120
        return $rearranged;
208
    }
209
210
    /**
211
     * Get the discriminator value from an entity
212
     *
213
     * @param E $entity
214
     *
215
     * @return void
216
     */
217 31
    protected function updateDiscriminatorValue($entity): void
218
    {
219
        /** @psalm-suppress InvalidArgument */
220 31
        $this->discriminatorValue = $this->local->mapper()->extractOne($entity, $this->discriminator);
221
    }
222
}
223