diff --git a/UPGRADE-3.x.md b/UPGRADE-3.x.md index f41f1487..6516c254 100644 --- a/UPGRADE-3.x.md +++ b/UPGRADE-3.x.md @@ -52,6 +52,12 @@ All twig classes have been deprecated and were moved to the `Sonata\Twig\` subna All meta classes have been deprecated and were moved to the `SonataBlockBundle`: - `Sonata\CoreBundle\Model\Metadata` => `Sonata\BlockBundle\Meta\Metadata` - `Sonata\CoreBundle\Model\MetadataInterface` => `Sonata\BlockBundle\Meta\MetadataInterface` + +### Serializer deprecations + +All serializer classes have been deprecated and were moved to the `Sonata\Serializer\` subnamespace: + - `Sonata\CoreBundle\Serializer\BaseSerializerHandler` => `Sonata\Serializer\BaseSerializerHandler` + - `Sonata\CoreBundle\Serializer\SerializerHandlerInterface` => `Sonata\Serializer\SerializerHandlerInterface` UPGRADE FROM 3.6 to 3.7 ======================= diff --git a/composer.json b/composer.json index 24d5f752..765572f8 100644 --- a/composer.json +++ b/composer.json @@ -61,6 +61,7 @@ "psr-4": { "Sonata\\CoreBundle\\": "src/CoreBundle/", "Sonata\\Form\\": "src/Form/", + "Sonata\\Serializer\\": "src/Serializer/", "Sonata\\Twig\\": "src/Twig/" } }, @@ -68,6 +69,7 @@ "psr-4": { "Sonata\\CoreBundle\\Tests\\": "tests/CoreBundle/", "Sonata\\Form\\Tests\\": "tests/Form/", + "Sonata\\Serializer\\Tests\\": "tests/Serializer/", "Sonata\\Twig\\Tests\\": "tests/Twig/" } } diff --git a/src/CoreBundle/Serializer/BaseSerializerHandler.php b/src/CoreBundle/Serializer/BaseSerializerHandler.php index 11855aec..b90e21aa 100644 --- a/src/CoreBundle/Serializer/BaseSerializerHandler.php +++ b/src/CoreBundle/Serializer/BaseSerializerHandler.php @@ -11,110 +11,15 @@ namespace Sonata\CoreBundle\Serializer; -use JMS\Serializer\Context; -use JMS\Serializer\GraphNavigator; -use JMS\Serializer\VisitorInterface; -use Sonata\CoreBundle\Model\ManagerInterface; +@trigger_error( + 'The '.__NAMESPACE__.'\BaseSerializerHandler class is deprecated since version 3.x and will be removed in 4.0.' + .' Use Sonata\Serializer\BaseSerializerHandler instead.', + E_USER_DEPRECATED +); /** - * @author Sylvain Deloux + * @deprecated Since version 3.x, to be removed in 4.0. */ -abstract class BaseSerializerHandler implements SerializerHandlerInterface +abstract class BaseSerializerHandler extends \Sonata\Serializer\BaseSerializerHandler implements SerializerHandlerInterface { - /** - * @var ManagerInterface - */ - protected $manager; - - /** - * @var string[] - */ - protected static $formats; - - /** - * @param ManagerInterface $manager - */ - public function __construct(ManagerInterface $manager) - { - $this->manager = $manager; - } - - /** - * @param string[] $formats - */ - final public static function setFormats(array $formats) - { - static::$formats = $formats; - } - - /** - * @param string $format - */ - final public static function addFormat($format) - { - static::$formats[] = $format; - } - - public static function getSubscribingMethods() - { - // NEXT_MAJOR : remove this block - if (null === static::$formats) { - static::$formats = ['json', 'xml', 'yml']; - @trigger_error( - '$formats has been set to default array("json", "xml", "yml"). Setting $formats to a - default array is deprecated since version 3.0 and will be removed in 4.0. Use SonataCoreBundle - configuration to add default serializer formats.', - E_USER_DEPRECATED - ); - } - - $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. - * - * @param object $data - * - * @return int|null - */ - public function serializeObjectToId(VisitorInterface $visitor, $data, array $type, Context $context) - { - $className = $this->manager->getClass(); - - if ($data instanceof $className) { - return $visitor->visitInteger($data->getId(), $type, $context); - } - } - - /** - * Deserialize object from its id. - * - * @param int $data - * - * @return null|object - */ - public function deserializeObjectFromId(VisitorInterface $visitor, $data, array $type) - { - return $this->manager->findOneBy(['id' => $data]); - } } diff --git a/src/CoreBundle/Serializer/SerializerHandlerInterface.php b/src/CoreBundle/Serializer/SerializerHandlerInterface.php index d82fdb96..d4cdd6a0 100644 --- a/src/CoreBundle/Serializer/SerializerHandlerInterface.php +++ b/src/CoreBundle/Serializer/SerializerHandlerInterface.php @@ -11,12 +11,16 @@ namespace Sonata\CoreBundle\Serializer; -use JMS\Serializer\Handler\SubscribingHandlerInterface; +@trigger_error( + 'The '.__NAMESPACE__.'\SerializerHandlerInterface class is deprecated since version 3.x and will be removed in 4.0.' + .' Use Sonata\Serializer\SerializerHandlerInterface instead.', + E_USER_DEPRECATED +); /** - * @author Sylvain Deloux + * @deprecated Since version 3.x, to be removed in 4.0. */ -interface SerializerHandlerInterface extends SubscribingHandlerInterface +interface SerializerHandlerInterface extends \Sonata\Serializer\SerializerHandlerInterface { /** * @return string diff --git a/src/Serializer/BaseSerializerHandler.php b/src/Serializer/BaseSerializerHandler.php new file mode 100644 index 00000000..7fb2b113 --- /dev/null +++ b/src/Serializer/BaseSerializerHandler.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\Serializer; + +use JMS\Serializer\Context; +use JMS\Serializer\GraphNavigator; +use JMS\Serializer\VisitorInterface; +use Sonata\CoreBundle\Model\ManagerInterface; + +/** + * @author Sylvain Deloux + */ +abstract class BaseSerializerHandler implements SerializerHandlerInterface +{ + /** + * @var ManagerInterface + */ + protected $manager; + + /** + * @var string[] + */ + protected static $formats; + + /** + * @param ManagerInterface $manager + */ + public function __construct(ManagerInterface $manager) + { + $this->manager = $manager; + } + + /** + * @param string[] $formats + */ + final public static function setFormats(array $formats) + { + static::$formats = $formats; + } + + /** + * @param string $format + */ + final public static function addFormat($format) + { + static::$formats[] = $format; + } + + public static function getSubscribingMethods() + { + // NEXT_MAJOR : remove this block + if (null === static::$formats) { + static::$formats = ['json', 'xml', 'yml']; + @trigger_error( + '$formats has been set to default array("json", "xml", "yml"). Setting $formats to a + default array is deprecated since version 3.0 and will be removed in 4.0. Use SonataCoreBundle + configuration to add default serializer formats.', + E_USER_DEPRECATED + ); + } + + $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. + * + * @param object $data + * + * @return int|null + */ + public function serializeObjectToId(VisitorInterface $visitor, $data, array $type, Context $context) + { + $className = $this->manager->getClass(); + + if ($data instanceof $className) { + return $visitor->visitInteger($data->getId(), $type, $context); + } + } + + /** + * Deserialize object from its id. + * + * @param int $data + * + * @return null|object + */ + public function deserializeObjectFromId(VisitorInterface $visitor, $data, array $type) + { + return $this->manager->findOneBy(['id' => $data]); + } +} diff --git a/src/Serializer/SerializerHandlerInterface.php b/src/Serializer/SerializerHandlerInterface.php new file mode 100644 index 00000000..1fe505d6 --- /dev/null +++ b/src/Serializer/SerializerHandlerInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\Serializer; + +use JMS\Serializer\Handler\SubscribingHandlerInterface; + +/** + * @author Sylvain Deloux + */ +interface SerializerHandlerInterface extends SubscribingHandlerInterface +{ + /** + * @return string + */ + public static function getType(); +} diff --git a/tests/Serializer/BaseSerializerHandlerTest.php b/tests/Serializer/BaseSerializerHandlerTest.php new file mode 100644 index 00000000..0e9b121b --- /dev/null +++ b/tests/Serializer/BaseSerializerHandlerTest.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\Serializer\Tests; + +use JMS\Serializer\Context; +use JMS\Serializer\GraphNavigator; +use JMS\Serializer\VisitorInterface; +use PHPUnit\Framework\TestCase; +use Sonata\CoreBundle\Model\ManagerInterface; +use Sonata\Serializer\BaseSerializerHandler; +use Sonata\Serializer\Tests\Fixtures\Bundle\Serializer\FooSerializer; + +/** + * @author Ahmet Akbana + */ +final class BaseSerializerHandlerTest extends TestCase +{ + public function setUp() + { + BaseSerializerHandler::setFormats(['json', 'xml', 'yml']); + } + + /** + * @group legacy + * + * NEXT_MAJOR : this should call setFormats method + */ + public function testGetSubscribingMethodsWithDefaultFormats() + { + $manager = $this->createMock(ManagerInterface::class); + + $serializer = new FooSerializer($manager); + + $expectedMethods = [ + [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'json', + 'type' => 'foo', + 'method' => 'serializeObjectToId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => 'json', + 'type' => 'foo', + 'method' => 'deserializeObjectFromId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'xml', + 'type' => 'foo', + 'method' => 'serializeObjectToId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => 'xml', + 'type' => 'foo', + 'method' => 'deserializeObjectFromId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'yml', + 'type' => 'foo', + 'method' => 'serializeObjectToId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => 'yml', + 'type' => 'foo', + 'method' => 'deserializeObjectFromId', + ], + ]; + + $methods = $serializer::getSubscribingMethods(); + + $this->assertSame($methods, $expectedMethods); + } + + public function testSetFormats() + { + $manager = $this->createMock(ManagerInterface::class); + + $serializer = new FooSerializer($manager); + + $expectedMethods = [ + [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'bar', + 'type' => 'foo', + 'method' => 'serializeObjectToId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => 'bar', + 'type' => 'foo', + 'method' => 'deserializeObjectFromId', + ], + ]; + + $serializer::setFormats(['bar']); + + $methods = $serializer::getSubscribingMethods(); + + $this->assertSame($methods, $expectedMethods); + } + + public function testAddFormats() + { + $manager = $this->createMock(ManagerInterface::class); + + $serializer = new FooSerializer($manager); + + $expectedMethods = [ + [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'bar', + 'type' => 'foo', + 'method' => 'serializeObjectToId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => 'bar', + 'type' => 'foo', + 'method' => 'deserializeObjectFromId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'foo', + 'type' => 'foo', + 'method' => 'serializeObjectToId', + ], + [ + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'format' => 'foo', + 'type' => 'foo', + 'method' => 'deserializeObjectFromId', + ], + ]; + + $serializer::setFormats(['bar']); + + $serializer::addFormat('foo'); + + $methods = $serializer::getSubscribingMethods(); + + $this->assertSame($methods, $expectedMethods); + } + + public function testSerializeObjectToIdWithDataIsInstanceOfManager() + { + $modelInstance = $this->getMockBuilder(FooSerializer::class) + ->disableOriginalConstructor() + ->setMethods(['getId']) + ->getMock(); + + $modelInstance->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $manager = $this->createMock(ManagerInterface::class); + $manager->expects($this->once()) + ->method('getClass') + ->willReturn(\get_class($modelInstance)); + + $context = $this->createMock(Context::class); + + $visitor = $this->createMock(VisitorInterface::class); + $visitor->expects($this->once()) + ->method('visitInteger') + ->with(1, ['foo'], $context) + ->willReturn(true); + + $serializer = new FooSerializer($manager); + + $this->assertTrue($serializer->serializeObjectToId($visitor, $modelInstance, ['foo'], $context)); + } + + public function testSerializeObjectToIdWithDataIsNotInstanceOfManager() + { + $modelInstance = $this->getMockBuilder(FooSerializer::class) + ->disableOriginalConstructor() + ->getMock(); + + $manager = $this->createMock(ManagerInterface::class); + $manager->expects($this->once()) + ->method('getClass') + ->willReturn('bar'); + + $context = $this->createMock(Context::class); + + $visitor = $this->createMock(VisitorInterface::class); + $visitor->expects($this->never()) + ->method('visitInteger'); + + $serializer = new FooSerializer($manager); + + $serializer->serializeObjectToId($visitor, $modelInstance, ['foo'], $context); + } + + public function testDeserializeObjectFromId() + { + $manager = $this->createMock(ManagerInterface::class); + $manager->expects($this->once()) + ->method('findOneBy') + ->with(['id' => 'foo']) + ->willReturn('bar'); + + $visitor = $this->createMock(VisitorInterface::class); + + $serializer = new FooSerializer($manager); + + $this->assertSame('bar', $serializer->deserializeObjectFromId($visitor, 'foo', [])); + } +} diff --git a/tests/Serializer/Fixtures/Bundle/Serializer/FooSerializer.php b/tests/Serializer/Fixtures/Bundle/Serializer/FooSerializer.php new file mode 100644 index 00000000..48a91a8a --- /dev/null +++ b/tests/Serializer/Fixtures/Bundle/Serializer/FooSerializer.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\Serializer\Tests\Fixtures\Bundle\Serializer; + +use Sonata\CoreBundle\Model\ManagerInterface; +use Sonata\Serializer\BaseSerializerHandler; + +/** + * @author Ahmet Akbana + */ +class FooSerializer extends BaseSerializerHandler +{ + /** + * @param ManagerInterface $manager + */ + public function __construct(ManagerInterface $manager) + { + parent::__construct($manager); + } + + /** + * {@inheritdoc} + */ + public static function getType() + { + return 'foo'; + } +}