From f5408fd88acb07227cfe8134597b36e1efc11b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20B=C5=82oszyk?= Date: Thu, 9 Apr 2020 13:55:52 +0200 Subject: [PATCH] Add serializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update docs/reference/installation.rst Co-Authored-By: Grégoire Paris Update src/Bridge/Symfony/DependencyInjection/Configuration.php Co-Authored-By: Grégoire Paris Update src/Bridge/Symfony/DependencyInjection/Configuration.php Co-Authored-By: Grégoire Paris Update src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php Co-Authored-By: Grégoire Paris Update src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php Co-Authored-By: Grégoire Paris Update src/Serializer/BaseSerializerHandler.php Co-Authored-By: Javier Spagnoletti Update src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php Co-Authored-By: Javier Spagnoletti --- composer.json | 2 + docs/reference/installation.rst | 13 +++ .../DependencyInjection/Configuration.php | 22 +++++ .../SonataFormExtension.php | 14 +++ src/Serializer/BaseSerializerHandler.php | 96 +++++++++++++++++++ src/Serializer/SerializerHandlerInterface.php | 24 +++++ .../DependencyInjection/ConfigurationTest.php | 6 ++ 7 files changed, 177 insertions(+) create mode 100644 src/Serializer/BaseSerializerHandler.php create mode 100644 src/Serializer/SerializerHandlerInterface.php diff --git a/composer.json b/composer.json index a06d3882..6a920fa0 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,8 @@ "require": { "php": "^7.2", "jms/metadata": "^2.1", + "jms/serializer": "^2.0 || ^3.0", + "sonata-project/doctrine-extensions": "^1.1", "symfony/event-dispatcher": "^3.4 || ^4.3 || ^5.0", "symfony/form": "^3.4.24 || ^4.3 || ^5.0", "symfony/options-resolver": "^3.4 || ^4.3 || ^5.0", diff --git a/docs/reference/installation.rst b/docs/reference/installation.rst index bfe3a6a6..6a03e9f3 100644 --- a/docs/reference/installation.rst +++ b/docs/reference/installation.rst @@ -63,6 +63,19 @@ corresponding configuration node accordingly: sonata_form: form_type: horizontal +If you are using ``jms/serializer`` subscribing methods you will need to configure the +return formats: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/sonata_form.yaml + + sonata_form: + serializer: + formats: ['json', 'xml', 'yml'] + .. note:: If you are not using Symfony Flex, this configuration should be added diff --git a/src/Bridge/Symfony/DependencyInjection/Configuration.php b/src/Bridge/Symfony/DependencyInjection/Configuration.php index 78c86931..33ec3736 100644 --- a/src/Bridge/Symfony/DependencyInjection/Configuration.php +++ b/src/Bridge/Symfony/DependencyInjection/Configuration.php @@ -37,6 +37,7 @@ public function getConfigTreeBuilder(): TreeBuilder } $this->addFlashMessageSection($rootNode); + $this->addSerializerFormats($rootNode); return $treeBuilder; } @@ -62,4 +63,25 @@ private function addFlashMessageSection(ArrayNodeDefinition $node): void ->end() ; } + + /** + * Adds configuration for serializer formats. + */ + private function addSerializerFormats(ArrayNodeDefinition $node): void + { + $node + ->children() + ->arrayNode('serializer') + ->addDefaultsIfNotSet() + ->children() + ->arrayNode('formats') + ->prototype('scalar')->end() + ->defaultValue(['json', 'xml', 'yml']) + ->info('Default serializer formats, will be used while getting subscribing methods.') + ->end() + ->end() + ->end() + ->end() + ; + } } diff --git a/src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php b/src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php index c5a04b43..9da3517c 100644 --- a/src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php +++ b/src/Bridge/Symfony/DependencyInjection/SonataFormExtension.php @@ -13,6 +13,8 @@ namespace Sonata\Form\Bridge\Symfony\DependencyInjection; +use JMS\Serializer\Handler\SubscribingHandlerInterface; +use Sonata\Form\Serializer\BaseSerializerHandler; use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -51,5 +53,17 @@ public function load(array $configs, ContainerBuilder $container): void $loader->load('validator.xml'); $container->setParameter('sonata.form.form_type', $config['form_type']); + + $this->configureSerializerFormats($config); + } + + /** + * @param mixed[] $config + */ + private function configureSerializerFormats(array $config): void + { + if (interface_exists(SubscribingHandlerInterface::class)) { + BaseSerializerHandler::setFormats($config['serializer']['formats']); + } } } diff --git a/src/Serializer/BaseSerializerHandler.php b/src/Serializer/BaseSerializerHandler.php new file mode 100644 index 00000000..f47da0a9 --- /dev/null +++ b/src/Serializer/BaseSerializerHandler.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\Form\Serializer; + +use JMS\Serializer\Context; +use JMS\Serializer\GraphNavigator; +use JMS\Serializer\VisitorInterface; +use Sonata\Doctrine\Model\ManagerInterface; + +/** + * @author Sylvain Deloux + */ +abstract class BaseSerializerHandler implements SerializerHandlerInterface +{ + /** + * @var ManagerInterface + */ + protected $manager; + + /** + * @var string[] + */ + protected static $formats = []; + + public function __construct(ManagerInterface $manager) + { + $this->manager = $manager; + } + + final public static function setFormats(array $formats): void + { + static::$formats = $formats; + } + + final public static function addFormat(string $format): void + { + static::$formats[] = $format; + } + + public static function getSubscribingMethods(): array + { + $type = static::getType(); + $methods = []; + + foreach (static::$formats as $format) { + $methods[] = [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => $format, + 'type' => $type, + 'method' => 'serializeObjectToId', + ]; + + $methods[] = [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => $format, + 'type' => $type, + 'method' => 'deserializeObjectFromId', + ]; + } + + return $methods; + } + + /** + * Serialize data object to id. + */ + public function serializeObjectToId(VisitorInterface $visitor, object $data, array $type, Context $context): ?int + { + $className = $this->manager->getClass(); + + if ($data instanceof $className) { + return $visitor->visitInteger($data->getId(), $type, $context); + } + + return null; + } + + /** + * Deserialize object from its id. + */ + public function deserializeObjectFromId(VisitorInterface $visitor, int $data, array $type): ?object + { + return $this->manager->findOneBy(['id' => $data]); + } +} diff --git a/src/Serializer/SerializerHandlerInterface.php b/src/Serializer/SerializerHandlerInterface.php new file mode 100644 index 00000000..4f8c6525 --- /dev/null +++ b/src/Serializer/SerializerHandlerInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\Form\Serializer; + +use JMS\Serializer\Handler\SubscribingHandlerInterface; + +/** + * @author Sylvain Deloux + */ +interface SerializerHandlerInterface extends SubscribingHandlerInterface +{ + public static function getType(): string; +} diff --git a/tests/Bridge/Symfony/DependencyInjection/ConfigurationTest.php b/tests/Bridge/Symfony/DependencyInjection/ConfigurationTest.php index fd32739c..35fc9b3c 100644 --- a/tests/Bridge/Symfony/DependencyInjection/ConfigurationTest.php +++ b/tests/Bridge/Symfony/DependencyInjection/ConfigurationTest.php @@ -43,6 +43,9 @@ public function testProcessedConfigurationLooksAsExpected(): void ['form_type' => 'standard'], // by this during the merge ], [ 'form_type' => 'standard', + 'serializer' => [ + 'formats' => ['json', 'xml', 'yml'], + ], ]); } @@ -52,6 +55,9 @@ public function testDefault(): void [], ], [ 'form_type' => 'standard', + 'serializer' => [ + 'formats' => ['json', 'xml', 'yml'], + ], ]); } }