Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3bec813

Browse files
dunglasfabpot
authored andcommitted
[Serializer] Move the normalization logic in an abstract class
1 parent 5c16f40 commit 3bec813

File tree

5 files changed

+353
-266
lines changed

5 files changed

+353
-266
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php

+22-2
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,34 @@ protected function getAllowedAttributes($classOrObject, array $context, $attribu
199199

200200
$allowedAttributes = array();
201201
foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
202-
if (count(array_intersect($attributeMetadata->getGroups(), $context['groups']))) {
203-
$allowedAttributes[] = $attributesAsString ? $attributeMetadata->getName() : $attributeMetadata;
202+
$name = $attributeMetadata->getName();
203+
204+
if (
205+
count(array_intersect($attributeMetadata->getGroups(), $context['groups'])) &&
206+
$this->isAllowedAttribute($classOrObject, $name, null, $context)
207+
) {
208+
$allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata;
204209
}
205210
}
206211

207212
return $allowedAttributes;
208213
}
209214

215+
/**
216+
* Is this attribute allowed?
217+
*
218+
* @param object|string $classOrObject
219+
* @param string $attribute
220+
* @param string|null $format
221+
* @param array $context
222+
*
223+
* @return bool
224+
*/
225+
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
226+
{
227+
return !in_array($attribute, $this->ignoredAttributes);
228+
}
229+
210230
/**
211231
* Normalizes the given data to an array. It's particularly useful during
212232
* the denormalization process.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Normalizer;
13+
14+
use Symfony\Component\Serializer\Exception\CircularReferenceException;
15+
use Symfony\Component\Serializer\Exception\LogicException;
16+
17+
/**
18+
* Base class for a normalizer dealing with objects.
19+
*
20+
* @author Kévin Dunglas <[email protected]>
21+
*/
22+
abstract class AbstractObjectNormalizer extends AbstractNormalizer
23+
{
24+
private $attributesCache = array();
25+
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function supportsNormalization($data, $format = null)
30+
{
31+
return is_object($data) && !$data instanceof \Traversable;
32+
}
33+
34+
/**
35+
* {@inheritdoc}
36+
*
37+
* @throws CircularReferenceException
38+
*/
39+
public function normalize($object, $format = null, array $context = array())
40+
{
41+
if ($this->isCircularReference($object, $context)) {
42+
return $this->handleCircularReference($object);
43+
}
44+
45+
$data = array();
46+
$attributes = $this->getAttributes($object, $format, $context);
47+
48+
foreach ($attributes as $attribute) {
49+
$attributeValue = $this->getAttributeValue($object, $attribute, $format, $context);
50+
51+
if (isset($this->callbacks[$attribute])) {
52+
$attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
53+
}
54+
55+
if (null !== $attributeValue && !is_scalar($attributeValue)) {
56+
if (!$this->serializer instanceof NormalizerInterface) {
57+
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attribute));
58+
}
59+
60+
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
61+
}
62+
63+
if ($this->nameConverter) {
64+
$attribute = $this->nameConverter->normalize($attribute);
65+
}
66+
67+
$data[$attribute] = $attributeValue;
68+
}
69+
70+
return $data;
71+
}
72+
73+
/**
74+
* Gets and caches attributes for the given object, format and context.
75+
*
76+
* @param object $object
77+
* @param string|null $format
78+
* @param array $context
79+
*
80+
* @return string[]
81+
*/
82+
protected function getAttributes($object, $format = null, array $context)
83+
{
84+
$key = sprintf('%s-%s', get_class($object), serialize($context));
85+
86+
if (isset($this->attributesCache[$key])) {
87+
return $this->attributesCache[$key];
88+
}
89+
90+
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
91+
92+
if (false !== $allowedAttributes) {
93+
return $this->attributesCache[$key] = $allowedAttributes;
94+
}
95+
96+
return $this->attributesCache[$key] = $this->extractAttributes($object, $format, $context);
97+
}
98+
99+
/**
100+
* Extracts attributes to normalize from the class of the given object, format and context.
101+
*
102+
* @param object $object
103+
* @param string|null $format
104+
* @param array $context
105+
*
106+
* @return string[]
107+
*/
108+
abstract protected function extractAttributes($object, $format = null, array $context = array());
109+
110+
/**
111+
* Gets the attribute value.
112+
*
113+
* @param object $object
114+
* @param string $attribute
115+
* @param string|null $format
116+
* @param array $context
117+
*
118+
* @return mixed
119+
*/
120+
abstract protected function getAttributeValue($object, $attribute, $format = null, array $context = array());
121+
122+
/**
123+
* {@inheritdoc}
124+
*/
125+
public function supportsDenormalization($data, $type, $format = null)
126+
{
127+
return class_exists($type);
128+
}
129+
130+
/**
131+
* {@inheritdoc}
132+
*/
133+
public function denormalize($data, $class, $format = null, array $context = array())
134+
{
135+
$allowedAttributes = $this->getAllowedAttributes($class, $context, true);
136+
$normalizedData = $this->prepareForDenormalization($data);
137+
138+
$reflectionClass = new \ReflectionClass($class);
139+
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes);
140+
141+
foreach ($normalizedData as $attribute => $value) {
142+
if ($this->nameConverter) {
143+
$attribute = $this->nameConverter->denormalize($attribute);
144+
}
145+
146+
$allowed = $allowedAttributes === false || in_array($attribute, $allowedAttributes);
147+
$ignored = in_array($attribute, $this->ignoredAttributes);
148+
149+
if ($allowed && !$ignored) {
150+
$this->setAttributeValue($object, $attribute, $value, $format, $context);
151+
}
152+
}
153+
154+
return $object;
155+
}
156+
157+
/**
158+
* Sets attribute value.
159+
*
160+
* @param object $object
161+
* @param string $attribute
162+
* @param mixed $value
163+
* @param string|null $format
164+
* @param array $context
165+
*/
166+
abstract protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array());
167+
}

src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php

+57-56
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\Component\Serializer\Normalizer;
1313

14-
use Symfony\Component\Serializer\Exception\CircularReferenceException;
15-
use Symfony\Component\Serializer\Exception\LogicException;
1614
use Symfony\Component\Serializer\Exception\RuntimeException;
1715

1816
/**
@@ -36,59 +34,8 @@
3634
* @author Nils Adermann <[email protected]>
3735
* @author Kévin Dunglas <[email protected]>
3836
*/
39-
class GetSetMethodNormalizer extends AbstractNormalizer
37+
class GetSetMethodNormalizer extends AbstractObjectNormalizer
4038
{
41-
/**
42-
* {@inheritdoc}
43-
*
44-
* @throws LogicException
45-
* @throws CircularReferenceException
46-
*/
47-
public function normalize($object, $format = null, array $context = array())
48-
{
49-
if ($this->isCircularReference($object, $context)) {
50-
return $this->handleCircularReference($object);
51-
}
52-
53-
$reflectionObject = new \ReflectionObject($object);
54-
$reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
55-
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
56-
57-
$attributes = array();
58-
foreach ($reflectionMethods as $method) {
59-
if ($this->isGetMethod($method)) {
60-
$attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3));
61-
if (in_array($attributeName, $this->ignoredAttributes)) {
62-
continue;
63-
}
64-
65-
if (false !== $allowedAttributes && !in_array($attributeName, $allowedAttributes)) {
66-
continue;
67-
}
68-
69-
$attributeValue = $method->invoke($object);
70-
if (isset($this->callbacks[$attributeName])) {
71-
$attributeValue = call_user_func($this->callbacks[$attributeName], $attributeValue);
72-
}
73-
if (null !== $attributeValue && !is_scalar($attributeValue)) {
74-
if (!$this->serializer instanceof NormalizerInterface) {
75-
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attributeName));
76-
}
77-
78-
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
79-
}
80-
81-
if ($this->nameConverter) {
82-
$attributeName = $this->nameConverter->normalize($attributeName);
83-
}
84-
85-
$attributes[$attributeName] = $attributeValue;
86-
}
87-
}
88-
89-
return $attributes;
90-
}
91-
9239
/**
9340
* {@inheritdoc}
9441
*
@@ -128,15 +75,15 @@ public function denormalize($data, $class, $format = null, array $context = arra
12875
*/
12976
public function supportsNormalization($data, $format = null)
13077
{
131-
return is_object($data) && !$data instanceof \Traversable && $this->supports(get_class($data));
78+
return parent::supportsNormalization($data, $format) && $this->supports(get_class($data));
13279
}
13380

13481
/**
13582
* {@inheritdoc}
13683
*/
13784
public function supportsDenormalization($data, $type, $format = null)
13885
{
139-
return class_exists($type) && $this->supports($type);
86+
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
14087
}
14188

14289
/**
@@ -179,4 +126,58 @@ private function isGetMethod(\ReflectionMethod $method)
179126
)
180127
;
181128
}
129+
130+
/**
131+
* {@inheritdoc}
132+
*/
133+
protected function extractAttributes($object, $format = null, array $context = array())
134+
{
135+
$reflectionObject = new \ReflectionObject($object);
136+
$reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
137+
138+
$attributes = array();
139+
foreach ($reflectionMethods as $method) {
140+
if (!$this->isGetMethod($method)) {
141+
continue;
142+
}
143+
144+
$attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3));
145+
146+
if ($this->isAllowedAttribute($object, $attributeName)) {
147+
$attributes[] = $attributeName;
148+
}
149+
}
150+
151+
return $attributes;
152+
}
153+
154+
/**
155+
* {@inheritdoc}
156+
*/
157+
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
158+
{
159+
$ucfirsted = ucfirst($attribute);
160+
161+
$getter = 'get'.$ucfirsted;
162+
if (is_callable(array($object, $getter))) {
163+
return $object->$getter();
164+
}
165+
166+
$isser = 'is'.$ucfirsted;
167+
if (is_callable(array($object, $isser))) {
168+
return $object->$isser();
169+
}
170+
}
171+
172+
/**
173+
* {@inheritdoc}
174+
*/
175+
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
176+
{
177+
$setter = 'set'.ucfirst($attribute);
178+
179+
if (is_callable(array($object, $setter))) {
180+
$object->$setter($value);
181+
}
182+
}
182183
}

0 commit comments

Comments
 (0)