Initial commit

This commit is contained in:
Antoine Hérault
2011-05-08 23:04:37 +02:00
commit ae7440f4d7
22 changed files with 1019 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Compiler pass that registers the adapter factories
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class AdapterFactoryManagerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('knplabs_gaufrette.adapter_factory_manager')) {
return;
}
$definition = $container->getDefinition('knplabs_gaufrette.adapter_factory_manager');
$calls = $definition->getMethodCalls();
$definition->setMethodCalls(array());
foreach ($container->findTaggedServiceIds('gaufrette.adapter_factory') as $id => $attributes) {
if (!empty($attributes['type'])) {
$definition->addMethodCall('set', array($attributes['type'], new Reference($id)));
}
}
$definition->setMethodCalls(array_merge($definition->getMethodCalls(), $calls));
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Compiler pass that registers the adapters
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class AdapterManagerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('knplabs_gaufrette.adapter_manager')) {
return;
}
$definition = $container->getDefinition('knplabs_gaufrette.adapter_manager');
$calls = $definition->getMethodCalls();
$definition->setMethodCalls(array());
foreach ($container->findTaggedServiceIds('gaufrette.adapter') as $id => $attributes) {
if (!empty($attributes['alias'])) {
$definition->addMethodCall('set', array($attributes['alias'], new Reference($id)));
}
}
$definition->setMethodCalls(array_merge($definition->getMethodCalls(), $calls));
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Interface that must be implemented by the adapater factories
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
interface AdapterFactoryInterface
{
/**
* Creates the adapter, registers it and returns its id
*
* @param ContainerBuilder $container
* @param string $id
* @param array $config
*
* @return string The Adapter service id in the DIC
*/
function create(ContainerBuilder $container, $id, array $config);
/**
* Returns the key for the factory configuration
*
* @return string
*/
function getKey();
/**
* Adds configuration nodes for the factory
*
* @param NodeBuilder $builder
*/
function addConfiguration(NodeDefinition $builder);
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
/**
* In memory adapter factory
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class InMemoryAdapterFactory implements AdapterFactoryInterface
{
/**
* {@inheritDoc}
*/
public function create(ContainerBuilder $container, $id, array $config)
{
$adapter = sprintf('knplabs_gaufrette.adapter.local.%s', $id);
$container
->setDefinition($adapter, new DefinitionDecorator('knplabs_gaufrette.adapter.in_memory'))
->replaceArgument(0, $config['files'])
;
return $adapter;
}
/**
* {@inheritDoc}
*/
public function getKey()
{
return 'in_memory';
}
/**
* {@inheritDoc}
*/
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->arrayNode('files')
->fixXmlConfig('file')
->useAttributeAsKey('filename')
->prototype('array')
->children()
->scalarNode('content')->end()
->scalarNode('checksum')->end()
->scalarNode('mtime')->end()
->end()
->end()
->end()
->end()
;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
/**
* Local adapter factory
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class LocalAdapterFactory implements AdapterFactoryInterface
{
/**
* {@inheritDoc}
*/
public function create(ContainerBuilder $container, $id, array $config)
{
$adapter = sprintf('knplabs_gaufrette.adapter.local.%s', $id);
$container
->setDefinition($adapter, new DefinitionDecorator('knplabs_gaufrette.adapter.local'))
->replaceArgument(0, $config['directory'])
->replaceArgument(1, $config['create'])
;
return $adapter;
}
/**
* {@inheritDoc}
*/
public function getKey()
{
return 'local';
}
/**
* {@inheritDoc}
*/
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('directory')->isRequired()->end()
->booleanNode('create')->defaultTrue()->end()
->end()
;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
/**
* Safe local adapter factory
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class SafeLocalAdapterFactory implements AdapterFactoryInterface
{
/**
* {@inheritDoc}
*/
public function create(ContainerBuilder $container, $id, array $config)
{
$adapter = sprintf('knplabs_gaufrette.adapter.safe_local.%s', $id);
$container
->setDefinition($adapter, new DefinitionDecorator('knplabs_gaufrette.adapter.safe_local'))
->replaceArgument(0, $config['directory'])
->replaceArgument(1, $config['create'])
;
return $adapter;
}
/**
* {@inheritDoc}
*/
public function getKey()
{
return 'safe-local';
}
/**
* {@inheritDoc}
*/
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('directory')->isRequired()->end()
->booleanNode('create')->defaultTrue()->end()
->end()
;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Service adapter factory
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class ServiceAdapterFactory implements AdapterFactoryInterface
{
/**
* {@inheritDoc}
*/
public function create(ContainerBuilder $container, $id, array $config)
{
return $config['id'];
}
/**
* {@inheritDoc}
*/
public function getKey()
{
return 'service';
}
/**
* {@inheritDoc}
*/
public function addConfiguration(NodeDefinition $builder)
{
$builder
->children()
->scalarNode('id')->isRequired()->end()
->end()
;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* Factory configuration for the Gaufrette DIC extension
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class FactoryConfiguration implements ConfigurationInterface
{
/**
* Generates the configuration tree builder
*
* @return TreeBuilder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$treeBuilder
->root('knplabs_gaufrette')
->ignoreExtraKeys()
->fixXmlConfig('factory', 'factories')
->children()
->arrayNode('factories')
->prototype('scalar')->end()
->end()
->end()
->end()
;
return $treeBuilder;
}
}

View File

@@ -0,0 +1,117 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
* The Gaufrette DIC extension
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class KnplabsGaufretteExtension extends Extension
{
private $factories = null;
/**
* Loads the extension
*
* @param array $configs
* @param ContainerBuilder $container
*/
public function load(array $configs, ContainerBuilder $container)
{
$processor = new Processor();
// first assemble the adapter factories
$factoryConfig = new FactoryConfiguration();
$config = $processor->processConfiguration($factoryConfig, $configs);
$factories = $this->createAdapterFactories($config, $container);
// then normalize the configs
$mainConfig = new MainConfiguration($factories);
$config = $processor->processConfiguration($mainConfig, $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('gaufrette.xml');
foreach ($config['adapters'] as $name => $adapter) {
$adapters[$name] = $this->createAdapter($name, $adapter, $container, $factories);
}
foreach ($config['filesystems'] as $name => $filesystem) {
$this->createFilesystem($name, $filesystem, $container, $adapters);
}
}
private function createAdapter($name, array $config, ContainerBuilder $container, array $factories)
{
$adapter = null;
foreach ($config as $key => $adapter) {
if (array_key_exists($key, $factories)) {
return $factories[$key]->create($container, $name, $adapter);
}
}
throw new \LogicException(sprintf('The adapter \'%s\' is not configured.', $name));
}
private function createFilesystem($name, array $config, ContainerBuilder $container, array $adapters)
{
if (!array_key_exists($config['adapter'], $adapters)) {
throw new \LogicException(sprintf('The adapter \'%s\' is not defined.', $config['adapter']));
}
$adapter = $adapters[$config['adapter']];
$id = sprintf('gaufrette.%s_filesystem', $name);
$container
->setDefinition($id, new DefinitionDecorator('knplabs_gaufrette.filesystem'))
->replaceArgument(0, new Reference($adapter))
;
if (!empty($config['alias'])) {
$container->setAlias($config['alias'], $id);
}
}
/**
* Creates the adapter factories
*
* @param array $config
* @param ContainerBuilder $container
*/
private function createAdapterFactories($config, ContainerBuilder $container)
{
if (null !== $this->factories) {
return $this->factories;
}
// load bundled adapter factories
$tempContainer = new ContainerBuilder();
$parameterBag = $container->getParameterBag();
$loader = new XmlFileLoader($tempContainer, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('adapter_factories.xml');
// load user-created adapter factories
foreach ($config['factories'] as $factory) {
$loader->load($parameterBag->resolveValue($factory));
}
$services = $tempContainer->findTaggedServiceIds('gaufrette.adapter.factory');
$factories = array();
foreach (array_keys($services) as $id) {
$factory = $tempContainer->get($id);
$factories[str_replace('-', '_', $factory->getKey())] = $factory;
}
return $this->factories = $factories;
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace Knplabs\Bundle\GaufretteBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* Main configuration for the Gaufrette DIC extension
*
* @author Antoine Hérault <antoine.herault@gmail.com>
*/
class MainConfiguration implements ConfigurationInterface
{
private $factories;
/**
* Constructor
*
* @param array $factories
*/
public function __construct(array $factories)
{
$this->factories = $factories;
}
/**
* Generates the configuration tree builder
*
* @return TreeBuilder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('knplabs_gaufrette');
$this->addAdaptersSection($rootNode, $this->factories);
$this->addFilesystemsSection($rootNode);
$rootNode
// add a faux-entry for factories, so that no validation error is thrown
->fixXmlConfig('factory', 'factories')
->children()
->arrayNode('factories')->ignoreExtraKeys()->end()
->end()
;
return $treeBuilder;
}
private function addAdaptersSection(ArrayNodeDefinition $node, array $factories)
{
$adapterNodeBuilder = $node
->fixXmlConfig('adapter')
->children()
->arrayNode('adapters')
->useAttributeAsKey('name')
->prototype('array')
->performNoDeepMerging()
->children()
;
foreach ($factories as $name => $factory) {
$factoryNode = $adapterNodeBuilder->arrayNode($name)->canBeUnset();
$factory->addConfiguration($factoryNode);
}
}
private function addFilesystemsSection(ArrayNodeDefinition $node)
{
$node
->fixXmlConfig('filesystem')
->children()
->arrayNode('filesystems')
->useAttributeAsKey('name')
->prototype('array')
->children()
->scalarNode('adapter')->isRequired()->end()
->scalarNode('alias')->defaultNull()->end()
->end()
->end()
->end()
;
}
}