Skip to content

Commit

Permalink
Merge pull request #3 from detailnet/feature/jms-serializer
Browse files Browse the repository at this point in the history
Creating JMSSerializer
  • Loading branch information
Ivan Wolf committed Jul 6, 2018
2 parents 30e905b + 360496f commit 48d5455
Show file tree
Hide file tree
Showing 25 changed files with 753 additions and 108 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Install the module through [Composer](http://getcomposer.org/) using the followi
```json
{
"require": {
"detailnet/dfw-normalization-module": "^1.0"
"detailnet/dfw-normalization-module": "^1.1"
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"zendframework/zend-mvc": "^3.0.1",
"zendframework/zend-servicemanager": "^3.1",
"zendframework/zend-stdlib": "^3.0.1",
"detailnet/dfw-normalization": "^1.1"
"detailnet/dfw-normalization": "^1.2"
},
"require-dev": {
"phpunit/phpunit": "^7.0",
Expand Down
4 changes: 2 additions & 2 deletions config/detail_normalization.local.php.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php

return array(
return [
'detail_normalization' => [],
);
];
93 changes: 58 additions & 35 deletions config/module.config.php
Original file line number Diff line number Diff line change
@@ -1,70 +1,93 @@
<?php

use Detail\Normalization;
use Detail\Normalization\Factory;

return [
'service_manager' => [
'abstract_factories' => [
],
'aliases' => [
'jms_serializer.php_serialization_visitor' =>
Detail\Normalization\JMSSerializer\PhpSerializationVisitor::CLASS,
'jms_serializer.php_deserialization_visitor' =>
Detail\Normalization\JMSSerializer\PhpDeserializationVisitor::CLASS,
'jms_serializer.naming_strategy.identical' => JMS\Serializer\Naming\IdenticalPropertyNamingStrategy::CLASS,
// 'jms_serializer.json_serialization_visitor' => JMS\Serializer\JsonSerializationVisitor::CLASS,
// 'jms_serializer.json_deserialization_visitor' => JMS\Serializer\JsonDeserializationVisitor::CLASS,
'jms_serializer.php_serialization_visitor' => Normalization\JMSSerializer\PhpSerializationVisitor::CLASS,
'jms_serializer.php_deserialization_visitor' => Normalization\JMSSerializer\PhpDeserializationVisitor::CLASS,
// 'jms_serializer.xml_serialization_visitor' => JMS\Serializer\XmlSerializationVisitor::CLASS,
// 'jms_serializer.xml_deserialization_visitor' => JMS\Serializer\XmlDeserializationVisitor::CLASS,
'jms_serializer.serializer' => JMS\Serializer\Serializer::CLASS,
],
'invokables' => [
Detail\Normalization\JMSSerializer\EventDispatcher\Subscriber\DoctrineProxySubscriber::CLASS =>
Detail\Normalization\JMSSerializer\EventDispatcher\Subscriber\DoctrineProxySubscriber::CLASS,
Detail\Normalization\JMSSerializer\Handler\ArrayCollectionHandler::CLASS =>
Detail\Normalization\JMSSerializer\Handler\ArrayCollectionHandler::CLASS,
Detail\Normalization\JMSSerializer\Handler\DateHandler::CLASS =>
Detail\Normalization\JMSSerializer\Handler\DateHandler::CLASS,
Detail\Normalization\JMSSerializer\Handler\DateImmutableHandler::CLASS =>
Detail\Normalization\JMSSerializer\Handler\DateImmutableHandler::CLASS,

// Add our own version of the default subscriber to support HalCollection types
'jms_serializer.doctrine_proxy_subscriber' =>
Detail\Normalization\JMSSerializer\EventDispatcher\Subscriber\DoctrineProxySubscriber::CLASS,
// JMSSerializer
JMS\Serializer\Naming\IdenticalPropertyNamingStrategy::CLASS =>
JMS\Serializer\Naming\IdenticalPropertyNamingStrategy::CLASS,
// Normalizer
Normalization\JMSSerializer\EventDispatcher\Subscriber\DoctrineProxySubscriber::CLASS =>
Normalization\JMSSerializer\EventDispatcher\Subscriber\DoctrineProxySubscriber::CLASS,
Normalization\JMSSerializer\Handler\ArrayCollectionHandler::CLASS =>
Normalization\JMSSerializer\Handler\ArrayCollectionHandler::CLASS,
Normalization\JMSSerializer\Handler\DateHandler::CLASS =>
Normalization\JMSSerializer\Handler\DateHandler::CLASS,
Normalization\JMSSerializer\Handler\UuidHandler::CLASS =>
Normalization\JMSSerializer\Handler\UuidHandler::CLASS,
],
'factories' => [
Detail\Normalization\JMSSerializer\PhpSerializationVisitor::CLASS =>
Detail\Normalization\Factory\JMSSerializer\PhpSerializationVisitorFactory::CLASS,
Detail\Normalization\JMSSerializer\PhpDeserializationVisitor::CLASS =>
Detail\Normalization\Factory\JMSSerializer\PhpDeserializationVisitorFactory::CLASS,
Detail\Normalization\Normalizer\JMSSerializerBasedNormalizer::CLASS =>
Detail\Normalization\Factory\Normalizer\JMSSerializerBasedNormalizerFactory::CLASS,
Detail\Normalization\Options\ModuleOptions::CLASS =>
Detail\Normalization\Factory\Options\ModuleOptionsFactory::CLASS,
// JMSSerializer
Normalization\Options\JMSSerializerOptions::CLASS => Factory\Options\JMSSerializerOptionsFactory::CLASS,
// JMS\Serializer\JsonSerializationVisitor::CLASS =>
// Factory\JMSSerializer\JsonSerializationVisitorFactory::CLASS,
// JMS\Serializer\JsonDeserializationVisitor::CLASS =>
// Factory\JMSSerializer\JsonDeserializationVisitorFactory::CLASS,
JMS\Serializer\Serializer::CLASS => Factory\JMSSerializer\SerializerFactory::CLASS,
// JMS\Serializer\XmlSerializationVisitor::CLASS =>
// Factory\JMSSerializer\XmlSerializationVisitorFactory::CLASS,
// JMS\Serializer\XmlDeserializationVisitor::CLASS =>
// Factory\JMSSerializer\XmlDeserializationVisitorFactory::CLASS,
'jms_serializer.naming_strategy' => Factory\JMSSerializer\NamingStrategyFactory::CLASS,
// Normalizer
Normalization\JMSSerializer\PhpSerializationVisitor::CLASS =>
Factory\JMSSerializer\PhpSerializationVisitorFactory::CLASS,
Normalization\JMSSerializer\PhpDeserializationVisitor::CLASS =>
Factory\JMSSerializer\PhpDeserializationVisitorFactory::CLASS,
Normalization\Normalizer\JMSSerializerBasedNormalizer::CLASS =>
Factory\Normalizer\JMSSerializerBasedNormalizerFactory::CLASS,
Normalization\Options\ModuleOptions::CLASS => Factory\Options\ModuleOptionsFactory::CLASS,
],
'initializers' => [
Detail\Normalization\Normalizer\NormalizerInitializer::CLASS,
],
'shared' => [
Normalization\Normalizer\NormalizerInitializer::CLASS,
],
],
'controllers' => [
'initializers' => [
Detail\Normalization\Normalizer\NormalizerInitializer::CLASS,
Normalization\Normalizer\NormalizerInitializer::CLASS,
],
],
'jms_serializer' => [
'debug' => false,
'naming_strategy' => 'identical',
'visitors' => [
'serialization' => [
// 'json' => 'jms_serializer.json_serialization_visitor',
'php' => 'jms_serializer.php_serialization_visitor',
// 'xml' => 'jms_serializer.xml_serialization_visitor',
],
'deserialization' => [
// 'json' => 'jms_serializer.json_deserialization_visitor',
'php' => 'jms_serializer.php_deserialization_visitor',
// 'xml' => 'jms_serializer.xml_deserialization_visitor',
],
],
'handlers' => [
'subscribers' => [
Detail\Normalization\JMSSerializer\Handler\ArrayCollectionHandler::CLASS,
Detail\Normalization\JMSSerializer\Handler\DateHandler::CLASS,
Detail\Normalization\JMSSerializer\Handler\DateImmutableHandler::CLASS,
Detail\Normalization\JMSSerializer\Handler\UuidHandler::CLASS,
/** @todo Add handlers for PhpCollection and StdClass */
Normalization\JMSSerializer\Handler\ArrayCollectionHandler::CLASS,
Normalization\JMSSerializer\Handler\DateHandler::CLASS,
Normalization\JMSSerializer\Handler\UuidHandler::CLASS,
],
],
'eventdispatcher' => [
'subscribers' => []
],
],
'detail_normalization' => [
'normalizer' => Detail\Normalization\Normalizer\JMSSerializerBasedNormalizer::CLASS,
'normalizer' => Normalization\Normalizer\JMSSerializerBasedNormalizer::CLASS,
],
];
37 changes: 37 additions & 0 deletions src/Factory/JMSSerializer/NamingStrategyFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Detail\Normalization\Factory\JMSSerializer;

use Interop\Container\ContainerInterface;

use Zend\ServiceManager\Factory\FactoryInterface;

use JMS\Serializer\Naming\CacheNamingStrategy;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\Naming\SerializedNameAnnotationStrategy;

use Detail\Normalization\Options\JMSSerializerOptions;

class NamingStrategyFactory implements
FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
* @return PropertyNamingStrategyInterface
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** @var JMSSerializerOptions $serializerOptions */
$serializerOptions = $container->get(JMSSerializerOptions::CLASS);
$strategyName = sprintf('jms_serializer.naming_strategy.%s', $serializerOptions->getNamingStrategy());

/** @var PropertyNamingStrategyInterface $strategy */
$propertyStrategy = $container->get($strategyName);
$annotationStrategy = new SerializedNameAnnotationStrategy($propertyStrategy);

/** @todo Make cache optional/configurable */
return new CacheNamingStrategy($annotationStrategy);
}
}
101 changes: 101 additions & 0 deletions src/Factory/JMSSerializer/SerializerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace Detail\Normalization\Factory\JMSSerializer;

use Interop\Container\ContainerInterface;

use Zend\ServiceManager\Factory\FactoryInterface;

use JMS\Serializer\EventDispatcher\EventDispatcher;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\Handler\HandlerRegistry;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\Serializer;
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\VisitorInterface;

use Detail\Normalization\Options\JMSSerializerOptions;

class SerializerFactory implements
FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
* @return Serializer
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** @var JMSSerializerOptions $serializerOptions */
$serializerOptions = $container->get(JMSSerializerOptions::CLASS);

$serializer = SerializerBuilder::create();
$serializer->setDebug((bool) $serializerOptions->getDebug());

// When configuring our own handlers, the default handlers of JMS won't be added
$serializer->configureHandlers(
function (HandlerRegistry $handlers) use ($serializerOptions, $container) {
foreach ($serializerOptions->getHandlers()->getSubscribers() as $subscriberClass) {
/** @var SubscribingHandlerInterface $subscriber */
$subscriber = $container->get($subscriberClass);

$handlers->registerSubscribingHandler($subscriber);
}
}
);

// When configuring our own listeners, the default listeners of JMS won't be added
$serializer->configureListeners(
function (EventDispatcher $events) use ($serializerOptions, $container) {
foreach ($serializerOptions->getEventDispatcher()->getSubscribers() as $subscriberClass) {
/** @var EventSubscriberInterface $subscriber */
$subscriber = $container->get($subscriberClass);

$events->addSubscriber($subscriber);
}
}
);

// Need to set naming strategy before adding default visitors
/** @var PropertyNamingStrategyInterface $namingStrategy */
$namingStrategy = $container->get('jms_serializer.naming_strategy');

$serializer->setPropertyNamingStrategy($namingStrategy);

// Add default visitors (JSON, XML)...
$serializer->addDefaultSerializationVisitors();
$serializer->addDefaultDeserializationVisitors();

// ..and our own visitors.
foreach ($serializerOptions->getVisitors()->getSerialization() as $format => $visitorName) {
/** @var VisitorInterface $visitor */
$visitor = $container->get($visitorName);

$serializer->setSerializationVisitor($format, $visitor);
}

foreach ($serializerOptions->getVisitors()->getDeserialization() as $format => $visitorName) {
/** @var VisitorInterface $visitor */
$visitor = $container->get($visitorName);

$serializer->setDeserializationVisitor($format, $visitor);
}

foreach ($serializerOptions->getMetadata()->getDirectories() as $directory) {
$serializer->addMetadataDir(
rtrim($directory->getPath(), '\\/'),
$directory->getNamespacePrefix() ? rtrim($directory->getNamespacePrefix(), '\\') : ''
);
}

$cacheDir = $serializerOptions->getMetadata()->getFileCache()->getDir();

if ($cacheDir !== null) {
$serializer->setCacheDir($cacheDir);
}

return $serializer->build();
}
}
20 changes: 20 additions & 0 deletions src/Factory/Options/JMSSerializerOptionsFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Detail\Normalization\Factory\Options;

use Interop\Container\ContainerInterface;

use Detail\Normalization\Options\JMSSerializerOptions;

/**
* @method JMSSerializerOptions __invoke(ContainerInterface $container, $requestedName, array $options = null)
*/
class JMSSerializerOptionsFactory extends RootOptionsFactory
{
const OPTION = 'jms_serializer';

protected function getOptionsClass(): string
{
return JMSSerializerOptions::CLASS;
}
}
24 changes: 6 additions & 18 deletions src/Factory/Options/ModuleOptionsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,17 @@

use Interop\Container\ContainerInterface;

use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Factory\FactoryInterface;

use Detail\Normalization\Options\ModuleOptions;

class ModuleOptionsFactory implements FactoryInterface
/**
* @method ModuleOptions __invoke(ContainerInterface $container, $requestedName, array $options = null)
*/
class ModuleOptionsFactory extends RootOptionsFactory
{
const OPTION = 'detail_normalization';

/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
* @return ModuleOptions
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
protected function getOptionsClass(): string
{
$config = $container->get('Config');

if (!isset($config[self::OPTION])) {
throw new ServiceNotCreatedException(sprintf('Missing config option "%s"', self::OPTION));
}

return new ModuleOptions($config[self::OPTION]);
return ModuleOptions::CLASS;
}
}
38 changes: 38 additions & 0 deletions src/Factory/Options/RootOptionsFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Detail\Normalization\Factory\Options;

use Interop\Container\ContainerInterface;

use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\Stdlib\AbstractOptions;

abstract class RootOptionsFactory implements
FactoryInterface
{
const OPTION = null;

/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
* @return AbstractOptions
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$config = $container->get('Config');

if (!isset($config[static::OPTION])) {
throw new ServiceNotCreatedException(sprintf('Missing config option "%s"', static::OPTION));
}

$optionsClass = $this->getOptionsClass();

/** @todo Check if class exists */

return new $optionsClass($config[static::OPTION]);
}

abstract protected function getOptionsClass(): string;
}
Loading

0 comments on commit 48d5455

Please sign in to comment.