| 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 |  |  |  |