Completed
Push — standalone ( 57a4d8...49bbc6 )
by Philip
10:02
created

RestRequestParser   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 39%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 23
lcom 1
cbo 8
dl 0
loc 179
ccs 39
cts 100
cp 0.39
rs 10
c 3
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A parseEntity() 0 22 3
A getRequestContent() 0 9 2
A updateObject() 0 19 4
B updateProperty() 0 31 2
A updatePropertyObject() 0 15 2
A isUpdateable() 0 13 4
B convert() 0 15 5
1
<?php
2
3
namespace Dontdrinkandroot\RestBundle\Service;
4
5
use Doctrine\Common\Util\ClassUtils;
6
use Doctrine\DBAL\Types\Type;
7
use Dontdrinkandroot\RestBundle\Metadata\PropertyMetadata;
8
use Metadata\MetadataFactory;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\PropertyAccess\PropertyAccessor;
11
12
class RestRequestParser
13
{
14
    /**
15
     * @var MetadataFactory
16
     */
17
    private $ddrRestMetadataFactory;
18
19
    /**
20
     * @var PropertyAccessor
21
     */
22
    private $propertyAccessor;
23
24 2
    public function __construct(MetadataFactory $ddrRestMetadataFactory, PropertyAccessor $propertyAccessor)
25
    {
26 2
        $this->ddrRestMetadataFactory = $ddrRestMetadataFactory;
27 2
        $this->propertyAccessor = $propertyAccessor;
28 2
    }
29
30
    /**
31
     * @param Request     $request
32
     * @param string      $entityClass
33
     * @param object|null $entity
34
     *
35
     * @return object
36
     */
37 2
    public function parseEntity(
38
        Request $request,
39
        $entityClass,
40
        $entity = null
41
    ) {
42 2
        $method = $request->getMethod();
43 2
        $format = $request->getRequestFormat();
44
45 2
        if ('json' !== $format) {
46
            throw new \RuntimeException(sprintf('Unsupported format "%s"', $format));
47
        }
48
49 2
        $data = $this->getRequestContent($request);
50
51 2
        if (null === $entity) {
52 1
            $entity = new $entityClass;
53
        }
54
55 2
        $this->updateObject($entity, $method, $data);
56
57 2
        return $entity;
58
    }
59
60
    /**
61
     * @param Request $request
62
     *
63
     * @return array
64
     */
65 2
    protected function getRequestContent(Request $request)
66
    {
67 2
        $content = $request->getContent();
68 2
        if ('' !== $content) {
69 2
            return json_decode($content, true);
70
        }
71
72
        return $request->request->all();
73
    }
74
75
    /**
76
     * @param object $object Access by reference.
77
     * @param string $method
78
     * @param array  $data
79
     */
80 2
    protected function updateObject(
81
        &$object,
82
        $method,
83
        $data
84
    ) {
85 2
        $classMetadata = $this->ddrRestMetadataFactory->getMetadataForClass(ClassUtils::getClass($object));
86
87 2
        foreach ($data as $key => $value) {
88 1
            if (!array_key_exists($key, $classMetadata->propertyMetadata)) {
89
                continue;
90
                //throw new \RuntimeException(sprintf('No field %s for Class %s', $key, get_class($object)));
91
            }
92
            /** @var PropertyMetadata $propertyMetadata */
93 1
            $propertyMetadata = $classMetadata->propertyMetadata[$key];
94 1
            if ($this->isUpdateable($method, $propertyMetadata)) {
95 1
                $this->updateProperty($object, $method, $key, $value, $propertyMetadata);
96
            }
97
        }
98 2
    }
99
100
    /**
101
     * @param object           $object Access by reference.
102
     * @param string           $method
103
     * @param string           $propertyName
104
     * @param mixed            $value
105
     * @param PropertyMetadata $propertyMetadata
106
     */
107 1
    protected function updateProperty(
108
        &$object,
109
        $method,
110
        $propertyName,
0 ignored issues
show
Unused Code introduced by
The parameter $propertyName is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
        $value,
112
        PropertyMetadata $propertyMetadata
113
    ) {
114
115
        // TODO: Reenable embedded
116
//        if (array_key_exists($propertyName, $doctrineClassMetadata->embeddedClasses)) {
117
//            $embeddedClass = $doctrineClassMetadata->embeddedClasses[$propertyName]['class'];
118
//            $this->updatePropertyObject($object, $method, $embeddedClass, $propertyName, $value);
119
//
120
//            return;
121
//        }
122
123
        //TODO: Reenable associations
124
//        if (array_key_exists($propertyName, $doctrineClassMetadata->associationMappings)) {
125
//            $associatedClass = $doctrineClassMetadata->associationMappings[$propertyName]['targetEntity'];
126
//            $this->updatePropertyObject($object, $method, $associatedClass, $propertyName, $value);
127
//
128
//            return;
129
//        }
130
131 1
        if (array_key_exists($propertyMetadata->getType(), Type::getTypesMap())) {
132 1
            $convertedValue = $this->convert($propertyMetadata->getType(), $value);
133 1
            $this->propertyAccessor->setValue($object, $propertyMetadata->name, $convertedValue);
134
        } else {
135
            $this->updatePropertyObject($object, $method, $propertyMetadata, $value);
136
        }
137 1
    }
138
139
    protected function updatePropertyObject(
140
        &$object,
141
        string $method,
142
        PropertyMetadata $propertyMetadata,
143
        $value
144
    ) {
145
        $propertyObject = $this->propertyAccessor->getValue($object, $propertyMetadata->name);
146
        if (null === $propertyObject) {
147
            $type = $propertyMetadata->getType();
148
            $propertyObject = new $type;
149
        }
150
151
        $this->updateObject($propertyObject, $method, $value);
152
        $this->propertyAccessor->setValue($object, $propertyMetadata->name, $propertyObject);
153
    }
154
155
    /**
156
     * @param string           $method
157
     * @param PropertyMetadata $propertyMetadata
158
     *
159
     * @return bool
160
     */
161 1
    protected function isUpdateable(
162
        $method,
163
        PropertyMetadata $propertyMetadata
164
    ) {
165 1
        if (Request::METHOD_PUT === $method || Request::METHOD_PATCH === $method) {
166 1
            return $propertyMetadata->isPuttable();
167
        }
168
        if (Request:: METHOD_POST === $method) {
169
            return $propertyMetadata->isPostable();
170
        }
171
172
        return false;
173
    }
174
175 1
    private function convert(?string $type, $value)
176
    {
177 1
        if (null === $value) {
178
            return $value;
179
        }
180
181
        switch ($type) {
182 1
            case 'datetime':
183 1
            case 'date':
184 1
            case 'time':
185 1
                return new \DateTime($value);
186
            default:
187
                return $value;
188
        }
189
    }
190
}
191