Skip to content
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