Passed
Push — master ( 545ffe...df9322 )
by JHONATAN
05:01
created

ObjectStorage::attach()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2.0185
1
<?php
2
3
namespace Vox\Webservice;
4
5
use InvalidArgumentException;
6
use Metadata\MetadataFactoryInterface;
7
use BadMethodCallException;
8
use Vox\Metadata\PropertyMetadata;
9
use Vox\Webservice\Mapping\BelongsTo;
10
use Vox\Webservice\Mapping\HasMany;
11
use Vox\Webservice\Mapping\HasOne;
12
use Vox\Webservice\Metadata\TransferMetadata;
13
14
/**
15
 * A object storage using an id hashmap pattern
16
 * 
17
 * @author Jhonatan Teixeira <[email protected]>
18
 */
19
class ObjectStorage implements ObjectStorageInterface
20
{
21
    use MetadataTrait;
22
    
23
    private $storage = [];
24
    
25 24
    public function __construct(MetadataFactoryInterface $metadataFactory)
26
    {
27 24
        $this->metadataFactory = $metadataFactory;
28 24
    }
29
    
30 13
    public function contains($object): bool
31
    {
32 13
        return isset($this->storage[get_class($object)][$this->getIdValue($object)]);
33
    }
34
    
35 12
    public function attach($object)
36
    {
37 12
        $className = get_class($object);
38 12
        $id        = $this->getIdValue($object);
39
        
40 12
        if (!$id) {
41
            throw new InvalidArgumentException('object has no id value');
42
        }
43
        
44 12
        $this->storage[$className][$id] = $object;
45 12
    }
46
    
47 8
    public function detach($object)
48
    {
49 8
        unset($this->storage[get_class($object)][$this->getIdValue($object)]);
50 8
    }
51
52 10
    public function getIterator()
53
    {
54 10
        $items = [];
55
        
56 10
        foreach ($this->storage as $transferData) {
57 8
            foreach ($transferData as $item) {
58 8
                $items[] = $item;
59
            }
60
        }
61
        
62 10
        return new \ArrayIterator($items);
63
    }
64
65 7
    public function isEquals($object): bool
66
    {
67 7
        $className    = get_class($object);
68 7
        $metadata     = $this->getClassMetadata($object);
69 7
        $idValue      = $this->getIdValue($object);
70 7
        $storedObject = $this->storage[$className][$idValue];
71
72
        /* @var $propertyMetadata PropertyMetadata */
73 7
        foreach ($metadata->propertyMetadata as $name => $propertyMetadata) {
74 7
            $storedValue = $propertyMetadata->getValue($storedObject);
75 7
            $value       = $propertyMetadata->getValue($object);
76
77 7
            if ($propertyMetadata->hasAnnotation(BelongsTo::class)) {
78 1
                if (!empty($value)
79 1
                    && $this->hasRelationshipChanged($object, $value, $propertyMetadata, $metadata)) {
80 1
                    return false;
81
                }
82
83 1
                continue;
84
            }
85
86 7
            if ($propertyMetadata->hasAnnotation(HasOne::class) || $propertyMetadata->hasAnnotation(HasMany::class)) {
87 1
                continue;
88
            }
89
90 7
            if ($storedValue != $value) {
91 7
                return false;
92
            }
93
        }
94
95 1
        return true;
96
    }
97
98 1
    private function hasRelationshipChanged(
99
        $object,
100
        $value,
101
        PropertyMetadata $propertyMetadata,
102
        TransferMetadata $metadata
103
    ): bool {
104
        /* @var $belongsTo BelongsTo */
105 1
        $belongsTo  = $propertyMetadata->getAnnotation(BelongsTo::class);
106 1
        $externalId = $this->getIdValue($value);
107 1
        $internalId = $metadata->propertyMetadata[$belongsTo->foreignField]->getValue($object);
108
109 1
        if ($externalId !== $internalId) {
110 1
            return true;
111
        }
112
113 1
        return false;
114
    }
115
116
    /**
117
     * @param string $className
118
     * @param scalar $id
119
     *
120
     * @return object
121
     */
122 6
    public function fetchByParams(...$params)
123
    {
124 6
        if (count($params) != 2) {
125
            throw new BadMethodCallException('this method needs two params, $className: string, $id: scalar');
126
        }
127
128 6
        $className = (string) $params[0];
129 6
        $id        = $params[1];
130
131 6
        if (!is_scalar($id)) {
132
            throw new BadMethodCallException('$id must be scalar value');
133
        }
134
135 6
        return $this->storage[$className][$id] ?? null;
136
    }
137
}
138