1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Daikon\Entity\EntityType; |
4
|
|
|
|
5
|
|
|
use Daikon\Entity\Assert\Assertion; |
6
|
|
|
use Daikon\Entity\Entity\EntityInterface; |
7
|
|
|
use Daikon\Entity\Entity\NestedEntity; |
8
|
|
|
use Daikon\Entity\Entity\TypedEntityInterface; |
9
|
|
|
use Daikon\Entity\Error\CorruptValues; |
10
|
|
|
use Daikon\Entity\Error\MissingImplementation; |
11
|
|
|
use Daikon\Entity\Error\UnexpectedValue; |
12
|
|
|
use Daikon\Entity\ValueObject\Nil; |
13
|
|
|
use Daikon\Entity\ValueObject\ValueObjectInterface; |
14
|
|
|
|
15
|
|
|
class NestedEntityAttribute implements AttributeInterface |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* @var string |
19
|
|
|
*/ |
20
|
|
|
private $name; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var EntityTypeInterface |
24
|
|
|
*/ |
25
|
|
|
private $entityType; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var EntityTypeMap |
29
|
|
|
*/ |
30
|
|
|
private $allowedTypes; |
31
|
|
|
|
32
|
54 |
|
public static function define( |
33
|
|
|
string $name, |
34
|
|
|
$entityTypeClasses, |
35
|
|
|
EntityTypeInterface $entityType |
36
|
|
|
): AttributeInterface { |
37
|
54 |
|
Assertion::isArray($entityTypeClasses); |
38
|
54 |
|
return new static($name, $entityType, $entityTypeClasses); |
39
|
|
|
} |
40
|
|
|
|
41
|
19 |
|
public function getValueType(): EntityTypeMap |
42
|
|
|
{ |
43
|
19 |
|
return $this->allowedTypes; |
44
|
|
|
} |
45
|
|
|
|
46
|
23 |
|
public function makeValue($value = null, EntityInterface $parent = null): ValueObjectInterface |
47
|
|
|
{ |
48
|
23 |
|
if ($value instanceof NestedEntity) { |
49
|
2 |
|
foreach ($this->getValueType() as $type) { |
50
|
2 |
|
if ($type === $value->getEntityType()) { |
51
|
2 |
|
return $value; |
52
|
|
|
} |
53
|
|
|
} |
54
|
|
|
throw new UnexpectedValue("Given entity-type is not allowed for attribute ".$this->getName()); |
55
|
|
|
} |
56
|
21 |
|
Assertion::nullOrisArray($value); |
57
|
20 |
|
return is_array($value) ? $this->makeEntity($value, $parent) : Nil::fromNative($value); |
|
|
|
|
58
|
|
|
} |
59
|
|
|
|
60
|
41 |
|
public function getName(): string |
61
|
|
|
{ |
62
|
41 |
|
return $this->name; |
63
|
|
|
} |
64
|
|
|
|
65
|
3 |
|
public function getEntityType(): EntityTypeInterface |
66
|
|
|
{ |
67
|
3 |
|
return $this->entityType; |
68
|
|
|
} |
69
|
|
|
|
70
|
1 |
|
public function getParent(): ?AttributeInterface |
71
|
|
|
{ |
72
|
1 |
|
return $this->getEntityType()->getParentAttribute(); |
73
|
|
|
} |
74
|
|
|
|
75
|
54 |
|
protected function __construct(string $name, EntityTypeInterface $entityType, array $allowedTypeClasses) |
76
|
|
|
{ |
77
|
54 |
|
$this->name = $name; |
78
|
54 |
|
$this->entityType = $entityType; |
79
|
54 |
|
$this->allowedTypes = new EntityTypeMap(array_map(function (string $typeFqcn) { |
80
|
54 |
|
if (!class_exists($typeFqcn)) { |
81
|
2 |
|
throw new MissingImplementation("Unable to load given entity-type class: '$typeFqcn'"); |
82
|
|
|
} |
83
|
54 |
|
return new $typeFqcn($this); |
84
|
54 |
|
}, $allowedTypeClasses)); |
85
|
54 |
|
} |
86
|
|
|
|
87
|
19 |
|
private function makeEntity(array $entityValues, TypedEntityInterface $parentEntity = null): NestedEntity |
88
|
|
|
{ |
89
|
19 |
|
Assertion::keyExists($entityValues, TypedEntityInterface::ENTITY_TYPE); |
90
|
17 |
|
$typePrefix = $entityValues[TypedEntityInterface::ENTITY_TYPE]; |
91
|
17 |
|
if (!$this->allowedTypes->has($typePrefix)) { |
92
|
2 |
|
throw new CorruptValues("Unknown type prefix given within nested-entity values."); |
93
|
|
|
} |
94
|
|
|
/* @var NestedEntity $entity */ |
95
|
15 |
|
$entity = $this->allowedTypes->get($typePrefix)->makeEntity($entityValues, $parentEntity); |
96
|
15 |
|
return $entity; |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.