Entity::makeValue()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 10
rs 10
c 0
b 0
f 0
ccs 7
cts 7
cp 1
cc 1
nc 1
nop 2
crap 1
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/entity project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\Entity;
10
11
use Daikon\Entity\Path\ValuePathParser;
12
use Daikon\Entity\Path\ValuePathPart;
13
use Daikon\Interop\Assertion;
14
use Daikon\ValueObject\ValueObjectInterface;
15
use Daikon\ValueObject\ValueObjectMap;
16
17
abstract class Entity implements EntityInterface
18
{
19
    private ValueObjectMap $valueObjectMap;
20
21
    private ValuePathParser $pathParser;
22
23 10
    final protected function __construct(array $state = [])
24
    {
25 10
        $this->pathParser = ValuePathParser::create();
26
27 10
        $objects = [];
28 10
        foreach ($this->getAttributeMap() as $name => $attribute) {
29 10
            if (array_key_exists($name, $state)) {
30 10
                $objects[$name] = $attribute->makeValue($state[$name]);
31
            }
32
        }
33
34 10
        $this->valueObjectMap = new ValueObjectMap($objects);
35 10
    }
36
37
    /**
38
     * @param array $state
39
     * @return static
40
     */
41 10
    public static function fromNative($state): self
42
    {
43 10
        return new static($state);
44
    }
45
46 1
    public function toNative(): array
47
    {
48 1
        $entityState = $this->valueObjectMap->toNative();
49 1
        $entityState[EntityInterface::TYPE_KEY] = static::class;
50 1
        return $entityState;
51
    }
52
53
    /** @param static $entity */
54 1
    public function isSameAs($entity): bool
55
    {
56 1
        Assertion::isInstanceOf($entity, static::class);
57 1
        return $this->getIdentity()->equals($entity->getIdentity());
58
    }
59
60 3
    public function has(string $name): bool
61
    {
62 3
        $has = $this->getAttributeMap()->has($name);
63 3
        Assertion::true($has, sprintf("Attribute '%s' is not known to the entity '%s'.", $name, static::class));
64 2
        return $this->valueObjectMap->has($name);
65
    }
66
67 6
    public function get(string $name, $default = null): ?ValueObjectInterface
68
    {
69 6
        if (mb_strpos($name, '.')) {
70 2
            return $this->evaluatePath($name);
71
        }
72
73 6
        $attribute = $this->getAttributeMap()->get($name, null);
74 6
        Assertion::notNull($attribute, sprintf("Attribute '%s' is not known to entity '%s'.", $name, static::class));
75
        /** @psalm-suppress PossiblyNullArgument */
76 5
        $attributeType = get_class($attribute);
77 5
        Assertion::nullOrIsInstanceOf($default, $attributeType, sprintf(
78 5
            "Default type for '$name' must be null or $attributeType, but got '%s'.",
79 5
            is_object($default) ? get_class($default) : @gettype($default)
80
        ));
81
82 5
        return $this->valueObjectMap->get($name, $default);
83
    }
84
85
    /** @return static */
86 1
    public function withValue(string $name, $value): self
87
    {
88 1
        $copy = clone $this;
89 1
        $copy->valueObjectMap = $copy->valueObjectMap->with($name, $this->makeValue($name, $value));
90 1
        return $copy;
91
    }
92
93
    /** @return static */
94 1
    public function withValues(iterable $values): self
95
    {
96 1
        $copy = clone $this;
97 1
        foreach ($values as $name => $value) {
98 1
            $copy->valueObjectMap = $copy->valueObjectMap->with($name, $this->makeValue($name, $value));
99
        }
100 1
        return $copy;
101
    }
102
103
    /** @param static $comparator */
104
    public function equals($comparator): bool
105
    {
106
        Assertion::isInstanceOf($comparator, static::class);
107
        return (new EntityDiff)($this, $comparator)->isEmpty();
108
    }
109
110
    public function __toString(): string
111
    {
112
        return (string)$this->getIdentity();
113
    }
114
115
    /** @param mixed $value */
116 2
    private function makeValue(string $name, $value): ValueObjectInterface
117
    {
118 2
        $attribute = $this->getAttributeMap()->get($name, null);
119 2
        Assertion::isInstanceOf(
120 2
            $attribute,
121 2
            AttributeInterface::class,
122 2
            sprintf("Attribute '%s' is unknown to entity '%s'.", $name, static::class)
123
        );
124
        /** @var AttributeInterface $attribute */
125 2
        return $attribute->makeValue($value);
126
    }
127
128 2
    private function evaluatePath(string $valuePath): ?ValueObjectInterface
129
    {
130 2
        $entity = $this;
131
        /** @var ValuePathPart $pathPart */
132 2
        foreach ($this->pathParser->parse($valuePath) as $pathPart) {
133 2
            $name = $pathPart->getAttributeName();
134 2
            $value = $entity ? $entity->get($name) : null;
135 1
            if ($value && $pathPart->hasPosition()) {
136 1
                Assertion::isInstanceOf(
137 1
                    $value,
138 1
                    EntityList::class,
139 1
                    sprintf("Trying to traverse a non-entity list '%s' on entity '%s'.", $name, static::class)
140
                );
141
                /** @var EntityList $value */
142 1
                $entity = $value->get($pathPart->getPosition());
143 1
                $value = $entity;
144
            }
145
        }
146 1
        return $value ?? null;
147
    }
148
149
    public function __get(string $attribute)
150
    {
151
        return $this->get($attribute);
152
    }
153
154 10
    public function __clone()
155
    {
156 10
        $this->pathParser = clone $this->pathParser;
157 10
        $this->valueObjectMap = clone $this->valueObjectMap;
158 10
    }
159
}
160