MetadataAwareNormalizer::normalizeMethod()   C
last analyzed

Complexity

Conditions 7
Paths 32

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 17.1096

Importance

Changes 5
Bugs 1 Features 0
Metric Value
c 5
b 1
f 0
dl 0
loc 33
ccs 9
cts 22
cp 0.4091
rs 6.7272
cc 7
eloc 19
nc 32
nop 5
crap 17.1096
1
<?php
2
3
namespace Happyr\SerializerBundle\Normalizer;
4
5
use Happyr\SerializerBundle\Annotation\ExclusionPolicy;
6
use Happyr\SerializerBundle\Metadata\Metadata;
7
use Happyr\SerializerBundle\PropertyManager\AttributeExtractor;
8
use Happyr\SerializerBundle\PropertyManager\ReflectionPropertyAccess;
9
use Happyr\SerializerBundle\PropertyManager\PropertyNameConverter;
10
use Symfony\Component\Serializer\Exception\LogicException;
11
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
12
use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer;
13
14
/**
15
 * @author Tobias Nyholm <[email protected]>
16
 */
17
class MetadataAwareNormalizer extends SerializerAwareNormalizer implements NormalizerInterface
18
{
19
    use GroupValidationTrait;
20
21
    /**
22
     * @var array
23
     */
24
    private $metadata;
25
26
    /**
27
     * @var AttributeExtractor
28
     */
29
    private $attributeExtractor;
30
31
    /**
32
     * @var PropertyNameConverter
33
     */
34
    private $propertyNameConverter;
35
36
    /**
37
     * @param array                 $metadata
38
     * @param AttributeExtractor    $attributeExtractor
39
     * @param PropertyNameConverter $pnc
40
     */
41 23
    public function __construct(array $metadata, AttributeExtractor $attributeExtractor, PropertyNameConverter $pnc)
42
    {
43 23
        $this->metadata = $metadata;
44 23
        $this->attributeExtractor = $attributeExtractor;
45 23
        $this->propertyNameConverter = $pnc;
46 23
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51 11
    public function normalize($object, $format = null, array $context = [])
52
    {
53 11
        $meta = $this->getMetadata($object);
54 11
        $attributes = $this->attributeExtractor->getAttributes($object);
55
56 11
        $normalizedData = [];
57 11
        foreach ($attributes['property'] as $propertyName => $bool) {
0 ignored issues
show
Bug introduced by
The expression $attributes['property'] of type string is not traversable.
Loading history...
58 11
            $this->normalizeProperty($normalizedData, $meta, $object, $propertyName, $context);
59 11
        }
60 11
        foreach ($attributes['method'] as $propertyName => $bool) {
0 ignored issues
show
Bug introduced by
The expression $attributes['method'] of type string is not traversable.
Loading history...
61 2
            $this->normalizeMethod($normalizedData, $meta, $object, $propertyName, $context);
62 11
        }
63
64 11
        foreach ($normalizedData as $name => $value) {
65 11
            if (null !== $value && !is_scalar($value)) {
66 1
                if (!$this->serializer instanceof NormalizerInterface) {
67
                    throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $name));
68
                }
69
70 1
                $normalizedData[$name] = $this->serializer->normalize($value, $format, $context);
71 1
            }
72 11
        }
73
74 11
        return $normalizedData;
75
    }
76
77
    /**
78
     * Normalize a property.
79
     *
80
     * @param array $normalizedData
81
     * @param array $meta
82
     * @param $object
83
     * @param $propertyName
84
     * @param array $context
85
     */
86 11
    protected function normalizeProperty(array &$normalizedData, array $meta, $object, $propertyName, array $context)
87
    {
88 11
        if (!isset($meta['property'][$propertyName])) {
89
            $meta['property'][$propertyName] = [];
90
        }
91
92
        // Default exclusion policy is NONE
93 11
        $exclusionPolicy = isset($meta['class']['exclusion_policy']) ? $meta['class']['exclusion_policy'] : ExclusionPolicy::NONE;
94
95
        // If this property should be in the output
96 11
        $included = $exclusionPolicy === ExclusionPolicy::NONE;
97
98 11
        $groups = ['Default'];
99 11
        $value = ReflectionPropertyAccess::get($object, $propertyName);
100 11
        foreach ($meta['property'][$propertyName] as $name => $metaValue) {
101
            switch ($name) {
102 11
                case 'exclude':
103
                    // Skip this
104 4
                    return;
105 10
                case 'expose':
106 4
                    $included = true;
107 4
                    break;
108 6
                case 'accessor':
109 1
                    if (!empty($metaValue['getter'])) {
110 1
                        $accessor = $metaValue['getter'];
111 1
                        $value = $object->$accessor();
112 1
                    }
113 1
                    break;
114 5
                case 'groups':
115 1
                    $groups = $metaValue;
116 1
                    break;
117
            }
118 11
        }
119
120
        // Validate context groups
121 11
        if (!empty($context['groups'])) {
122 1
            $included = $this->includeBasedOnGroup($context, $groups);
123 1
        }
124
125 11
        if (!$included) {
126 3
            return;
127
        }
128
129 11
        $serializedName = $this->propertyNameConverter->getSerializedName($meta['property'][$propertyName], $propertyName);
130 11
        $normalizedData[$serializedName] = $value;
131 11
    }
132
133
    /**
134
     * Normalize a method.
135
     *
136
     * @param array $normalizedData
137
     * @param array $meta
138
     * @param $object
139
     * @param $methodName
140
     * @param array $context
141
     */
142 2
    protected function normalizeMethod(array &$normalizedData, array $meta, $object, $methodName, array $context)
143
    {
144 2
        if (!isset($meta['method'][$methodName])) {
145
            $meta['method'][$methodName] = [];
146
        }
147
148
        // Methods are never serialized by default
149 2
        $included = false;
150
151 2
        $groups = ['Default'];
152 2
        foreach ($meta['method'][$methodName] as $name => $metaValue) {
153
            switch ($name) {
154
                case 'expose':
155
                    $included = true;
156
                    break;
157
                case 'groups':
158
                    $groups = $metaValue;
159
                    break;
160
            }
161 2
        }
162
163
        // Validate context groups
164 2
        if (!empty($context['groups'])) {
165
            $included = $this->includeBasedOnGroup($context, $groups);
166
        }
167
168 2
        if (!$included) {
169 2
            return;
170
        }
171
172
        $serializedName = $this->propertyNameConverter->getSerializedName($meta['method'][$methodName], $methodName);
173
        $normalizedData[$serializedName] = $object->$methodName();
174
    }
175
176
    /**
177
     * @param mixed $data
178
     * @param null  $format
179
     *
180
     * @return bool
181
     */
182 11
    public function supportsNormalization($data, $format = null)
183
    {
184 11
        if (!is_object($data)) {
185 1
            return false;
186
        }
187
188 11
        $class = get_class($data);
189
190 11
        return isset($this->metadata[$class]);
191
    }
192
193
    /**
194
     * @param object $object
195
     *
196
     * @return array
197
     */
198 11
    private function getMetadata($object)
199
    {
200 11
        $class = get_class($object);
201
202 11
        return $this->metadata[$class];
203
    }
204
}
205