/src/Symfony/Component/Serializer/Serializer.php

https://github.com/Faianca/symfony · PHP · 252 lines · 151 code · 31 blank · 70 comment · 17 complexity · 40f2bca0c780b8fe1e3779bd86957b6d MD5 · raw file

  1. <?php
  2. namespace Symfony\Component\Serializer;
  3. use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
  4. use Symfony\Component\Serializer\Encoder\EncoderInterface;
  5. use Symfony\Component\Serializer\Encoder\DecoderInterface;
  6. use Symfony\Component\Serializer\Encoder\NormalizationAwareInterface;
  7. use Symfony\Component\Serializer\Exception\RuntimeException;
  8. use Symfony\Component\Serializer\Exception\LogicException;
  9. use Symfony\Component\Serializer\Exception\UnexpectedValueException;
  10. /*
  11. * This file is part of the Symfony framework.
  12. *
  13. * (c) Fabien Potencier <fabien@symfony.com>
  14. *
  15. * This source file is subject to the MIT license that is bundled
  16. * with this source code in the file LICENSE.
  17. */
  18. /**
  19. * Serializer serializes and deserializes data
  20. *
  21. * objects are turned into arrays by normalizers
  22. * arrays are turned into various output formats by encoders
  23. *
  24. * $serializer->serialize($obj, 'xml')
  25. * $serializer->decode($data, 'xml')
  26. * $serializer->denormalize($data, 'Class', 'xml')
  27. *
  28. * @author Jordi Boggiano <j.boggiano@seld.be>
  29. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  30. * @author Lukas Kahwe Smith <smith@pooteeweet.org>
  31. */
  32. class Serializer implements SerializerInterface
  33. {
  34. protected $normalizers = array();
  35. protected $encoders = array();
  36. protected $normalizerCache = array();
  37. protected $denormalizerCache = array();
  38. public function __construct(array $normalizers = array(), array $encoders = array())
  39. {
  40. foreach ($normalizers as $normalizer) {
  41. if ($normalizer instanceof SerializerAwareInterface) {
  42. $normalizer->setSerializer($this);
  43. }
  44. }
  45. $this->normalizers = $normalizers;
  46. foreach ($encoders as $encoder) {
  47. if ($encoder instanceof SerializerAwareInterface) {
  48. $encoder->setSerializer($this);
  49. }
  50. }
  51. $this->encoders = $encoders;
  52. }
  53. /**
  54. * {@inheritdoc}
  55. */
  56. public final function serialize($data, $format)
  57. {
  58. if (!$this->supportsSerialization($format)) {
  59. throw new UnexpectedValueException('Serialization for the format '.$format.' is not supported');
  60. }
  61. $encoder = $this->getEncoder($format);
  62. if (!$encoder instanceof NormalizationAwareInterface) {
  63. $data = $this->normalize($data, $format);
  64. }
  65. return $this->encode($data, $format);
  66. }
  67. /**
  68. * {@inheritdoc}
  69. */
  70. public final function deserialize($data, $type, $format)
  71. {
  72. if (!$this->supportsDeserialization($format)) {
  73. throw new UnexpectedValueException('Deserialization for the format '.$format.' is not supported');
  74. }
  75. $data = $this->decode($data, $format);
  76. return $this->denormalize($data, $type, $format);
  77. }
  78. /**
  79. * {@inheritdoc}
  80. */
  81. public function normalize($data, $format = null)
  82. {
  83. if (null === $data || is_scalar($data)) {
  84. return $data;
  85. }
  86. if ($data instanceof \Traversable) {
  87. $normalized = array();
  88. foreach ($data as $key => $val) {
  89. $normalized[$key] = $this->normalize($val, $format);
  90. }
  91. return $normalized;
  92. }
  93. if (is_object($data)) {
  94. return $this->normalizeObject($data, $format);
  95. }
  96. if (is_array($data)) {
  97. foreach ($data as $key => $val) {
  98. $data[$key] = $this->normalize($val, $format);
  99. }
  100. return $data;
  101. }
  102. throw new UnexpectedValueException('An unexpected value could not be normalized: '.var_export($data, true));
  103. }
  104. /**
  105. * {@inheritdoc}
  106. */
  107. public function denormalize($data, $type, $format = null)
  108. {
  109. return $this->denormalizeObject($data, $type, $format);
  110. }
  111. /**
  112. * {@inheritdoc}
  113. */
  114. public final function encode($data, $format)
  115. {
  116. return $this->getEncoder($format)->encode($data, $format);
  117. }
  118. /**
  119. * {@inheritdoc}
  120. */
  121. public final function decode($data, $format)
  122. {
  123. return $this->getEncoder($format)->decode($data, $format);
  124. }
  125. /**
  126. * Normalizes an object into a set of arrays/scalars
  127. *
  128. * @param object $object object to normalize
  129. * @param string $format format name, present to give the option to normalizers to act differently based on formats
  130. * @return array|scalar
  131. */
  132. private function normalizeObject($object, $format = null)
  133. {
  134. if (!$this->normalizers) {
  135. throw new LogicException('You must register at least one normalizer to be able to normalize objects.');
  136. }
  137. $class = get_class($object);
  138. if (isset($this->normalizerCache[$class][$format])) {
  139. return $this->normalizerCache[$class][$format]->normalize($object, $format);
  140. }
  141. foreach ($this->normalizers as $normalizer) {
  142. if ($normalizer->supportsNormalization($object, $class, $format)) {
  143. $this->normalizerCache[$class][$format] = $normalizer;
  144. return $normalizer->normalize($object, $format);
  145. }
  146. }
  147. throw new UnexpectedValueException('Could not normalize object of type '.$class.', no supporting normalizer found.');
  148. }
  149. /**
  150. * Denormalizes data back into an object of the given class
  151. *
  152. * @param mixed $data data to restore
  153. * @param string $class the expected class to instantiate
  154. * @param string $format format name, present to give the option to normalizers to act differently based on formats
  155. * @return object
  156. */
  157. private function denormalizeObject($data, $class, $format = null)
  158. {
  159. if (!$this->normalizers) {
  160. throw new LogicException('You must register at least one normalizer to be able to denormalize objects.');
  161. }
  162. if (isset($this->denormalizerCache[$class][$format])) {
  163. return $this->denormalizerCache[$class][$format]->denormalize($data, $class, $format);
  164. }
  165. foreach ($this->normalizers as $normalizer) {
  166. if ($normalizer->supportsDenormalization($data, $class, $format)) {
  167. $this->denormalizerCache[$class][$format] = $normalizer;
  168. return $normalizer->denormalize($data, $class, $format);
  169. }
  170. }
  171. throw new UnexpectedValueException('Could not denormalize object of type '.$class.', no supporting normalizer found.');
  172. }
  173. /**
  174. * {@inheritdoc}
  175. */
  176. public function supportsSerialization($format)
  177. {
  178. return $this->supportsEncoding($format);
  179. }
  180. /**
  181. * {@inheritdoc}
  182. */
  183. public function supportsDeserialization($format)
  184. {
  185. return $this->supportsDecoding($format);
  186. }
  187. /**
  188. * {@inheritdoc}
  189. */
  190. public function supportsEncoding($format)
  191. {
  192. try {
  193. $encoder = $this->getEncoder($format);
  194. } catch (\RuntimeException $e) {
  195. return false;
  196. }
  197. return $encoder instanceof EncoderInterface;
  198. }
  199. /**
  200. * {@inheritdoc}
  201. */
  202. public function supportsDecoding($format)
  203. {
  204. try {
  205. $encoder = $this->getEncoder($format);
  206. } catch (\RuntimeException $e) {
  207. return false;
  208. }
  209. return $encoder instanceof DecoderInterface;
  210. }
  211. /**
  212. * {@inheritdoc}
  213. */
  214. public function getEncoder($format)
  215. {
  216. if (!isset($this->encoders[$format])) {
  217. throw new RuntimeException(sprintf('No encoder found for format "%s".', $format));
  218. }
  219. return $this->encoders[$format];
  220. }
  221. }