<?php
namespace Oneup\FlysystemBundle\DependencyInjection;
use League\Flysystem\FilesystemInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
class OneupFlysystemExtension extends Extension
{
private $adapterFactories;
private $cacheFactories;
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('factories.xml');
list($adapterFactories, $cacheFactories) = $this->getFactories($container);
$configuration = new Configuration($adapterFactories, $cacheFactories);
$config = $this->processConfiguration($configuration, $configs);
$loader->load('adapters.xml');
$loader->load('flysystem.xml');
$loader->load('cache.xml');
$loader->load('plugins.xml');
$adapters = array();
$filesystems = array();
$caches = array();
foreach ($config['adapters'] as $name => $adapter) {
$adapters[$name] = $this->createAdapter($name, $adapter, $container, $adapterFactories);
}
foreach ($config['cache'] as $name => $cache) {
$caches[$name] = $this->createCache($name, $cache, $container, $cacheFactories);
}
foreach ($config['filesystems'] as $name => $filesystem) {
$filesystems[$name] = $this->createFilesystem($name, $filesystem, $container, $adapters, $caches);
}
$this->loadStreamWrappers($config['filesystems'], $filesystems, $loader, $container);
}
public function getConfiguration(array $config, ContainerBuilder $container)
{
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('factories.xml');
list($adapterFactories, $cacheFactories) = $this->getFactories($container);
return new Configuration($adapterFactories, $cacheFactories);
}
private function createCache($name, array $config, ContainerBuilder $container, array $factories)
{
foreach ($config as $key => $adapter) {
if (array_key_exists($key, $factories)) {
$id = sprintf('oneup_flysystem.%s_cache', $name);
$factories[$key]->create($container, $id, $adapter);
return $id;
}
}
throw new \LogicException(sprintf('The cache \'%s\' is not configured.', $name));
}
private function createAdapter($name, array $config, ContainerBuilder $container, array $factories)
{
foreach ($config as $key => $adapter) {
if (array_key_exists($key, $factories)) {
$id = sprintf('oneup_flysystem.%s_adapter', $name);
$factories[$key]->create($container, $id, $adapter);
return $id;
}
}
throw new \LogicException(sprintf('The adapter \'%s\' is not configured.', $name));
}
private function createFilesystem($name, array $config, ContainerBuilder $container, array $adapters, array $caches)
{
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('oneup_flysystem.%s_filesystem', $name);
$cache = null;
if (array_key_exists($config['cache'], $caches)) {
$cache = $caches[$config['cache']];
$container
->setDefinition($adapter.'_cached', new ChildDefinition('oneup_flysystem.adapter.cached'))
->replaceArgument(0, new Reference($adapter))
->replaceArgument(1, new Reference($cache));
}
$tagParams = array('key' => $name);
if ($config['mount']) {
$tagParams['mount'] = $config['mount'];
}
$options = [];
if (array_key_exists('visibility', $config)) {
$options['visibility'] = $config['visibility'];
}
if (array_key_exists('disable_asserts', $config)) {
$options['disable_asserts'] = $config['disable_asserts'];
}
$container
->setDefinition($id, new ChildDefinition('oneup_flysystem.filesystem'))
->replaceArgument(0, new Reference($cache ? $adapter.'_cached' : $adapter))
->replaceArgument(1, $options)
->addTag('oneup_flysystem.filesystem', $tagParams)
->setPublic(true)
;
if (!empty($config['alias'])) {
$container->getDefinition($id)->setPublic(false);
if (null === $alias = $container->setAlias($config['alias'], $id)) {
$alias = $container->getAlias($config['alias']);
}
$alias->setPublic(true);
}
// Attach Plugins
$defFilesystem = $container->getDefinition($id);
if (isset($config['plugins']) && is_array($config['plugins'])) {
foreach ($config['plugins'] as $pluginId) {
$defFilesystem->addMethodCall('addPlugin', array(new Reference($pluginId)));
}
}
if (method_exists($container, 'registerAliasForArgument')) {
$aliasName = $name;
if (!preg_match('~filesystem$~i', $aliasName)) {
$aliasName .= 'Filesystem';
}
$container->registerAliasForArgument($id, FilesystemInterface::class, $aliasName)->setPublic(false);
}
return new Reference($id);
}
private function getFactories(ContainerBuilder $container)
{
return array(
$this->getAdapterFactories($container),
$this->getCacheFactories($container),
);
}
private function getAdapterFactories(ContainerBuilder $container)
{
if (null !== $this->adapterFactories) {
return $this->adapterFactories;
}
$factories = array();
$services = $container->findTaggedServiceIds('oneup_flysystem.adapter_factory');
foreach (array_keys($services) as $id) {
$factory = $container->get($id);
$factories[str_replace('-', '_', $factory->getKey())] = $factory;
}
return $this->adapterFactories = $factories;
}
private function getCacheFactories(ContainerBuilder $container)
{
if (null !== $this->cacheFactories) {
return $this->cacheFactories;
}
$factories = array();
$services = $container->findTaggedServiceIds('oneup_flysystem.cache_factory');
foreach (array_keys($services) as $id) {
$factory = $container->get($id);
$factories[str_replace('-', '_', $factory->getKey())] = $factory;
}
return $this->cacheFactories = $factories;
}
/**
* @param array $configs
* @param Reference[] $filesystems
* @param Loader\XmlFileLoader $loader
* @param ContainerBuilder $container
*/
private function loadStreamWrappers(array $configs, array $filesystems, Loader\XmlFileLoader $loader, ContainerBuilder $container)
{
if (!$this->hasStreamWrapperConfiguration($configs)) {
return;
}
if (!class_exists('Twistor\FlysystemStreamWrapper')) {
throw new InvalidConfigurationException('twistor/flysystem-stream-wrapper must be installed to use the stream wrapper feature.');
}
$loader->load('stream_wrappers.xml');
$configurations = [];
foreach ($configs as $name => $filesystem) {
if (!isset($filesystem['stream_wrapper'])) {
continue;
}
$streamWrapper = array_merge(['configuration' => null], $filesystem['stream_wrapper']);
$configuration = new ChildDefinition('oneup_flysystem.stream_wrapper.configuration.def');
$configuration
->replaceArgument(0, $streamWrapper['protocol'])
->replaceArgument(1, $filesystems[$name])
->replaceArgument(2, $streamWrapper['configuration'])
->setPublic(false);
$container->setDefinition('oneup_flysystem.stream_wrapper.configuration.'.$name, $configuration);
$configurations[$name] = new Reference('oneup_flysystem.stream_wrapper.configuration.'.$name);
}
$container->getDefinition('oneup_flysystem.stream_wrapper.manager')->replaceArgument(0, $configurations);
}
/**
* @param array $configs
*
* @return bool
*/
private function hasStreamWrapperConfiguration(array $configs)
{
foreach ($configs as $name => $filesystem) {
if (isset($filesystem['stream_wrapper'])) {
return true;
}
}
return false;
}
}