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

Normalizer   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 55.56%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 7
dl 0
loc 161
ccs 60
cts 108
cp 0.5556
rs 10
c 0
b 0
f 0

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