Passed
Push — dev_2x ( fedccd...fb9ebe )
by Adrian
02:16
created

Patcher::patchCollection()   B

Complexity

Conditions 9
Paths 13

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
c 1
b 0
f 0
dl 0
loc 37
rs 8.0555
cc 9
nc 13
nop 3
1
<?php
2
declare(strict_types=1);
3
4
namespace Sirius\Orm\Entity;
5
6
use Sirius\Orm\Collection\Collection;
7
use Sirius\Orm\Contract\EntityInterface;
8
use Sirius\Orm\Contract\Relation\ToManyInterface;
9
use Sirius\Orm\Contract\Relation\ToOneInterface;
10
use Sirius\Orm\Helpers\Arr;
11
use Sirius\Orm\Mapper;
12
13
class Patcher
14
{
15
    /**
16
     * @var Mapper
17
     */
18
    protected $mapper;
19
20
    public function __construct(Mapper $mapper)
21
    {
22
        $this->mapper = $mapper;
23
    }
24
25
    public function __invoke(EntityInterface $entity, array $attributes)
26
    {
27
        $names      = $this->mapper->getConfig()->getAttributeNames();
28
        $properties = $this->mapper->getHydrator()->hydrateToArray(Arr::only($attributes, $names));
29
        $relations  = array_keys($this->mapper->getRelations());
30
        foreach (array_keys($attributes) as $attr) {
31
            // we have an attribute
32
            if (in_array($attr, $names) && isset($properties[$attr])) {
33
                $this->mapper->getHydrator()->set($entity, $attr, $properties[$attr]);
34
                continue;
35
            }
36
37
            // we have a relation
38
            if (in_array($attr, $relations)) {
39
                $this->setRelated($entity, $attr, $attributes[$attr]);
40
            }
41
        }
42
43
        return $entity;
44
    }
45
46
    protected function setRelated(EntityInterface $entity, string $relationName, $attributes)
47
    {
48
        $relation = $this->mapper->getRelation($relationName);
49
        if ($relation instanceof ToOneInterface) {
50
            $this->patchSingle($entity, $relationName, $attributes);
51
        } elseif ($relation instanceof ToManyInterface) {
52
            $this->patchCollection($entity, $relationName, $attributes);
53
        }
54
    }
55
56
    private function patchSingle(EntityInterface $entity, string $relationName, $attributes)
57
    {
58
        if (!is_array($attributes)) {
59
            $this->mapper->getHydrator()->set($entity, $relationName, $attributes);
60
            return;
61
        }
62
        $foreignMapper = $this->mapper->getRelation($relationName)
63
                                      ->getForeignMapper();
64
        $currentValue  = $this->mapper->getHydrator()->get($entity, $relationName);
65
        $this->patchOrCreate($foreignMapper, $currentValue, $attributes);
66
        $this->mapper->getHydrator()->set($entity, $relationName, $currentValue);
67
    }
68
69
    private function patchCollection(EntityInterface $entity, string $relationName, $attributes)
70
    {
71
        $foreignMapper = $this->mapper->getRelation($relationName)
72
                                      ->getForeignMapper();
73
        /** @var Collection|null $collection */
74
        $collection  = $this->mapper->getHydrator()->get($entity, $relationName);
75
        if (!$collection || $collection->isEmpty()) {
76
            $this->mapper->getHydrator()->set($entity, $relationName, $foreignMapper->newCollection($attributes));
77
            return;
78
        }
79
80
        $newCollection = $foreignMapper->newCollection($attributes);
81
82
        // first remove the elements from the current collection
83
        // that are not present in the new collection
84
        foreach ($collection as $item) {
85
            if (!$newCollection->contains($item)) {
86
                $collection->removeElement($item);
87
                continue;
88
            }
89
        }
90
91
        // add or update elements in the current collection
92
        // that exist in the new collection
93
        foreach ($newCollection as $idx => $item) {
94
            $pk = $foreignMapper->getHydrator()->getPk($item);
95
            if (!$pk || !$collection->contains($item)) {
96
                $collection->add($item);
97
                continue;
98
            }
99
100
            $crtItem = $collection->findByPk($pk);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $crtItem is correct as $collection->findByPk($pk) targeting Sirius\Orm\Collection\Collection::findByPk() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
101
            if ($crtItem) {
102
                $foreignMapper->patch($crtItem, $attributes[$idx]);
103
            } else {
104
                // fallback for when the item is not found
105
                $collection->add($item);
106
            }
107
        }
108
    }
109
110
    private function patchOrCreate(Mapper $mapper, EntityInterface $entity = null, array $attributes = [])
111
    {
112
        if ($entity) {
113
            return $mapper->patch($entity, $attributes);
114
        }
115
116
        return $mapper->newEntity($attributes);
117
    }
118
}
119