Completed
Push — master ( a5189e...da7714 )
by Pavel
02:31
created

CanHydrate::setProperty()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 3
dl 0
loc 13
ccs 8
cts 8
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A CanHydrate::setObjectProperty() 0 9 2
1
<?php namespace Pz\Doctrine\Rest\Traits;
2
3
use Doctrine\Common\Collections\ArrayCollection;
4
use Doctrine\Common\Util\ClassUtils;
5
use Doctrine\ORM\Mapping\ClassMetadataInfo;
6
use Pz\Doctrine\Rest\Contracts\JsonApiResource;
7
use Pz\Doctrine\Rest\Exceptions\RestException;
8
use Pz\Doctrine\Rest\RestRepository;
9
10
trait CanHydrate
11
{
12
    /**
13
     * @return RestRepository
14
     */
15
    abstract public function repository();
16
17
    /**
18
     * @param string|object $entity
19
     * @param array         $data
20
     * @param string        $scope
21
     *
22
     * @return object
23
     * @throws RestException
24
     */
25 7
    public function hydrateEntity($entity, array $data, $scope = '')
26
    {
27 7
        $hydrated = false;
28 7
        $entity = is_object($entity) ? $entity : new $entity;
29
30 7
        if (isset($data['attributes']) && is_array($data['attributes'])) {
31 7
            $entity = $this->hydrateAttributes($entity, $data['attributes'], $scope);
32 6
            $hydrated = true;
33
        }
34
35
36 7
        if (isset($data['relationships']) && is_array($data['relationships'])) {
37 3
            $entity = $this->hydrateRelationships($entity, $data['relationships'], $scope);
38 2
            $hydrated = true;
39
        }
40
41 7
        if (!$hydrated) {
42 1
            throw RestException::missingDataMembers($scope);
43
        }
44
45 6
        return $entity;
46
    }
47
48
    /**
49
     * @param        $entity
50
     * @param array  $attributes
51
     * @param string $scope
52
     *
53
     * @return mixed
54
     * @throws RestException
55
     */
56 7
    private function hydrateAttributes($entity, array $attributes, $scope = '')
57
    {
58 7
        $metadata = $this->repository()->getEntityManager()->getClassMetadata(ClassUtils::getClass($entity));
59
60 7
        foreach ($attributes as $name => $value) {
61 7
            if (!isset($metadata->reflFields[$name])) {
62 1
                throw RestException::unknownAttribute($scope.$name);
63
            }
64
65 6
            $this->setObjectProperty($entity, $name, $value);
66
        }
67
68 6
        return $entity;
69
    }
70
71
    /**
72
     * @param       $entity
73
     * @param array $relationships
74
     * @param       $scope
75
     *
76
     * @return mixed
77
     * @throws RestException
78
     */
79 3
    private function hydrateRelationships($entity, array $relationships, $scope)
80
    {
81 3
        $metadata = $this->repository()->getEntityManager()->getClassMetadata(ClassUtils::getClass($entity));
82
83 3
        foreach ($relationships as $name => $data) {
84 3
            if (!isset($metadata->associationMappings[$name])) {
85 1
                throw RestException::unknownRelation($scope.$name);
86
            }
87
88 3
            $mapping = $metadata->associationMappings[$name];
89
90 3
            if (!isset($data['data'])) {
91 1
                throw RestException::missingData($scope.$name);
92
            }
93
94 3
            if (in_array($mapping['type'], [ClassMetadataInfo::ONE_TO_ONE, ClassMetadataInfo::MANY_TO_ONE])) {
95 3
                $this->setObjectProperty($entity, $name,
96 3
                    $this->hydrateRelationData($mapping['targetEntity'], $data['data'], $scope.$name)
97
                );
98
            }
99
100 3
            if (in_array($mapping['type'], [ClassMetadataInfo::ONE_TO_MANY, ClassMetadataInfo::MANY_TO_MANY])) {
101 3
                $this->hydrateToManyRelation($entity, $name, $mapping['targetEntity'], $data['data'], $scope.$name);
102
            }
103
        }
104
105 2
        return $entity;
106
    }
107
108
    /**
109
     * Hydrate one relation.
110
     *
111
     * @param object $entity
112
     * @param string $name          Relation name
113
     * @param string $targetEntity  Doctrine relation class name
114
     * @param mixed  $data
115
     * @param string $scope
116
     *
117
     * @return object
118
     * @throws RestException
119
     */
120 2
    private function hydrateToManyRelation($entity, $name, $targetEntity, $data, $scope)
121
    {
122 2
        if (!is_array($data)) {
123 1
            throw RestException::missingData($scope);
124
        }
125
126 1
        $this->setObjectProperty($entity, $name,
127 1
            new ArrayCollection(array_map(
128 1
                function($item, $index) use ($targetEntity, $scope) {
129 1
                    return $this->hydrateRelationData($targetEntity, $item, $scope.'['.$index.']');
130 1
                },
131 1
                $data,
132 1
                array_keys($data)
133
            ))
134
        );
135 1
    }
136
137
    /**
138
     * @param string $class
139
     * @param mixed  $data
140
     * @param string $scope
141
     *
142
     * @return object
143
     * @throws RestException
144
     * @throws \Doctrine\ORM\ORMException
145
     */
146 3
    private function hydrateRelationData($class, $data, $scope)
147
    {
148 3
        if (is_scalar($data)) {
149 1
            return $this->repository()->getEntityManager()->getReference($class, $data);
150
        }
151
152 3
        if (!is_array($data)) {
153 1
            throw RestException::missingData($scope);
154
        }
155
156 2
        if (isset($data['id']) && isset($data['type'])) {
157 2
            return $this->repository()->getEntityManager()->getReference($class, $data['id']);
158
        } else {
159 1
            return $this->hydrateEntity($class, $data, $scope.'.');
160
        }
161
    }
162
163
    /**
164
     * Set property on entity object.
165
     *
166
     * @param object $entity
167
     * @param string $name
168
     * @param mixed  $value
169
     *
170
     * @return object
171
     * @throws RestException
172
     */
173 7
    private function setObjectProperty($entity, $name, $value)
174
    {
175 7
        $setter = 'set'.ucfirst($name);
176
177 7
        if (!method_exists($entity, $setter)) {
178 1
            throw RestException::missingSetter($entity, $name, $setter);
179
        }
180
181 6
        return $entity->$setter($value);
182
    }
183
}
184