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

Normalizer::normalize()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 78
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 13.0056

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 78
ccs 30
cts 31
cp 0.9677
rs 5.1663
cc 13
eloc 43
nc 11
nop 4
crap 13.0056

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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