Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add global handlers for all data types #1587

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions doc/handlers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,50 @@ Skippable Subscribing Handlers

In case you need to be able to fall back to the default deserialization behavior instead of using your custom
handler, you can simply throw a `SkipHandlerException` from you custom handler method to do so.

Global Subscribing Handlers
----------------
You can register global handler, if type is '*'::

use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\Context;

class MyHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods()
{
return [
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => '*',
'method' => 'handleCustomSerialization',
],
[
'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
'format' => 'json',
'type' => '*',
'method' => 'handleCustomDeserialization',
],
];
}

public function handleCustomSerialization(JsonSerializationVisitor $visitor, mixed $data, array $type, Context $context)
{
// preform custom logic
}

public function handleCustomDeserialization(JsonDeserializationVisitor $visitor, mixed $data, array $type, Context $context)
{
// preform custom logic
}
}
..

Be aware that when you register a global handler,
it will be triggered for every serialization/deserialization process,
unless another custom handler specified.
Be sure to properly handle data processing.
12 changes: 9 additions & 3 deletions src/Handler/HandlerRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

class HandlerRegistry implements HandlerRegistryInterface
{
protected const GLOBAL_HANDLER_TYPE = '*';

/**
* @var callable[]
*/
Expand Down Expand Up @@ -70,11 +72,15 @@ public function registerHandler(int $direction, string $typeName, string $format
*/
public function getHandler(int $direction, string $typeName, string $format)
{
if (!isset($this->handlers[$direction][$typeName][$format])) {
return null;
if (isset($this->handlers[$direction][$typeName][$format])) {
return $this->handlers[$direction][$typeName][$format];
}

if (isset($this->handlers[$direction][self::GLOBAL_HANDLER_TYPE][$format])) {
return $this->handlers[$direction][self::GLOBAL_HANDLER_TYPE][$format];
}

return $this->handlers[$direction][$typeName][$format];
return null;
}

/**
Expand Down
15 changes: 12 additions & 3 deletions src/Handler/LazyHandlerRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,20 @@ public function getHandler(int $direction, string $typeName, string $format)
return $this->initializedHandlers[$direction][$typeName][$format];
}

if (!isset($this->handlers[$direction][$typeName][$format])) {
return null;
$handler = $this->handlers[$direction][$typeName][$format] ?? null;

if (null === $handler) {
if (isset($this->initializedHandlers[$direction][self::GLOBAL_HANDLER_TYPE][$format])) {
return $this->initializedHandlers[$direction][self::GLOBAL_HANDLER_TYPE][$format];
}

if (null === $handler = $this->handlers[$direction][self::GLOBAL_HANDLER_TYPE][$format]) {
return null;
}

$typeName = self::GLOBAL_HANDLER_TYPE;
}

$handler = $this->handlers[$direction][$typeName][$format];
if (\is_array($handler) && \is_string($handler[0]) && $this->container->has($handler[0])) {
$handler[0] = $this->container->get($handler[0]);
}
Expand Down
20 changes: 20 additions & 0 deletions tests/Handler/HandlerRegistryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ public function testRegisteredHandlersCanBeRetrieved()
self::assertSame($xmlDeserializationHandler, $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '\stdClass', 'xml'));
}

public function testRegisteredGlobalHandlersCanBeRetrieved()
{
$jsonSerializationHandler = new DummyHandler();
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'json', $jsonSerializationHandler);

$jsonDeserializationHandler = new DummyHandler();
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'json', $jsonDeserializationHandler);

$xmlSerializationHandler = new DummyHandler();
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'xml', $xmlSerializationHandler);

$xmlDeserializationHandler = new DummyHandler();
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'xml', $xmlDeserializationHandler);

self::assertSame($jsonSerializationHandler, $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'json'));
self::assertSame($jsonDeserializationHandler, $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'json'));
self::assertSame($xmlSerializationHandler, $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'xml'));
self::assertSame($xmlDeserializationHandler, $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'xml'));
}

protected function createHandlerRegistry()
{
return new HandlerRegistry();
Expand Down
24 changes: 24 additions & 0 deletions tests/Handler/LazyHandlerRegistryTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,30 @@ public function testRegisteredHandlersCanBeRetrievedWhenBeingDefinedAsServices()
self::assertSame([$xmlDeserializationHandler, 'handle'], $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '\stdClass', 'xml'));
}

public function testRegisteredGlobalHandlersCanBeRetrievedWhenBeingDefinedAsServices()
{
$jsonSerializationHandler = new HandlerService();
$this->registerHandlerService('handler.serialization.json', $jsonSerializationHandler);
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'json', ['handler.serialization.json', 'handle']);

$jsonDeserializationHandler = new HandlerService();
$this->registerHandlerService('handler.deserialization.json', $jsonDeserializationHandler);
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'json', ['handler.deserialization.json', 'handle']);

$xmlSerializationHandler = new HandlerService();
$this->registerHandlerService('handler.serialization.xml', $xmlSerializationHandler);
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'xml', ['handler.serialization.xml', 'handle']);

$xmlDeserializationHandler = new HandlerService();
$this->registerHandlerService('handler.deserialization.xml', $xmlDeserializationHandler);
$this->handlerRegistry->registerHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'xml', ['handler.deserialization.xml', 'handle']);

self::assertSame([$jsonSerializationHandler, 'handle'], $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'json'));
self::assertSame([$jsonDeserializationHandler, 'handle'], $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'json'));
self::assertSame([$xmlSerializationHandler, 'handle'], $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_SERIALIZATION, '*', 'xml'));
self::assertSame([$xmlDeserializationHandler, 'handle'], $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, '*', 'xml'));
}

abstract protected function createContainer();

abstract protected function registerHandlerService($serviceId, $listener);
Expand Down