Completed
Push — standalone ( 8da518...787e4c )
by Philip
09:19
created

Normalizer   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 96.72%

Importance

Changes 0
Metric Value
wmc 28
c 0
b 0
f 0
lcom 1
cbo 7
dl 0
loc 161
ccs 59
cts 61
cp 0.9672
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
C normalize() 0 78 13
A isIncluded() 0 14 4
A appendPath() 0 8 3
C normalizeField() 0 31 7
1
<?php
2
3
namespace Dontdrinkandroot\RestBundle\Service;
4
5
use Doctrine\Common\Collections\Collection;
6
use Doctrine\Common\Util\ClassUtils;
7
use Doctrine\DBAL\Types\Type;
8
use Dontdrinkandroot\RestBundle\Metadata\ClassMetadata;
9
use Dontdrinkandroot\RestBundle\Metadata\PropertyMetadata;
10
use Metadata\MetadataFactoryInterface;
11
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
12
13
class Normalizer
14
{
15
    /**
16
     * @var MetadataFactoryInterface
17
     */
18
    private $metadataFactory;
19
20
    /**
21
     * @var PropertyAccessorInterface
22
     */
23
    private $propertyAccessor;
24
25 24
    function __construct(MetadataFactoryInterface $metadataFactory, PropertyAccessorInterface $propertyAccessor)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
26
    {
27 24
        $this->metadataFactory = $metadataFactory;
28 24
        $this->propertyAccessor = $propertyAccessor;
29 24
    }
30
31
    /**
32
     * @param mixed    $data
33
     * @param string[] $includes
34
     * @param int      $depth
35
     * @param string   $path
36
     *
37
     * @return array
38
     */
39 24
    public function normalize($data, $includes = [], int $depth = 0, string $path = '')
40
    {
41 24
        if (is_array($data)) {
42 14
            $normalizedData = [];
43 14
            foreach ($data as $datum) {
44 14
                $normalizedData[] = $this->normalize($datum, $includes, $depth + 1, $path);
45
            }
46
47 14
            return $normalizedData;
48
        }
49
50 24
        if (is_object($data)) {
51
52 24
            $normalizedData = [];
53
54
            /** @var ClassMetadata $classMetadata */
55 24
            $classMetadata = $this->metadataFactory->getMetadataForClass(ClassUtils::getClass($data));
56
57
            /** @var PropertyMetadata $propertyMetadatum */
58 24
            foreach ($classMetadata->propertyMetadata as $propertyMetadatum) {
59
60 24
                if ($propertyMetadatum->isExcluded()) {
61 12
                    continue;
62
                }
63
64 24
                if ($propertyMetadatum->isAssociation()) {
65
66
                    /* Inlude if includable AND it is on include path */
67 18
                    if ($propertyMetadatum->isIncludable() && $this->isIncluded(
68
                            $path,
69 18
                            $propertyMetadatum->getIncludablePaths(),
70
                            $includes
71
                        )
72
                    ) {
73 4
                        $value = $this->propertyAccessor->getValue($data, $propertyMetadatum->name);
74 4
                        if ($propertyMetadatum->isCollection()) {
75
                            /** @var Collection $value */
76 2
                            $value = $value->getValues();
77
                        }
78 4
                        $normalizedData[$propertyMetadatum->name] = $this->normalize(
79
                            $value,
80
                            $includes,
81 4
                            $depth + 1,
82 18
                            $this->appendPath($path, $propertyMetadatum->name)
83
                        );
84
                    }
85
                } else {
86
87
                    /* Inlude if includable is missing OR it is on include path */
88 24
                    if (!$propertyMetadatum->isIncludable() || $this->isIncluded(
89
                            $path,
90 24
                            $propertyMetadatum->getIncludablePaths(),
91
                            $includes
92
                        )
93
                    ) {
94 24
                        $value = $this->propertyAccessor->getValue($data, $propertyMetadatum->name);
95 24
                        if (!array_key_exists($propertyMetadatum->getType(), Type::getTypesMap())) {
96 10
                            $normalizedData[$propertyMetadatum->name] = $this->normalize(
97
                                $value,
98
                                $includes,
99 10
                                $depth + 1,
100 10
                                $this->appendPath($path, $propertyMetadatum->name)
101
                            );
102
                        } else {
103 24
                            $normalizedData[$propertyMetadatum->name] = $this->normalizeField(
104
                                $value,
105
                                $propertyMetadatum
106
                            );
107
                        }
108
                    }
109
                }
110
            }
111
112 24
            return $normalizedData;
113
        }
114
115
        return null;
116
    }
117
118 18
    private function isIncluded($currentPath, array $paths, ?array $includes): bool
119
    {
120 18
        if (null === $includes) {
121
            return false;
122
        }
123
124 18
        foreach ($paths as $path) {
125 18
            if (in_array($this->appendPath($currentPath, $path), $includes)) {
126 18
                return true;
127
            }
128
        }
129
130 18
        return false;
131
    }
132
133 18
    private function appendPath($path, $name)
134
    {
135 18
        if (null === $path || '' === $path) {
136 18
            return $name;
137
        }
138
139 4
        return $path . '.' . $name;
140
    }
141
142 24
    private function normalizeField($value, PropertyMetadata $propertyMetadata)
143
    {
144 24
        switch ($propertyMetadata->getType()) {
145 24
            case 'datetime':
146 10
                if (null === $value) {
147 4
                    return null;
148
                }
149
150
                /** @var $value \DateTime */
151 8
                return $value->format('Y-m-d H:i:s');
152
153 24
            case 'date':
154 10
                if (null === $value) {
155 4
                    return null;
156
                }
157
158
                /** @var $value \DateTime */
159 8
                return $value->format('Y-m-d');
160
161 24
            case 'time':
162 10
                if (null === $value) {
163 4
                    return null;
164
                }
165
166
                /** @var $value \DateTime */
167 8
                return $value->format('H:i:s');
168
169
            default:
170 24
                return $value;
171
        }
172
    }
173
}
174