feature #21924 [FrameworkBundle] Allow to configure Serializer mapping paths (chalasr)
This PR was merged into the 3.3-dev branch.
Discussion
----------
[FrameworkBundle] Allow to configure Serializer mapping paths
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #21187
| License | MIT
| Doc PR | todo
Follows https://github.com/symfony/symfony/pull/19086 for the Serializer
Commits
-------
5446903296
[FrameworkBundle] Allow configuring serializer mapping paths
This commit is contained in:
commit
3023e4b707
@ -37,6 +37,8 @@ CHANGELOG
|
||||
`Symfony\Bundle\WebServerBundle\WebServerBundle` in your AppKernel to use them.
|
||||
* Added `$defaultLocale` as 3rd argument of `Translator::__construct()`
|
||||
making `Translator` works with any PSR-11 container
|
||||
* Added `framework.serializer.mapping` config option allowing to define custom
|
||||
serialization mapping files and directories
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
@ -687,6 +687,15 @@ class Configuration implements ConfigurationInterface
|
||||
->scalarNode('cache')->end()
|
||||
->scalarNode('name_converter')->end()
|
||||
->scalarNode('circular_reference_handler')->end()
|
||||
->arrayNode('mapping')
|
||||
->addDefaultsIfNotSet()
|
||||
->fixXmlConfig('path')
|
||||
->children()
|
||||
->arrayNode('paths')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
@ -986,8 +986,7 @@ class FrameworkExtension extends Extension
|
||||
$container->setParameter('validator.translation_domain', $config['translation_domain']);
|
||||
|
||||
$files = array('xml' => array(), 'yml' => array());
|
||||
$this->getValidatorMappingFiles($container, $files);
|
||||
$this->getValidatorMappingFilesFromConfig($container, $config, $files);
|
||||
$this->registerValidatorMapping($container, $config, $files);
|
||||
|
||||
if (!empty($files['xml'])) {
|
||||
$validatorBuilder->addMethodCall('addXmlMappings', array($files['xml']));
|
||||
@ -1028,51 +1027,54 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
private function getValidatorMappingFiles(ContainerBuilder $container, array &$files)
|
||||
private function registerValidatorMapping(ContainerBuilder $container, array $config, array &$files)
|
||||
{
|
||||
$fileRecorder = function ($extension, $path) use (&$files) {
|
||||
$files['yaml' === $extension ? 'yml' : $extension][] = $path;
|
||||
};
|
||||
|
||||
if (interface_exists('Symfony\Component\Form\FormInterface')) {
|
||||
$reflClass = new \ReflectionClass('Symfony\Component\Form\FormInterface');
|
||||
$files['xml'][] = dirname($reflClass->getFileName()).'/Resources/config/validation.xml';
|
||||
$fileRecorder('xml', dirname($reflClass->getFileName()).'/Resources/config/validation.xml');
|
||||
}
|
||||
|
||||
foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
|
||||
$dirname = $bundle['path'];
|
||||
|
||||
if ($container->fileExists($file = $dirname.'/Resources/config/validation.yml', false)) {
|
||||
$files['yml'][] = $file;
|
||||
$fileRecorder('yml', $file);
|
||||
}
|
||||
|
||||
if ($container->fileExists($file = $dirname.'/Resources/config/validation.xml', false)) {
|
||||
$files['xml'][] = $file;
|
||||
$fileRecorder('xml', $file);
|
||||
}
|
||||
|
||||
if ($container->fileExists($dir = $dirname.'/Resources/config/validation', '/^$/')) {
|
||||
$this->getValidatorMappingFilesFromDir($dir, $files);
|
||||
$this->registerMappingFilesFromDir($dir, $fileRecorder);
|
||||
}
|
||||
}
|
||||
|
||||
$this->registerMappingFilesFromConfig($container, $config, $fileRecorder);
|
||||
}
|
||||
|
||||
private function getValidatorMappingFilesFromDir($dir, array &$files)
|
||||
private function registerMappingFilesFromDir($dir, callable $fileRecorder)
|
||||
{
|
||||
foreach (Finder::create()->followLinks()->files()->in($dir)->name('/\.(xml|ya?ml)$/') as $file) {
|
||||
$extension = $file->getExtension();
|
||||
$files['yaml' === $extension ? 'yml' : $extension][] = $file->getRealpath();
|
||||
$fileRecorder($file->getExtension(), $file->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
private function getValidatorMappingFilesFromConfig(ContainerBuilder $container, array $config, array &$files)
|
||||
private function registerMappingFilesFromConfig(ContainerBuilder $container, array $config, callable $fileRecorder)
|
||||
{
|
||||
foreach ($config['mapping']['paths'] as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->getValidatorMappingFilesFromDir($path, $files);
|
||||
$this->registerMappingFilesFromDir($path, $fileRecorder);
|
||||
$container->addResource(new DirectoryResource($path, '/^$/'));
|
||||
} elseif ($container->fileExists($path, false)) {
|
||||
if (preg_match('/\.(xml|ya?ml)$/', $path, $matches)) {
|
||||
$extension = $matches[1];
|
||||
$files['yaml' === $extension ? 'yml' : $extension][] = $path;
|
||||
} else {
|
||||
if (!preg_match('/\.(xml|ya?ml)$/', $path, $matches)) {
|
||||
throw new \RuntimeException(sprintf('Unsupported mapping type in "%s", supported types are XML & Yaml.', $path));
|
||||
}
|
||||
$fileRecorder($matches[1], $path);
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Could not open file or directory "%s".', $path));
|
||||
}
|
||||
@ -1230,39 +1232,30 @@ class FrameworkExtension extends Extension
|
||||
$serializerLoaders[] = $annotationLoader;
|
||||
}
|
||||
|
||||
$fileRecorder = function ($extension, $path) use (&$serializerLoaders) {
|
||||
$definition = new Definition(in_array($extension, array('yaml', 'yml')) ? 'Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader' : 'Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array($path));
|
||||
$definition->setPublic(false);
|
||||
$serializerLoaders[] = $definition;
|
||||
};
|
||||
|
||||
foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
|
||||
$dirname = $bundle['path'];
|
||||
|
||||
if ($container->fileExists($file = $dirname.'/Resources/config/serialization.xml', false)) {
|
||||
$definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array($file));
|
||||
$definition->setPublic(false);
|
||||
|
||||
$serializerLoaders[] = $definition;
|
||||
$fileRecorder('xml', $file);
|
||||
}
|
||||
|
||||
if ($container->fileExists($file = $dirname.'/Resources/config/serialization.yml', false)) {
|
||||
$definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader', array($file));
|
||||
$definition->setPublic(false);
|
||||
|
||||
$serializerLoaders[] = $definition;
|
||||
$fileRecorder('yml', $file);
|
||||
}
|
||||
|
||||
if ($container->fileExists($dir = $dirname.'/Resources/config/serialization')) {
|
||||
foreach (Finder::create()->followLinks()->files()->in($dir)->name('*.xml') as $file) {
|
||||
$definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array($file->getPathname()));
|
||||
$definition->setPublic(false);
|
||||
|
||||
$serializerLoaders[] = $definition;
|
||||
}
|
||||
foreach (Finder::create()->followLinks()->files()->in($dir)->name('*.yml') as $file) {
|
||||
$definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader', array($file->getPathname()));
|
||||
$definition->setPublic(false);
|
||||
|
||||
$serializerLoaders[] = $definition;
|
||||
}
|
||||
$this->registerMappingFilesFromDir($dir, $fileRecorder);
|
||||
}
|
||||
}
|
||||
|
||||
$this->registerMappingFilesFromConfig($container, $config, $fileRecorder);
|
||||
|
||||
$chainLoader->replaceArgument(0, $serializerLoaders);
|
||||
$container->getDefinition('serializer.mapping.cache_warmer')->replaceArgument(0, $serializerLoaders);
|
||||
|
||||
|
@ -176,7 +176,7 @@
|
||||
<xsd:complexType name="validation">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="static-method" type="xsd:string" />
|
||||
<xsd:element name="mapping" type="validation_mapping" />
|
||||
<xsd:element name="mapping" type="file_mapping" />
|
||||
</xsd:choice>
|
||||
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
@ -185,7 +185,7 @@
|
||||
<xsd:attribute name="static-method" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="validation_mapping">
|
||||
<xsd:complexType name="file_mapping">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="path" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
@ -204,6 +204,9 @@
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="serializer">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="mapping" type="file_mapping" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
<xsd:attribute name="cache" type="xsd:string" />
|
||||
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
|
||||
|
@ -226,6 +226,7 @@ class ConfigurationTest extends TestCase
|
||||
'serializer' => array(
|
||||
'enabled' => !class_exists(FullStack::class),
|
||||
'enable_annotations' => !class_exists(FullStack::class),
|
||||
'mapping' => array('paths' => array()),
|
||||
),
|
||||
'property_access' => array(
|
||||
'magic_call' => false,
|
||||
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
$container->loadFromExtension('framework', array(
|
||||
'annotations' => array('enabled' => true),
|
||||
'serializer' => array(
|
||||
'enable_annotations' => true,
|
||||
'mapping' => array(
|
||||
'paths' => array(
|
||||
'%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files',
|
||||
'%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml',
|
||||
'%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:framework="http://symfony.com/schema/dic/symfony">
|
||||
|
||||
<framework:config>
|
||||
<framework:annotations enabled="true" />
|
||||
<framework:serializer enable-annotations="true">
|
||||
<framework:mapping>
|
||||
<framework:path>%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files</framework:path>
|
||||
<framework:path>%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml</framework:path>
|
||||
<framework:path>%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml</framework:path>
|
||||
</framework:mapping>
|
||||
</framework:serializer>
|
||||
</framework:config>
|
||||
</container>
|
@ -0,0 +1,10 @@
|
||||
framework:
|
||||
annotations:
|
||||
enabled: true
|
||||
serializer:
|
||||
enable_annotations: true
|
||||
mapping:
|
||||
paths:
|
||||
- "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files"
|
||||
- "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml"
|
||||
- "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml"
|
@ -28,10 +28,12 @@ use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessor;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
|
||||
@ -800,6 +802,28 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
$this->assertEquals(new Reference('foo'), $cache);
|
||||
}
|
||||
|
||||
public function testSerializerMapping()
|
||||
{
|
||||
$container = $this->createContainerFromFile('serializer_mapping', array('kernel.bundles_metadata' => array('TestBundle' => array('namespace' => 'Symfony\\Bundle\\FrameworkBundle\\Tests', 'path' => __DIR__.'/Fixtures/TestBundle', 'parent' => null))));
|
||||
$configDir = __DIR__.'/Fixtures/TestBundle/Resources/config';
|
||||
$expectedLoaders = array(
|
||||
new Definition(AnnotationLoader::class, array(new Reference('annotation_reader'))),
|
||||
new Definition(XmlFileLoader::class, array($configDir.'/serialization.xml')),
|
||||
new Definition(YamlFileLoader::class, array($configDir.'/serialization.yml')),
|
||||
new Definition(XmlFileLoader::class, array($configDir.'/serializer_mapping/files/foo.xml')),
|
||||
new Definition(YamlFileLoader::class, array($configDir.'/serializer_mapping/files/foo.yml')),
|
||||
new Definition(YamlFileLoader::class, array($configDir.'/serializer_mapping/serialization.yml')),
|
||||
new Definition(YamlFileLoader::class, array($configDir.'/serializer_mapping/serialization.yaml')),
|
||||
);
|
||||
|
||||
foreach ($expectedLoaders as $definition) {
|
||||
$definition->setPublic(false);
|
||||
}
|
||||
|
||||
$loaders = $container->getDefinition('serializer.mapping.chain_loader')->getArgument(0);
|
||||
$this->assertEquals(sort($expectedLoaders), sort($loaders));
|
||||
}
|
||||
|
||||
public function testAssetHelperWhenAssetsAreEnabled()
|
||||
{
|
||||
$container = $this->createContainerFromFile('full');
|
||||
|
Reference in New Issue
Block a user