vendor/symfony/serializer/Serializer.php line 152

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Serializer;
  11. use Symfony\Component\Serializer\Encoder\ChainDecoder;
  12. use Symfony\Component\Serializer\Encoder\ChainEncoder;
  13. use Symfony\Component\Serializer\Encoder\ContextAwareDecoderInterface;
  14. use Symfony\Component\Serializer\Encoder\ContextAwareEncoderInterface;
  15. use Symfony\Component\Serializer\Encoder\DecoderInterface;
  16. use Symfony\Component\Serializer\Encoder\EncoderInterface;
  17. use Symfony\Component\Serializer\Exception\LogicException;
  18. use Symfony\Component\Serializer\Exception\NotEncodableValueException;
  19. use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
  20. use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
  21. use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
  22. use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
  23. use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
  24. use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
  25. use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
  26. use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
  27. /**
  28.  * Serializer serializes and deserializes data.
  29.  *
  30.  * objects are turned into arrays by normalizers.
  31.  * arrays are turned into various output formats by encoders.
  32.  *
  33.  *     $serializer->serialize($obj, 'xml')
  34.  *     $serializer->decode($data, 'xml')
  35.  *     $serializer->denormalize($data, 'Class', 'xml')
  36.  *
  37.  * @author Jordi Boggiano <j.boggiano@seld.be>
  38.  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  39.  * @author Lukas Kahwe Smith <smith@pooteeweet.org>
  40.  * @author Kévin Dunglas <dunglas@gmail.com>
  41.  */
  42. class Serializer implements SerializerInterfaceContextAwareNormalizerInterfaceContextAwareDenormalizerInterfaceContextAwareEncoderInterfaceContextAwareDecoderInterface
  43. {
  44.     /**
  45.      * @var Encoder\ChainEncoder
  46.      */
  47.     protected $encoder;
  48.     /**
  49.      * @var Encoder\ChainDecoder
  50.      */
  51.     protected $decoder;
  52.     /**
  53.      * @internal since Symfony 4.1
  54.      */
  55.     protected $normalizers = [];
  56.     private $cachedNormalizers;
  57.     private $denormalizerCache = [];
  58.     private $normalizerCache = [];
  59.     /**
  60.      * @param (NormalizerInterface|DenormalizerInterface)[] $normalizers
  61.      * @param (EncoderInterface|DecoderInterface)[]         $encoders
  62.      */
  63.     public function __construct(array $normalizers = [], array $encoders = [])
  64.     {
  65.         foreach ($normalizers as $normalizer) {
  66.             if ($normalizer instanceof SerializerAwareInterface) {
  67.                 $normalizer->setSerializer($this);
  68.             }
  69.             if ($normalizer instanceof DenormalizerAwareInterface) {
  70.                 $normalizer->setDenormalizer($this);
  71.             }
  72.             if ($normalizer instanceof NormalizerAwareInterface) {
  73.                 $normalizer->setNormalizer($this);
  74.             }
  75.             if (!($normalizer instanceof NormalizerInterface || $normalizer instanceof DenormalizerInterface)) {
  76.                 @trigger_error(sprintf('Passing normalizers ("%s") which do not implement either "%s" or "%s" has been deprecated since Symfony 4.2.', \get_class($normalizer), NormalizerInterface::class, DenormalizerInterface::class), E_USER_DEPRECATED);
  77.                 // throw new \InvalidArgumentException(\sprintf('The class "%s" does not implement "%s" or "%s".', \get_class($normalizer), NormalizerInterface::class, DenormalizerInterface::class));
  78.             }
  79.         }
  80.         $this->normalizers $normalizers;
  81.         $decoders = [];
  82.         $realEncoders = [];
  83.         foreach ($encoders as $encoder) {
  84.             if ($encoder instanceof SerializerAwareInterface) {
  85.                 $encoder->setSerializer($this);
  86.             }
  87.             if ($encoder instanceof DecoderInterface) {
  88.                 $decoders[] = $encoder;
  89.             }
  90.             if ($encoder instanceof EncoderInterface) {
  91.                 $realEncoders[] = $encoder;
  92.             }
  93.             if (!($encoder instanceof EncoderInterface || $encoder instanceof DecoderInterface)) {
  94.                 @trigger_error(sprintf('Passing encoders ("%s") which do not implement either "%s" or "%s" has been deprecated since Symfony 4.2.', \get_class($encoder), EncoderInterface::class, DecoderInterface::class), E_USER_DEPRECATED);
  95.                 // throw new \InvalidArgumentException(\sprintf('The class "%s" does not implement "%s" or "%s".', \get_class($normalizer), EncoderInterface::class, DecoderInterface::class));
  96.             }
  97.         }
  98.         $this->encoder = new ChainEncoder($realEncoders);
  99.         $this->decoder = new ChainDecoder($decoders);
  100.     }
  101.     /**
  102.      * {@inheritdoc}
  103.      */
  104.     final public function serialize($data$format, array $context = [])
  105.     {
  106.         if (!$this->supportsEncoding($format$context)) {
  107.             throw new NotEncodableValueException(sprintf('Serialization for the format %s is not supported'$format));
  108.         }
  109.         if ($this->encoder->needsNormalization($format$context)) {
  110.             $data $this->normalize($data$format$context);
  111.         }
  112.         return $this->encode($data$format$context);
  113.     }
  114.     /**
  115.      * {@inheritdoc}
  116.      */
  117.     final public function deserialize($data$type$format, array $context = [])
  118.     {
  119.         if (!$this->supportsDecoding($format$context)) {
  120.             throw new NotEncodableValueException(sprintf('Deserialization for the format %s is not supported'$format));
  121.         }
  122.         $data $this->decode($data$format$context);
  123.         return $this->denormalize($data$type$format$context);
  124.     }
  125.     /**
  126.      * {@inheritdoc}
  127.      */
  128.     public function normalize($data$format null, array $context = [])
  129.     {
  130.         // If a normalizer supports the given data, use it
  131.         if ($normalizer $this->getNormalizer($data$format$context)) {
  132.             return $normalizer->normalize($data$format$context);
  133.         }
  134.         if (null === $data || is_scalar($data)) {
  135.             return $data;
  136.         }
  137.         if (\is_array($data) || $data instanceof \Traversable) {
  138.             $normalized = [];
  139.             foreach ($data as $key => $val) {
  140.                 $normalized[$key] = $this->normalize($val$format$context);
  141.             }
  142.             return $normalized;
  143.         }
  144.         if (\is_object($data)) {
  145.             if (!$this->normalizers) {
  146.                 throw new LogicException('You must register at least one normalizer to be able to normalize objects.');
  147.             }
  148.             throw new NotNormalizableValueException(sprintf('Could not normalize object of type %s, no supporting normalizer found.', \get_class($data)));
  149.         }
  150.         throw new NotNormalizableValueException(sprintf('An unexpected value could not be normalized: %s'var_export($datatrue)));
  151.     }
  152.     /**
  153.      * {@inheritdoc}
  154.      *
  155.      * @throws NotNormalizableValueException
  156.      */
  157.     public function denormalize($data$type$format null, array $context = [])
  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 ($normalizer $this->getDenormalizer($data$type$format$context)) {
  163.             return $normalizer->denormalize($data$type$format$context);
  164.         }
  165.         throw new NotNormalizableValueException(sprintf('Could not denormalize object of type %s, no supporting normalizer found.'$type));
  166.     }
  167.     /**
  168.      * {@inheritdoc}
  169.      */
  170.     public function supportsNormalization($data$format null, array $context = [])
  171.     {
  172.         return null !== $this->getNormalizer($data$format$context);
  173.     }
  174.     /**
  175.      * {@inheritdoc}
  176.      */
  177.     public function supportsDenormalization($data$type$format null, array $context = [])
  178.     {
  179.         return null !== $this->getDenormalizer($data$type$format$context);
  180.     }
  181.     /**
  182.      * Returns a matching normalizer.
  183.      *
  184.      * @param mixed  $data    Data to get the serializer for
  185.      * @param string $format  Format name, present to give the option to normalizers to act differently based on formats
  186.      * @param array  $context Options available to the normalizer
  187.      *
  188.      * @return NormalizerInterface|null
  189.      */
  190.     private function getNormalizer($data, ?string $format, array $context)
  191.     {
  192.         if ($this->cachedNormalizers !== $this->normalizers) {
  193.             $this->cachedNormalizers $this->normalizers;
  194.             $this->denormalizerCache $this->normalizerCache = [];
  195.         }
  196.         $type = \is_object($data) ? \get_class($data) : 'native-'.\gettype($data);
  197.         if (!isset($this->normalizerCache[$format][$type])) {
  198.             $this->normalizerCache[$format][$type] = [];
  199.             foreach ($this->normalizers as $k => $normalizer) {
  200.                 if (!$normalizer instanceof NormalizerInterface) {
  201.                     continue;
  202.                 }
  203.                 if (!$normalizer instanceof CacheableSupportsMethodInterface || !$normalizer->hasCacheableSupportsMethod()) {
  204.                     $this->normalizerCache[$format][$type][$k] = false;
  205.                 } elseif ($normalizer->supportsNormalization($data$format$context)) {
  206.                     $this->normalizerCache[$format][$type][$k] = true;
  207.                     break;
  208.                 }
  209.             }
  210.         }
  211.         foreach ($this->normalizerCache[$format][$type] as $k => $cached) {
  212.             $normalizer $this->normalizers[$k];
  213.             if ($cached || $normalizer->supportsNormalization($data$format$context)) {
  214.                 return $normalizer;
  215.             }
  216.         }
  217.     }
  218.     /**
  219.      * Returns a matching denormalizer.
  220.      *
  221.      * @param mixed  $data    Data to restore
  222.      * @param string $class   The expected class to instantiate
  223.      * @param string $format  Format name, present to give the option to normalizers to act differently based on formats
  224.      * @param array  $context Options available to the denormalizer
  225.      *
  226.      * @return DenormalizerInterface|null
  227.      */
  228.     private function getDenormalizer($datastring $class, ?string $format, array $context)
  229.     {
  230.         if ($this->cachedNormalizers !== $this->normalizers) {
  231.             $this->cachedNormalizers $this->normalizers;
  232.             $this->denormalizerCache $this->normalizerCache = [];
  233.         }
  234.         if (!isset($this->denormalizerCache[$format][$class])) {
  235.             $this->denormalizerCache[$format][$class] = [];
  236.             foreach ($this->normalizers as $k => $normalizer) {
  237.                 if (!$normalizer instanceof DenormalizerInterface) {
  238.                     continue;
  239.                 }
  240.                 if (!$normalizer instanceof CacheableSupportsMethodInterface || !$normalizer->hasCacheableSupportsMethod()) {
  241.                     $this->denormalizerCache[$format][$class][$k] = false;
  242.                 } elseif ($normalizer->supportsDenormalization(null$class$format$context)) {
  243.                     $this->denormalizerCache[$format][$class][$k] = true;
  244.                     break;
  245.                 }
  246.             }
  247.         }
  248.         foreach ($this->denormalizerCache[$format][$class] as $k => $cached) {
  249.             $normalizer $this->normalizers[$k];
  250.             if ($cached || $normalizer->supportsDenormalization($data$class$format$context)) {
  251.                 return $normalizer;
  252.             }
  253.         }
  254.     }
  255.     /**
  256.      * {@inheritdoc}
  257.      */
  258.     final public function encode($data$format, array $context = [])
  259.     {
  260.         return $this->encoder->encode($data$format$context);
  261.     }
  262.     /**
  263.      * {@inheritdoc}
  264.      */
  265.     final public function decode($data$format, array $context = [])
  266.     {
  267.         return $this->decoder->decode($data$format$context);
  268.     }
  269.     /**
  270.      * {@inheritdoc}
  271.      */
  272.     public function supportsEncoding($format, array $context = [])
  273.     {
  274.         return $this->encoder->supportsEncoding($format$context);
  275.     }
  276.     /**
  277.      * {@inheritdoc}
  278.      */
  279.     public function supportsDecoding($format, array $context = [])
  280.     {
  281.         return $this->decoder->supportsDecoding($format$context);
  282.     }
  283. }