[DoctrineMongoDBBundle] Initial use of the new Configuration class for DoctrineMongoDBExtension.
This commit is contained in:
parent
94da3127b9
commit
a13500459f
@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Bundle\DoctrineMongoDBBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
|
||||
/**
|
||||
* FrameworkExtension configuration structure.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@thatsquality.com>
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
/**
|
||||
* Generates the configuration tree.
|
||||
*
|
||||
* @param boolean $kernelDebug The kernel.debug DIC parameter
|
||||
* @return \Symfony\Component\DependencyInjection\Configuration\NodeInterface
|
||||
*/
|
||||
public function getConfigTree()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder();
|
||||
$rootNode = $treeBuilder->root('doctrinemongodb', 'array');
|
||||
|
||||
$this->addSingleDocumentManagerSection($rootNode);
|
||||
$this->addDocumentManagersSection($rootNode);
|
||||
$this->addSingleConnectionSection($rootNode);
|
||||
$this->addConnectionsSection($rootNode);
|
||||
|
||||
$rootNode
|
||||
->scalarNode('proxy_namespace')->defaultValue(null)->end()
|
||||
->scalarNode('auto_generate_proxy_classes')->defaultValue(null)->end()
|
||||
->scalarNode('hydrator_namespace')->defaultValue(null)->end()
|
||||
->scalarNode('auto_generate_hydrator_classes')->defaultValue(null)->end()
|
||||
;
|
||||
|
||||
return $treeBuilder->buildTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the nodes responsible for the config that supports the single
|
||||
* document manager.
|
||||
*/
|
||||
private function addSingleDocumentManagerSection(NodeBuilder $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->scalarNode('default_document_manager')->defaultValue('default')->end()
|
||||
->scalarNode('default_database')->defaultValue('default')->end()
|
||||
->builder($this->getMetadataCacheDriverNode())
|
||||
->fixXmlConfig('mapping')
|
||||
->builder($this->getMappingsNode())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the "document_managers" section
|
||||
*/
|
||||
private function addDocumentManagersSection(NodeBuilder $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->fixXmlConfig('document_manager')
|
||||
->arrayNode('document_managers')
|
||||
->useAttributeAsKey('id')
|
||||
->prototype('array')
|
||||
->performNoDeepMerging()
|
||||
->treatNullLike(array())
|
||||
->builder($this->getMetadataCacheDriverNode())
|
||||
->scalarNode('default_database')->end()
|
||||
->scalarNode('connection')->end()
|
||||
->scalarNode('database')->end()
|
||||
->fixXmlConfig('mapping')
|
||||
->builder($this->getMappingsNode())
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the single-connection section:
|
||||
* * default_connection
|
||||
* * server
|
||||
* * options
|
||||
*/
|
||||
private function addSingleConnectionSection(NodeBuilder $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->scalarNode('default_connection')->defaultValue('default')->end()
|
||||
->builder($this->addConnectionServerNode())
|
||||
->builder($this->addConnectionOptionsNode())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the configuration for the "connections" key
|
||||
*/
|
||||
private function addConnectionsSection(NodeBuilder $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->fixXmlConfig('connection')
|
||||
->arrayNode('connections')
|
||||
->useAttributeAsKey('id')
|
||||
->prototype('array')
|
||||
->performNoDeepMerging()
|
||||
->builder($this->addConnectionServerNode())
|
||||
->builder($this->addConnectionOptionsNode())
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array node used for "mappings".
|
||||
*
|
||||
* This is used in two different parts of the tree.
|
||||
*
|
||||
* @param NodeBuilder $rootNode The parent node
|
||||
* @return NodeBuilder
|
||||
*/
|
||||
protected function getMappingsNode()
|
||||
{
|
||||
$node = new Nodebuilder('mappings', 'array');
|
||||
$node
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
// I believe that "null" should *not* set the type
|
||||
// it's guessed in AbstractDoctrineExtension::detectMetadataDriver
|
||||
->treatNullLike(array())
|
||||
->beforeNormalization()
|
||||
// if it's not an array, then the scalar is the type key
|
||||
->ifTrue(function($v) { return !is_array($v); })
|
||||
->then(function($v){ return array('type' => $v); })
|
||||
->end()
|
||||
->scalarNode('type')->end()
|
||||
->scalarNode('dir')->end()
|
||||
->scalarNode('prefix')->end()
|
||||
->scalarNode('alias')->end()
|
||||
->performNoDeepMerging()
|
||||
->end()
|
||||
;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the NodeBuilder for the "server" key of a connection.
|
||||
*/
|
||||
private function addConnectionServerNode()
|
||||
{
|
||||
$node = new NodeBuilder('server', 'scalar');
|
||||
|
||||
$node
|
||||
->defaultValue(null)
|
||||
->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the NodeBuilder for the "options" key of a connection.
|
||||
*/
|
||||
private function addConnectionOptionsNode()
|
||||
{
|
||||
$node = new NodeBuilder('options', 'array');
|
||||
|
||||
$node
|
||||
->performNoDeepMerging()
|
||||
->addDefaultsIfNotSet() // adds an empty array of omitted
|
||||
|
||||
// options go into the Mongo constructor
|
||||
// http://www.php.net/manual/en/mongo.construct.php
|
||||
->booleanNode('connect')->end()
|
||||
->scalarNode('persist')->end()
|
||||
->scalarNode('timeout')->end()
|
||||
->booleanNode('replicaSet')->end()
|
||||
->scalarNode('username')->end()
|
||||
->scalarNode('password')->end()
|
||||
->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getMetadataCacheDriverNode()
|
||||
{
|
||||
$node = new NodeBuilder('metadata_cache_driver', 'array');
|
||||
|
||||
$node
|
||||
->beforeNormalization()
|
||||
// if scalar
|
||||
->ifTrue(function($v) { return !is_array($v); })
|
||||
->then(function($v) { return array('type' => $v); })
|
||||
->end()
|
||||
->scalarNode('type')->end()
|
||||
->scalarNode('class')->end()
|
||||
->scalarNode('host')->end()
|
||||
->scalarNode('port')->end()
|
||||
->scalarNode('instance_class')->end()
|
||||
->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Bundle\DoctrineAbstractBundle\DependencyInjection\AbstractDoctrineExtension;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
/**
|
||||
* Doctrine MongoDB ODM extension.
|
||||
@ -60,23 +61,13 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
foreach ($configs as $config) {
|
||||
$this->doMongodbLoad($config, $container);
|
||||
}
|
||||
}
|
||||
// Load DoctrineMongoDBBundle/Resources/config/mongodb.xml
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('mongodb.xml');
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration();
|
||||
$config = $processor->process($configuration->getConfigTree(), $configs);
|
||||
|
||||
/**
|
||||
* Loads the MongoDB ODM configuration.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* <doctrine:mongodb server="mongodb://localhost:27017" />
|
||||
*
|
||||
* @param array $config An array of configuration settings
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*/
|
||||
protected function doMongodbLoad($config, ContainerBuilder $container)
|
||||
{
|
||||
$this->loadDefaults($config, $container);
|
||||
$this->loadConnections($config, $container);
|
||||
$this->loadDocumentManagers($config, $container);
|
||||
@ -91,17 +82,10 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
*/
|
||||
protected function loadDefaults(array $config, ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('doctrine.odm.mongodb.metadata.annotation')) {
|
||||
// Load DoctrineMongoDBBundle/Resources/config/mongodb.xml
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('mongodb.xml');
|
||||
}
|
||||
|
||||
// Allow these application configuration options to override the defaults
|
||||
$options = array(
|
||||
'default_document_manager',
|
||||
'default_connection',
|
||||
'metadata_cache_driver',
|
||||
'proxy_namespace',
|
||||
'auto_generate_proxy_classes',
|
||||
'hydrator_namespace',
|
||||
@ -112,11 +96,10 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
if (isset($config[$key])) {
|
||||
$container->setParameter('doctrine.odm.mongodb.'.$key, $config[$key]);
|
||||
}
|
||||
|
||||
$nKey = str_replace('_', '-', $key);
|
||||
if (isset($config[$nKey])) {
|
||||
$container->setParameter('doctrine.odm.mongodb.'.$key, $config[$nKey]);
|
||||
}
|
||||
|
||||
if (isset($config['metadata_cache_driver'])) {
|
||||
$container->setParameter('doctrine.odm.mongodb.metadata_cache_driver', $config['metadata_cache_driver']['type']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,11 +205,7 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
|
||||
$documentManagers = array();
|
||||
|
||||
if (isset($config['document-managers'])) {
|
||||
$config['document_managers'] = $config['document-managers'];
|
||||
}
|
||||
|
||||
if (isset($config['document_managers'])) {
|
||||
if (count($config['document_managers'])) {
|
||||
$configDocumentManagers = $config['document_managers'];
|
||||
|
||||
if (isset($config['document_managers']['document-manager'])) {
|
||||
@ -255,8 +234,8 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
protected function loadDocumentManagerMetadataCacheDriver(array $documentManager, ContainerBuilder $container)
|
||||
{
|
||||
$metadataCacheDriver = $container->getParameter('doctrine.odm.mongodb.metadata_cache_driver');
|
||||
$dmMetadataCacheDriver = isset($documentManager['metadata-cache-driver']) ? $documentManager['metadata-cache-driver'] : (isset($documentManager['metadata_cache_driver']) ? $documentManager['metadata_cache_driver'] : $metadataCacheDriver);
|
||||
$type = is_array($dmMetadataCacheDriver) && isset($dmMetadataCacheDriver['type']) ? $dmMetadataCacheDriver['type'] : $dmMetadataCacheDriver;
|
||||
$dmMetadataCacheDriver = isset($documentManager['metadata_cache_driver']) ? $documentManager['metadata_cache_driver'] : $metadataCacheDriver;
|
||||
$type = is_array($dmMetadataCacheDriver) ? $dmMetadataCacheDriver['type'] : $dmMetadataCacheDriver;
|
||||
|
||||
if ('memcache' === $type) {
|
||||
$memcacheClass = isset($dmMetadataCacheDriver['class']) ? $dmMetadataCacheDriver['class'] : sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type);
|
||||
@ -271,6 +250,7 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
} else {
|
||||
$cacheDef = new Definition(sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type));
|
||||
}
|
||||
|
||||
$container->setDefinition(sprintf('doctrine.odm.mongodb.%s_metadata_cache', $documentManager['name']), $cacheDef);
|
||||
}
|
||||
|
||||
@ -305,7 +285,7 @@ class DoctrineMongoDBExtension extends AbstractDoctrineExtension
|
||||
$defaultConnection = $container->getParameter('doctrine.odm.mongodb.default_connection');
|
||||
|
||||
$connections = array();
|
||||
if (isset($config['connections'])) {
|
||||
if (count($config['connections'])) {
|
||||
$configConnections = $config['connections'];
|
||||
if (isset($config['connections']['connection']) && isset($config['connections']['connection'][0])) {
|
||||
// Multiple connections
|
||||
|
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\DoctrineMongoDBBundle\Tests\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Bundle\DoctrineMongoDBBundle\DependencyInjection\Configuration;
|
||||
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider optionProvider
|
||||
* @param array $configs The source array of configuration arrays
|
||||
* @param array $correctValues A key-value pair of end values to check
|
||||
*/
|
||||
public function testMergeOptions(array $configs, array $correctValues)
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration();
|
||||
$options = $processor->process($configuration->getConfigTree(), $configs);
|
||||
|
||||
foreach ($correctValues as $key => $correctVal)
|
||||
{
|
||||
$this->assertEquals($correctVal, $options[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
public function optionProvider()
|
||||
{
|
||||
$cases = array();
|
||||
|
||||
// single config, testing normal option setting
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('default_document_manager' => 'foo'),
|
||||
),
|
||||
array('default_document_manager' => 'foo')
|
||||
);
|
||||
|
||||
// single config, testing normal option setting with dashes
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('default-document-manager' => 'bar'),
|
||||
),
|
||||
array('default_document_manager' => 'bar')
|
||||
);
|
||||
|
||||
// testing the normal override merging - the later config array wins
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('default_document_manager' => 'foo'),
|
||||
array('default_document_manager' => 'baz'),
|
||||
),
|
||||
array('default_document_manager' => 'baz')
|
||||
);
|
||||
|
||||
// the "options" array is totally replaced
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('options' => array('timeout' => 2000)),
|
||||
array('options' => array('username' => 'foo')),
|
||||
),
|
||||
array('options' => array('username' => 'foo')),
|
||||
);
|
||||
|
||||
// mappings are merged non-recursively.
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('mappings' => array('foomap' => array('type' => 'val1'), 'barmap' => array('dir' => 'val2'))),
|
||||
array('mappings' => array('barmap' => array('prefix' => 'val3'))),
|
||||
),
|
||||
array('mappings' => array('foomap' => array('type' => 'val1'), 'barmap' => array('prefix' => 'val3'))),
|
||||
);
|
||||
|
||||
// connections are merged non-recursively.
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('connections' => array('foocon' => array('server' => 'val1'), 'barcon' => array('options' => array('username' => 'val2')))),
|
||||
array('connections' => array('barcon' => array('server' => 'val3'))),
|
||||
),
|
||||
array('connections' => array(
|
||||
'foocon' => array('server' => 'val1', 'options' => array()),
|
||||
'barcon' => array('server' => 'val3', 'options' => array())
|
||||
)),
|
||||
);
|
||||
|
||||
// managers are merged non-recursively.
|
||||
$cases[] = array(
|
||||
array(
|
||||
array('document_managers' => array('foodm' => array('database' => 'val1'), 'bardm' => array('default_database' => 'val2'))),
|
||||
array('document_managers' => array('bardm' => array('database' => 'val3'))),
|
||||
),
|
||||
array('document_managers' => array(
|
||||
'foodm' => array('database' => 'val1', 'mappings' => array()),
|
||||
'bardm' => array('database' => 'val3', 'mappings' => array()),
|
||||
)),
|
||||
);
|
||||
|
||||
return $cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNormalizationTests
|
||||
*/
|
||||
public function testNormalizeOptions(array $config, $targetKey, array $normalized)
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration();
|
||||
$options = $processor->process($configuration->getConfigTree(), array($config));
|
||||
$this->assertSame($normalized, $options[$targetKey]);
|
||||
}
|
||||
|
||||
public function getNormalizationTests()
|
||||
{
|
||||
return array(
|
||||
// connection versus connections (id is the identifier)
|
||||
array(
|
||||
array('connection' => array(
|
||||
array('server' => 'mongodb://abc', 'id' => 'foo'),
|
||||
array('server' => 'mongodb://def', 'id' => 'bar'),
|
||||
)),
|
||||
'connections',
|
||||
array(
|
||||
'foo' => array('server' => 'mongodb://abc', 'options' => array()),
|
||||
'bar' => array('server' => 'mongodb://def', 'options' => array()),
|
||||
),
|
||||
),
|
||||
// document_manager versus document_managers (id is the identifier)
|
||||
array(
|
||||
array('document_manager' => array(
|
||||
array('connection' => 'conn1', 'id' => 'foo'),
|
||||
array('connection' => 'conn2', 'id' => 'bar'),
|
||||
)),
|
||||
'document_managers',
|
||||
array(
|
||||
'foo' => array('connection' => 'conn1', 'mappings' => array()),
|
||||
'bar' => array('connection' => 'conn2', 'mappings' => array()),
|
||||
),
|
||||
),
|
||||
// mapping versus mappings (name is the identifier)
|
||||
array(
|
||||
array('mapping' => array(
|
||||
array('type' => 'yml', 'name' => 'foo'),
|
||||
array('type' => 'xml', 'name' => 'bar'),
|
||||
)),
|
||||
'mappings',
|
||||
array(
|
||||
'foo' => array('type' => 'yml'),
|
||||
'bar' => array('type' => 'xml'),
|
||||
),
|
||||
),
|
||||
// mapping configuration that's beneath a specific document manager
|
||||
array(
|
||||
array('document_manager' => array(
|
||||
array('id' => 'foo', 'connection' => 'conn1', 'mapping' => array(
|
||||
'type' => 'xml', 'name' => 'foo-mapping'
|
||||
)),
|
||||
)),
|
||||
'document_managers',
|
||||
array(
|
||||
'foo' => array('connection' => 'conn1', 'mappings' => array(
|
||||
'foo-mapping' => array('type' => 'xml'),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\DoctrineMongoDBBundle\Tests\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Bundle\DoctrineMongoDBBundle\DependencyInjection\DoctrineMongoDBExtension;
|
||||
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
class DoctrineMongoDBExtensionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider parameterProvider
|
||||
*/
|
||||
public function testParameterOverride($option, $parameter, $value)
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new DoctrineMongoDBExtension();
|
||||
$loader->load(array(array($option => $value)), $container);
|
||||
|
||||
$this->assertEquals($value, $container->getParameter('doctrine.odm.mongodb.'.$parameter));
|
||||
}
|
||||
|
||||
public function parameterProvider()
|
||||
{
|
||||
return array(
|
||||
array('proxy_namespace', 'proxy_namespace', 'foo'),
|
||||
array('proxy-namespace', 'proxy_namespace', 'bar'),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user