Passed
Push — master ( adcfba...df27c1 )
by Pavel
01:38
created

CanHydrate::hydrateAttributes()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 2
nop 3
dl 0
loc 12
ccs 6
cts 7
cp 0.8571
crap 3.0261
rs 9.4285
c 0
b 0
f 0
1
<?php namespace Pz\Doctrine\Rest\Traits;
2
3
use Doctrine\Common\Collections\ArrayCollection;
4
use Doctrine\ORM\Mapping\ClassMetadataInfo;
5
use Pz\Doctrine\Rest\Exceptions\RestException;
6
use Pz\Doctrine\Rest\RestRepository;
7
8
trait CanHydrate
9
{
10
    /**
11
     * @return RestRepository
12
     */
13
    abstract public function repository();
14
15
    /**
16
     * @param string|object $entity
17
     * @param array         $data
18
     * @param string        $scope
19
     *
20
     * @return object
21
     * @throws RestException
22
     */
23 4
    protected function hydrateData($entity, array $data, $scope = 'root')
24
    {
25 4
        $entity = is_object($entity) ? $entity : new $entity;
26
27 4
        if (!isset($data['attributes']) || !is_array($data['attributes'])) {
28
            throw RestException::missingAttributes($scope);
29
        }
30
31 4
        $entity = $this->hydrateAttributes($entity, $data['attributes'], $scope);
32
33 4
        if (isset($data['relationships']) && is_array($data['relationships'])) {
34 1
            $entity = $this->hydrateRelationships($entity, $data['relationships'], $scope);
35
        }
36
37 4
        return $entity;
38
    }
39
40
    /**
41
     * @param        $entity
42
     * @param array  $attributes
43
     * @param string $scope
44
     *
45
     * @return mixed
46
     * @throws RestException
47
     */
48 4
    protected function hydrateAttributes($entity, array $attributes, $scope = 'root')
49
    {
50 4
        $metadata = $this->repository()->getClassMetadata();
51 4
        foreach ($attributes as $name => $value) {
52 4
            if (!isset($metadata->reflFields[$name])) {
53
                throw RestException::unknownAttribute(sprintf('%s.attribute.%s', $scope, $name));
54
            }
55
56 4
            $this->setProperty($entity, $name, $value);
57
        }
58
59 4
        return $entity;
60
    }
61
62
    /**
63
     * @param       $entity
64
     * @param array $relationships
65
     * @param       $scope
66
     *
67
     * @return mixed
68
     * @throws RestException
69
     */
70 1
    protected function hydrateRelationships($entity, array $relationships, $scope)
71
    {
72 1
        $metadata = $this->repository()->getClassMetadata();
73
74 1
        foreach ($relationships as $name => $data) {
75 1
            $relationScope = sprintf('%s.relation.%s', $scope, $name);
76
77 1
            if (!isset($metadata->associationMappings[$name])) {
78
                throw RestException::unknownRelation($relationScope);
79
            }
80
81 1
            $mapping = $metadata->associationMappings[$name];
82 1
            $mappingClass = $mapping['targetEntity'];
83
84 1
            if (!isset($data['data'])) {
85
                throw RestException::missingData($relationScope);
86
            }
87
88 1
            if (in_array($mapping['type'], [ClassMetadataInfo::ONE_TO_ONE, ClassMetadataInfo::MANY_TO_ONE])) {
89 1
                $this->setProperty($entity, $name,
90 1
                    $this->hydrateRelationData($mappingClass, $data['data'], $relationScope)
91
                );
92
            }
93
94 1
            if (in_array($mapping['type'], [ClassMetadataInfo::ONE_TO_MANY, ClassMetadataInfo::MANY_TO_MANY])) {
95
                if (!is_array($data['data'])) {
96
                    throw RestException::missingData($relationScope);
97
                }
98
99
                $this->setProperty($entity, $name,
100
                    new ArrayCollection(array_map(
101
                        function($data, $index) use ($mappingClass, $relationScope) {
102
                            return $this->hydrateRelationData(
103
                                $mappingClass, $data, sprintf('%s.%s', $relationScope, $index)
104
                            );
105
                        },
106 1
                        $data['data']
107
                    ))
108
                );
109
            }
110
        }
111
112 1
        return $entity;
113
    }
114
115
    /**
116
     * @param object $entity
117
     * @param string $name
118
     * @param mixed  $value
119
     *
120
     * @return object
121
     * @throws RestException
122
     */
123 4
    protected function setProperty($entity, $name, $value)
124
    {
125 4
        $setter = 'set' . ucfirst($name);
126 4
        if (!method_exists($entity, $setter)) {
127
            throw RestException::createUnprocessable(sprintf('Setter not found for entity'));
128
        }
129
130 4
        return $entity->$setter($value);
131
    }
132
133
    /**
134
     * @param        $class
135
     * @param        $data
136
     * @param string $scope
137
     *
138
     * @return object
139
     * @throws RestException
140
     * @throws \Doctrine\ORM\ORMException
141
     */
142 4
    protected function hydrateRelationData($class, $data, $scope = 'root')
143
    {
144 4
        if (is_scalar($data)) {
145
            return $this->repository()->getEntityManager()->getReference($class, $data);
146
        }
147
148 4
        if (!is_array($data)) {
149
            throw RestException::missingData($scope);
150
        }
151
152 4
        if (isset($data['id']) && isset($data['type'])) {
153 1
            return $this->repository()->getEntityManager()->getReference($class, $data['id']);
154
        } else {
155 4
            return $this->hydrateData($class, $data, $scope);
156
        }
157
    }
158
}
159