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

Normalizer::normalize()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 78
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 34.125

Importance

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

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 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