72c5721c89928e7b304f2c51dda34558238912c3
[yaffs-website] / vendor / symfony / serializer / Serializer.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
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;
13
14 use Symfony\Component\Serializer\Encoder\ChainDecoder;
15 use Symfony\Component\Serializer\Encoder\ChainEncoder;
16 use Symfony\Component\Serializer\Encoder\DecoderInterface;
17 use Symfony\Component\Serializer\Encoder\EncoderInterface;
18 use Symfony\Component\Serializer\Exception\LogicException;
19 use Symfony\Component\Serializer\Exception\NotEncodableValueException;
20 use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
21 use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
22 use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
23 use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
24 use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
25
26 /**
27  * Serializer serializes and deserializes data.
28  *
29  * objects are turned into arrays by normalizers.
30  * arrays are turned into various output formats by encoders.
31  *
32  *     $serializer->serialize($obj, 'xml')
33  *     $serializer->decode($data, 'xml')
34  *     $serializer->denormalize($data, 'Class', 'xml')
35  *
36  * @author Jordi Boggiano <j.boggiano@seld.be>
37  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
38  * @author Lukas Kahwe Smith <smith@pooteeweet.org>
39  * @author Kévin Dunglas <dunglas@gmail.com>
40  */
41 class Serializer implements SerializerInterface, NormalizerInterface, DenormalizerInterface, EncoderInterface, DecoderInterface
42 {
43     /**
44      * @var Encoder\ChainEncoder
45      */
46     protected $encoder;
47
48     /**
49      * @var Encoder\ChainDecoder
50      */
51     protected $decoder;
52
53     /**
54      * @var array
55      */
56     protected $normalizers = array();
57
58     /**
59      * @var array
60      *
61      * @deprecated since 3.1 will be removed in 4.0
62      */
63     protected $normalizerCache = array();
64
65     /**
66      * @var array
67      *
68      * @deprecated since 3.1 will be removed in 4.0
69      */
70     protected $denormalizerCache = array();
71
72     public function __construct(array $normalizers = array(), array $encoders = array())
73     {
74         foreach ($normalizers as $normalizer) {
75             if ($normalizer instanceof SerializerAwareInterface) {
76                 $normalizer->setSerializer($this);
77             }
78
79             if ($normalizer instanceof DenormalizerAwareInterface) {
80                 $normalizer->setDenormalizer($this);
81             }
82
83             if ($normalizer instanceof NormalizerAwareInterface) {
84                 $normalizer->setNormalizer($this);
85             }
86         }
87         $this->normalizers = $normalizers;
88
89         $decoders = array();
90         $realEncoders = array();
91         foreach ($encoders as $encoder) {
92             if ($encoder instanceof SerializerAwareInterface) {
93                 $encoder->setSerializer($this);
94             }
95             if ($encoder instanceof DecoderInterface) {
96                 $decoders[] = $encoder;
97             }
98             if ($encoder instanceof EncoderInterface) {
99                 $realEncoders[] = $encoder;
100             }
101         }
102         $this->encoder = new ChainEncoder($realEncoders);
103         $this->decoder = new ChainDecoder($decoders);
104     }
105
106     /**
107      * {@inheritdoc}
108      */
109     final public function serialize($data, $format, array $context = array())
110     {
111         if (!$this->supportsEncoding($format, $context)) {
112             throw new NotEncodableValueException(sprintf('Serialization for the format %s is not supported', $format));
113         }
114
115         if ($this->encoder->needsNormalization($format, $context)) {
116             $data = $this->normalize($data, $format, $context);
117         }
118
119         return $this->encode($data, $format, $context);
120     }
121
122     /**
123      * {@inheritdoc}
124      */
125     final public function deserialize($data, $type, $format, array $context = array())
126     {
127         if (!$this->supportsDecoding($format, $context)) {
128             throw new NotEncodableValueException(sprintf('Deserialization for the format %s is not supported', $format));
129         }
130
131         $data = $this->decode($data, $format, $context);
132
133         return $this->denormalize($data, $type, $format, $context);
134     }
135
136     /**
137      * {@inheritdoc}
138      */
139     public function normalize($data, $format = null, array $context = array())
140     {
141         // If a normalizer supports the given data, use it
142         if ($normalizer = $this->getNormalizer($data, $format, $context)) {
143             return $normalizer->normalize($data, $format, $context);
144         }
145
146         if (null === $data || is_scalar($data)) {
147             return $data;
148         }
149
150         if (\is_array($data) || $data instanceof \Traversable) {
151             $normalized = array();
152             foreach ($data as $key => $val) {
153                 $normalized[$key] = $this->normalize($val, $format, $context);
154             }
155
156             return $normalized;
157         }
158
159         if (\is_object($data)) {
160             if (!$this->normalizers) {
161                 throw new LogicException('You must register at least one normalizer to be able to normalize objects.');
162             }
163
164             throw new NotNormalizableValueException(sprintf('Could not normalize object of type %s, no supporting normalizer found.', \get_class($data)));
165         }
166
167         throw new NotNormalizableValueException(sprintf('An unexpected value could not be normalized: %s', var_export($data, true)));
168     }
169
170     /**
171      * {@inheritdoc}
172      *
173      * @throws NotNormalizableValueException
174      */
175     public function denormalize($data, $type, $format = null, array $context = array())
176     {
177         if (!$this->normalizers) {
178             throw new LogicException('You must register at least one normalizer to be able to denormalize objects.');
179         }
180
181         if ($normalizer = $this->getDenormalizer($data, $type, $format, $context)) {
182             return $normalizer->denormalize($data, $type, $format, $context);
183         }
184
185         throw new NotNormalizableValueException(sprintf('Could not denormalize object of type %s, no supporting normalizer found.', $type));
186     }
187
188     /**
189      * {@inheritdoc}
190      */
191     public function supportsNormalization($data, $format = null/*, array $context = array()*/)
192     {
193         if (\func_num_args() > 2) {
194             $context = \func_get_arg(2);
195         } else {
196             if (__CLASS__ !== \get_class($this)) {
197                 $r = new \ReflectionMethod($this, __FUNCTION__);
198                 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
199                     @trigger_error(sprintf('The "%s()" method will have a third `$context = array()` argument in version 4.0. Not defining it is deprecated since Symfony 3.3.', __METHOD__), E_USER_DEPRECATED);
200                 }
201             }
202
203             $context = array();
204         }
205
206         return null !== $this->getNormalizer($data, $format, $context);
207     }
208
209     /**
210      * {@inheritdoc}
211      */
212     public function supportsDenormalization($data, $type, $format = null/*, array $context = array()*/)
213     {
214         if (\func_num_args() > 3) {
215             $context = \func_get_arg(3);
216         } else {
217             if (__CLASS__ !== \get_class($this)) {
218                 $r = new \ReflectionMethod($this, __FUNCTION__);
219                 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
220                     @trigger_error(sprintf('The "%s()" method will have a fourth `$context = array()` argument in version 4.0. Not defining it is deprecated since Symfony 3.3.', __METHOD__), E_USER_DEPRECATED);
221                 }
222             }
223
224             $context = array();
225         }
226
227         return null !== $this->getDenormalizer($data, $type, $format, $context);
228     }
229
230     /**
231      * Returns a matching normalizer.
232      *
233      * @param mixed  $data    Data to get the serializer for
234      * @param string $format  Format name, present to give the option to normalizers to act differently based on formats
235      * @param array  $context Options available to the normalizer
236      *
237      * @return NormalizerInterface|null
238      */
239     private function getNormalizer($data, $format, array $context)
240     {
241         foreach ($this->normalizers as $normalizer) {
242             if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($data, $format, $context)) {
243                 return $normalizer;
244             }
245         }
246     }
247
248     /**
249      * Returns a matching denormalizer.
250      *
251      * @param mixed  $data    Data to restore
252      * @param string $class   The expected class to instantiate
253      * @param string $format  Format name, present to give the option to normalizers to act differently based on formats
254      * @param array  $context Options available to the denormalizer
255      *
256      * @return DenormalizerInterface|null
257      */
258     private function getDenormalizer($data, $class, $format, array $context)
259     {
260         foreach ($this->normalizers as $normalizer) {
261             if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format, $context)) {
262                 return $normalizer;
263             }
264         }
265     }
266
267     /**
268      * {@inheritdoc}
269      */
270     final public function encode($data, $format, array $context = array())
271     {
272         return $this->encoder->encode($data, $format, $context);
273     }
274
275     /**
276      * {@inheritdoc}
277      */
278     final public function decode($data, $format, array $context = array())
279     {
280         return $this->decoder->decode($data, $format, $context);
281     }
282
283     /**
284      * {@inheritdoc}
285      */
286     public function supportsEncoding($format/*, array $context = array()*/)
287     {
288         if (\func_num_args() > 1) {
289             $context = \func_get_arg(1);
290         } else {
291             if (__CLASS__ !== \get_class($this)) {
292                 $r = new \ReflectionMethod($this, __FUNCTION__);
293                 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
294                     @trigger_error(sprintf('The "%s()" method will have a second `$context = array()` argument in version 4.0. Not defining it is deprecated since Symfony 3.3.', __METHOD__), E_USER_DEPRECATED);
295                 }
296             }
297
298             $context = array();
299         }
300
301         return $this->encoder->supportsEncoding($format, $context);
302     }
303
304     /**
305      * {@inheritdoc}
306      */
307     public function supportsDecoding($format/*, array $context = array()*/)
308     {
309         if (\func_num_args() > 1) {
310             $context = \func_get_arg(1);
311         } else {
312             if (__CLASS__ !== \get_class($this)) {
313                 $r = new \ReflectionMethod($this, __FUNCTION__);
314                 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
315                     @trigger_error(sprintf('The "%s()" method will have a second `$context = array()` argument in version 4.0. Not defining it is deprecated since Symfony 3.3.', __METHOD__), E_USER_DEPRECATED);
316                 }
317             }
318
319             $context = array();
320         }
321
322         return $this->decoder->supportsDecoding($format, $context);
323     }
324 }