Passed
Pull Request — master (#26)
by butschster
02:08
created

Entity::getPrimaryFields()   B

Complexity

Conditions 9
Paths 12

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 13
nc 12
nop 0
dl 0
loc 26
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Cycle ORM Schema Builder.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Schema\Definition;
13
14
use Cycle\Schema\Definition\Map\FieldMap;
15
use Cycle\Schema\Definition\Map\OptionMap;
16
use Cycle\Schema\Definition\Map\RelationMap;
17
use Cycle\Schema\Exception\EntityException;
18
19
/**
20
 * Contains information about specific entity definition.
21
 */
22
final class Entity
23
{
24
    /** @var OptionMap */
25
    private $options;
26
27
    /** @var string */
28
    private $role;
29
30
    /** @var string|null */
31
    private $class;
32
33
    /** @var string|null */
34
    private $mapper;
35
36
    /** @var string|null */
37
    private $source;
38
39
    /** @var string|null */
40
    private $constrain;
41
42
    /** @var string|null */
43
    private $repository;
44
45
    /** @var FieldMap */
46
    private $fields;
47
48
    /** @var RelationMap */
49
    private $relations;
50
51
    /** @var array */
52
    private $schema = [];
53
54
    /** @var FieldMap */
55
    private $primaryKeyFields;
56
57
    /**
58
     * Entity constructor.
59
     */
60
    public function __construct()
61
    {
62
        $this->options = new OptionMap();
63
        $this->fields = new FieldMap();
64
        $this->primaryKeyFields = new FieldMap();
65
        $this->relations = new RelationMap();
66
    }
67
68
    /**
69
     * Full entity copy.
70
     */
71
    public function __clone()
72
    {
73
        $this->options = clone $this->options;
74
        $this->fields = clone $this->fields;
75
        $this->primaryKeyFields = clone $this->primaryKeyFields;
76
        $this->relations = clone $this->relations;
77
    }
78
79
    /**
80
     * @return OptionMap
81
     */
82
    public function getOptions(): OptionMap
83
    {
84
        return $this->options;
85
    }
86
87
    /**
88
     * @param string $role
89
     * @return Entity
90
     */
91
    public function setRole(string $role): self
92
    {
93
        $this->role = $role;
94
95
        return $this;
96
    }
97
98
    /**
99
     * @return string|null
100
     */
101
    public function getRole(): ?string
102
    {
103
        return $this->role;
104
    }
105
106
    /***
107
     * @param string $class
108
     * @return Entity
109
     */
110
    public function setClass(string $class): self
111
    {
112
        $this->class = $class;
113
114
        return $this;
115
    }
116
117
    /**
118
     * @return string|null
119
     */
120
    public function getClass(): ?string
121
    {
122
        return $this->class;
123
    }
124
125
    /**
126
     * @param string|null $mapper
127
     * @return Entity
128
     */
129
    public function setMapper(?string $mapper): self
130
    {
131
        $this->mapper = $mapper;
132
133
        return $this;
134
    }
135
136
    /**
137
     * @return string
138
     */
139
    public function getMapper(): ?string
140
    {
141
        return $this->normalizeClass($this->mapper);
142
    }
143
144
    /**
145
     * @param string|null $source
146
     * @return Entity
147
     */
148
    public function setSource(?string $source): self
149
    {
150
        $this->source = $source;
151
152
        return $this;
153
    }
154
155
    /**
156
     * @return string
157
     */
158
    public function getSource(): ?string
159
    {
160
        return $this->normalizeClass($this->source);
161
    }
162
163
    /**
164
     * @param string|null $constrain
165
     * @return Entity
166
     */
167
    public function setConstrain(?string $constrain): self
168
    {
169
        $this->constrain = $constrain;
170
171
        return $this;
172
    }
173
174
    /**
175
     * @return string|null
176
     */
177
    public function getConstrain(): ?string
178
    {
179
        return $this->normalizeClass($this->constrain);
180
    }
181
182
    /**
183
     * @param string|null $repository
184
     * @return Entity
185
     */
186
    public function setRepository(?string $repository): self
187
    {
188
        $this->repository = $repository;
189
190
        return $this;
191
    }
192
193
    /**
194
     * @return string
195
     */
196
    public function getRepository(): ?string
197
    {
198
        return $this->normalizeClass($this->repository);
199
    }
200
201
    /**
202
     * @return FieldMap
203
     */
204
    public function getFields(): FieldMap
205
    {
206
        return $this->fields;
207
    }
208
209
    /**
210
     * @return RelationMap
211
     */
212
    public function getRelations(): RelationMap
213
    {
214
        return $this->relations;
215
    }
216
217
    /**
218
     * @param array $schema
219
     * @return Entity
220
     */
221
    public function setSchema(array $schema): Entity
222
    {
223
        $this->schema = $schema;
224
225
        return $this;
226
    }
227
228
    /**
229
     * @return array
230
     */
231
    public function getSchema(): array
232
    {
233
        return $this->schema;
234
    }
235
236
    /**
237
     * Merge entity relations and fields.
238
     *
239
     * @param Entity $entity
240
     */
241
    public function merge(Entity $entity): void
242
    {
243
        foreach ($entity->getRelations() as $name => $relation) {
244
            if (!$this->relations->has($name)) {
245
                $this->relations->set($name, $relation);
246
            }
247
        }
248
249
        foreach ($entity->getFields() as $name => $field) {
250
            if (!$this->fields->has($name)) {
251
                $this->fields->set($name, $field);
252
            }
253
        }
254
    }
255
256
    /**
257
     * Check if entity has primary key
258
     */
259
    public function hasPrimaryKey(): bool
260
    {
261
        if ($this->primaryKeyFields->count() > 0) {
262
            return true;
263
        }
264
265
        foreach ($this->getFields() as $field) {
266
            if ($field->isPrimary()) {
267
                return true;
268
            }
269
        }
270
271
        return false;
272
    }
273
274
    /**
275
     * Set primary key columns
276
     * Column names will be converted into property names
277
     */
278
    public function setPrimaryKeys(array $columns): void
279
    {
280
        $this->primaryKeyFields = new FieldMap();
281
282
        foreach ($columns as $column) {
283
            $name = $this->getFields()->getKeyByColumnName($column);
284
            $this->primaryKeyFields->set($name, $this->getFields()->get($name));
285
        }
286
    }
287
288
    /**
289
     * Get entity primary key property names
290
     * @return FieldMap
291
     */
292
    public function getPrimaryFields(): FieldMap
293
    {
294
        $map = new FieldMap();
295
296
        foreach ($this->getFields() as $name => $field) {
297
            if ($field->isPrimary()) {
298
                $map->set($name, $field);
299
            }
300
        }
301
302
        if ($this->primaryKeyFields->count() > 0 && $map->count() === 0) {
303
            return $this->primaryKeyFields;
304
        }
305
306
        if ($this->primaryKeyFields->count() === 0 && $map->count() > 0) {
307
            return $map;
308
        }
309
310
        if (
311
            $this->primaryKeyFields->count() !== $map->count()
312
            || array_diff($map->getColumnNames(), $this->primaryKeyFields->getColumnNames()) != []
313
        ) {
314
            throw new EntityException("Ambiguous primary key definition for `{$this->getRole()}`.");
315
        }
316
317
        return $this->primaryKeyFields;
318
    }
319
320
    /**
321
     * @param string|null $class
322
     * @return string|null
323
     */
324
    private function normalizeClass(string $class = null): ?string
325
    {
326
        if ($class === null) {
327
            return null;
328
        }
329
330
        return ltrim($class, '\\');
331
    }
332
}
333