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 Metadata[] |
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
|
|
|
public function __construct(array $metadata, AttributeExtractor $attributeExtractor, PropertyNameConverter $pnc) |
42
|
|
|
{ |
43
|
|
|
$this->metadata = $metadata; |
44
|
|
|
$this->attributeExtractor = $attributeExtractor; |
45
|
|
|
$this->propertyNameConverter = $pnc; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
public function normalize($object, $format = null, array $context = array()) |
49
|
|
|
{ |
50
|
|
|
$meta = $this->getMetadata($object); |
51
|
|
|
$attributes = $this->attributeExtractor->getAttributes($object); |
52
|
|
|
|
53
|
|
|
$normalizedData = []; |
54
|
|
|
foreach ($attributes['property'] as $propertyName => $bool) { |
|
|
|
|
55
|
|
|
$this->normalizeProperty($normalizedData, $meta, $object, $propertyName, $context); |
|
|
|
|
56
|
|
|
} |
57
|
|
|
foreach ($attributes['method'] as $propertyName => $bool) { |
|
|
|
|
58
|
|
|
$this->normalizeMethod($normalizedData, $meta, $object, $propertyName, $context); |
|
|
|
|
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
foreach ($normalizedData as $name => $value) { |
62
|
|
|
if (null !== $value && !is_scalar($value)) { |
63
|
|
|
if (!$this->serializer instanceof NormalizerInterface) { |
64
|
|
|
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $name)); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
$normalizedData[$name] = $this->serializer->normalize($value, $format, $context); |
68
|
|
|
} |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
return $normalizedData; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
protected function normalizeProperty(array &$normalizedData, array $meta, $object, $propertyName, array $context) |
75
|
|
|
{ |
76
|
|
|
if (!isset($meta['property'][$propertyName])) { |
77
|
|
|
$meta['property'][$propertyName] = []; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
// Default exclusion policy is NONE |
81
|
|
|
$exclusionPolicy = isset($meta['class']['exclusion_policy']) ? $meta['class']['exclusion_policy'] : ExclusionPolicy::NONE; |
82
|
|
|
|
83
|
|
|
// If this property should be in the output |
84
|
|
|
$included = $exclusionPolicy === ExclusionPolicy::NONE; |
85
|
|
|
|
86
|
|
|
$groups = ['Default']; |
87
|
|
|
$value = ReflectionPropertyAccess::get($object, $propertyName); |
88
|
|
|
foreach ($meta['property'][$propertyName] as $name => $metaValue) { |
89
|
|
|
switch ($name) { |
90
|
|
|
case 'exclude'; |
|
|
|
|
91
|
|
|
// Skip this |
92
|
|
|
return; |
93
|
|
|
case 'expose': |
94
|
|
|
$included = true; |
95
|
|
|
break; |
96
|
|
|
case 'accessor': |
97
|
|
|
if (!empty($metaValue['getter'])) { |
98
|
|
|
$accessor = $metaValue['getter']; |
99
|
|
|
$value = $object->$accessor(); |
100
|
|
|
} |
101
|
|
|
break; |
102
|
|
|
case 'groups': |
103
|
|
|
$groups = $metaValue; |
104
|
|
|
break; |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
// Validate context groups |
109
|
|
|
if (!empty($context['groups'])) { |
110
|
|
|
$included = $this->includeBasedOnGroup($context, $groups); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
if (!$included) { |
114
|
|
|
return; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
$serializedName = $this->propertyNameConverter->getSerializedName($meta['property'][$propertyName], $propertyName); |
118
|
|
|
$normalizedData[$serializedName] = $value; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
protected function normalizeMethod(array &$normalizedData, array $meta, $object, $methodName, array $context) |
122
|
|
|
{ |
123
|
|
|
if (!isset($meta['method'][$methodName])) { |
124
|
|
|
$meta['method'][$methodName] = []; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
// Methods are never serialized by default |
128
|
|
|
$included = false; |
129
|
|
|
|
130
|
|
|
$groups = ['Default']; |
131
|
|
|
foreach ($meta['method'][$methodName] as $name => $metaValue) { |
132
|
|
|
switch ($name) { |
133
|
|
|
case 'expose': |
134
|
|
|
$included = true; |
135
|
|
|
break; |
136
|
|
|
case 'serialized_name': |
137
|
|
|
$serializedName = $metaValue; |
|
|
|
|
138
|
|
|
break; |
139
|
|
|
case 'groups': |
140
|
|
|
$groups = $metaValue; |
141
|
|
|
break; |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
// Validate context groups |
146
|
|
|
if (!empty($context['groups'])) { |
147
|
|
|
$included = $this->includeBasedOnGroup($context, $groups); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
if (!$included) { |
151
|
|
|
return; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
$serializedName = $this->propertyNameConverter->getSerializedName($meta['method'][$methodName], $methodName); |
155
|
|
|
$normalizedData[$serializedName] = $object->$methodName(); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @param mixed $data |
160
|
|
|
* @param null $format |
161
|
|
|
* |
162
|
|
|
* @return bool |
163
|
|
|
*/ |
164
|
|
|
public function supportsNormalization($data, $format = null) |
165
|
|
|
{ |
166
|
|
|
$class = get_class($data); |
167
|
|
|
|
168
|
|
|
return isset($this->metadata[$class]); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* @param $object |
173
|
|
|
*/ |
174
|
|
|
private function getMetadata($object) |
175
|
|
|
{ |
176
|
|
|
$class = get_class($object); |
177
|
|
|
|
178
|
|
|
return $this->metadata[$class]; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.