vendor/jms/serializer/src/Serializer.php line 163

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace JMS\Serializer;
  4. use JMS\Serializer\ContextFactory\DefaultDeserializationContextFactory;
  5. use JMS\Serializer\ContextFactory\DefaultSerializationContextFactory;
  6. use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface;
  7. use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
  8. use JMS\Serializer\Exception\InvalidArgumentException;
  9. use JMS\Serializer\Exception\RuntimeException;
  10. use JMS\Serializer\Exception\UnsupportedFormatException;
  11. use JMS\Serializer\GraphNavigator\Factory\GraphNavigatorFactoryInterface;
  12. use JMS\Serializer\Type\Parser;
  13. use JMS\Serializer\Type\ParserInterface;
  14. use JMS\Serializer\Visitor\Factory\DeserializationVisitorFactory;
  15. use JMS\Serializer\Visitor\Factory\SerializationVisitorFactory;
  16. use Metadata\MetadataFactoryInterface;
  17. /**
  18.  * Serializer Implementation.
  19.  *
  20.  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  21.  */
  22. final class Serializer implements SerializerInterfaceArrayTransformerInterface
  23. {
  24.     /**
  25.      * @var MetadataFactoryInterface
  26.      */
  27.     private $factory;
  28.     /**
  29.      * @var ParserInterface
  30.      */
  31.     private $typeParser;
  32.     /**
  33.      * @var SerializationVisitorFactory[]
  34.      */
  35.     private $serializationVisitors;
  36.     /**
  37.      * @var DeserializationVisitorFactory[]
  38.      */
  39.     private $deserializationVisitors;
  40.     /**
  41.      * @var SerializationContextFactoryInterface
  42.      */
  43.     private $serializationContextFactory;
  44.     /**
  45.      * @var DeserializationContextFactoryInterface
  46.      */
  47.     private $deserializationContextFactory;
  48.     /**
  49.      * @var GraphNavigatorFactoryInterface[]
  50.      */
  51.     private $graphNavigators;
  52.     /**
  53.      * @param GraphNavigatorFactoryInterface[] $graphNavigators
  54.      * @param SerializationVisitorFactory[] $serializationVisitors
  55.      * @param DeserializationVisitorFactory[] $deserializationVisitors
  56.      */
  57.     public function __construct(
  58.         MetadataFactoryInterface $factory,
  59.         array $graphNavigators,
  60.         array $serializationVisitors,
  61.         array $deserializationVisitors,
  62.         ?SerializationContextFactoryInterface $serializationContextFactory null,
  63.         ?DeserializationContextFactoryInterface $deserializationContextFactory null,
  64.         ?ParserInterface $typeParser null
  65.     ) {
  66.         $this->factory $factory;
  67.         $this->graphNavigators $graphNavigators;
  68.         $this->serializationVisitors $serializationVisitors;
  69.         $this->deserializationVisitors $deserializationVisitors;
  70.         $this->typeParser $typeParser ?? new Parser();
  71.         $this->serializationContextFactory $serializationContextFactory ?: new DefaultSerializationContextFactory();
  72.         $this->deserializationContextFactory $deserializationContextFactory ?: new DefaultDeserializationContextFactory();
  73.     }
  74.     /**
  75.      * Parses a direction string to one of the direction constants.
  76.      */
  77.     public static function parseDirection(string $dirStr): int
  78.     {
  79.         switch (strtolower($dirStr)) {
  80.             case 'serialization':
  81.                 return GraphNavigatorInterface::DIRECTION_SERIALIZATION;
  82.             case 'deserialization':
  83.                 return GraphNavigatorInterface::DIRECTION_DESERIALIZATION;
  84.             default:
  85.                 throw new InvalidArgumentException(sprintf('The direction "%s" does not exist.'$dirStr));
  86.         }
  87.     }
  88.     private function findInitialType(?string $typeSerializationContext $context): ?string
  89.     {
  90.         if (null !== $type) {
  91.             return $type;
  92.         } elseif ($context->hasAttribute('initial_type')) {
  93.             return $context->getAttribute('initial_type');
  94.         }
  95.         return null;
  96.     }
  97.     private function getNavigator(int $direction): GraphNavigatorInterface
  98.     {
  99.         if (!isset($this->graphNavigators[$direction])) {
  100.             throw new RuntimeException(
  101.                 sprintf(
  102.                     'Can not find a graph navigator for the direction "%s".',
  103.                     GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction 'serialization' 'deserialization'
  104.                 )
  105.             );
  106.         }
  107.         return $this->graphNavigators[$direction]->getGraphNavigator();
  108.     }
  109.     private function getVisitor(int $directionstring $format): VisitorInterface
  110.     {
  111.         $factories GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction
  112.             $this->serializationVisitors
  113.             $this->deserializationVisitors;
  114.         if (!isset($factories[$format])) {
  115.             throw new UnsupportedFormatException(
  116.                 sprintf(
  117.                     'The format "%s" is not supported for %s.',
  118.                     $format,
  119.                     GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction 'serialization' 'deserialization'
  120.                 )
  121.             );
  122.         }
  123.         return $factories[$format]->getVisitor();
  124.     }
  125.     /**
  126.      * {@InheritDoc}
  127.      */
  128.     public function serialize($datastring $format, ?SerializationContext $context null, ?string $type null): string
  129.     {
  130.         if (null === $context) {
  131.             $context $this->serializationContextFactory->createSerializationContext();
  132.         }
  133.         $visitor $this->getVisitor(GraphNavigatorInterface::DIRECTION_SERIALIZATION$format);
  134.         $navigator $this->getNavigator(GraphNavigatorInterface::DIRECTION_SERIALIZATION);
  135.         $type $this->findInitialType($type$context);
  136.         $result $this->visit($navigator$visitor$context$data$format$type);
  137.         $context->close();
  138.         return $visitor->getResult($result);
  139.     }
  140.     /**
  141.      * {@InheritDoc}
  142.      */
  143.     public function deserialize(string $datastring $typestring $format, ?DeserializationContext $context null)
  144.     {
  145.         if (null === $context) {
  146.             $context $this->deserializationContextFactory->createDeserializationContext();
  147.         }
  148.         $visitor $this->getVisitor(GraphNavigatorInterface::DIRECTION_DESERIALIZATION$format);
  149.         $navigator $this->getNavigator(GraphNavigatorInterface::DIRECTION_DESERIALIZATION);
  150.         $result $this->visit($navigator$visitor$context$data$format$type);
  151.         $context->close();
  152.         return $visitor->getResult($result);
  153.     }
  154.     /**
  155.      * {@InheritDoc}
  156.      */
  157.     public function toArray($data, ?SerializationContext $context null, ?string $type null): array
  158.     {
  159.         if (null === $context) {
  160.             $context $this->serializationContextFactory->createSerializationContext();
  161.         }
  162.         $visitor $this->getVisitor(GraphNavigatorInterface::DIRECTION_SERIALIZATION'json');
  163.         $navigator $this->getNavigator(GraphNavigatorInterface::DIRECTION_SERIALIZATION);
  164.         $type $this->findInitialType($type$context);
  165.         $result $this->visit($navigator$visitor$context$data'json'$type);
  166.         $result $this->convertArrayObjects($result);
  167.         if (!\is_array($result)) {
  168.             throw new RuntimeException(sprintf(
  169.                 'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
  170.                 \is_object($data) ? \get_class($data) : \gettype($data),
  171.                 \is_object($result) ? \get_class($result) : \gettype($result)
  172.             ));
  173.         }
  174.         return $result;
  175.     }
  176.     /**
  177.      * {@InheritDoc}
  178.      */
  179.     public function fromArray(array $datastring $type, ?DeserializationContext $context null)
  180.     {
  181.         if (null === $context) {
  182.             $context $this->deserializationContextFactory->createDeserializationContext();
  183.         }
  184.         $visitor $this->getVisitor(GraphNavigatorInterface::DIRECTION_DESERIALIZATION'json');
  185.         $navigator $this->getNavigator(GraphNavigatorInterface::DIRECTION_DESERIALIZATION);
  186.         return $this->visit($navigator$visitor$context$data'json'$typefalse);
  187.     }
  188.     /**
  189.      * @param mixed $data
  190.      *
  191.      * @return mixed
  192.      */
  193.     private function visit(GraphNavigatorInterface $navigatorVisitorInterface $visitorContext $context$datastring $format, ?string $type nullbool $prepare true)
  194.     {
  195.         $context->initialize(
  196.             $format,
  197.             $visitor,
  198.             $navigator,
  199.             $this->factory
  200.         );
  201.         $visitor->setNavigator($navigator);
  202.         $navigator->initialize($visitor$context);
  203.         if ($prepare) {
  204.             $data $visitor->prepare($data);
  205.         }
  206.         if (null !== $type) {
  207.             $type $this->typeParser->parse($type);
  208.         }
  209.         return $navigator->accept($data$type);
  210.     }
  211.     /**
  212.      * @param mixed $data
  213.      *
  214.      * @return mixed
  215.      */
  216.     private function convertArrayObjects($data)
  217.     {
  218.         if ($data instanceof \ArrayObject || $data instanceof \stdClass) {
  219.             $data = (array) $data;
  220.         }
  221.         if (\is_array($data)) {
  222.             foreach ($data as $k => $v) {
  223.                 $data[$k] = $this->convertArrayObjects($v);
  224.             }
  225.         }
  226.         return $data;
  227.     }
  228. }