Skip to content

Commit c8e55b6

Browse files
committed
Add Lazy adapter to all runtime switch between adapters
1 parent fd9e1fb commit c8e55b6

7 files changed

Lines changed: 160 additions & 32 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the flysystem-bundle project.
5+
*
6+
* (c) Titouan Galopin <galopintitouan@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace League\FlysystemBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
16+
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
use Symfony\Component\DependencyInjection\Reference;
18+
19+
class LazyFactoryPass implements CompilerPassInterface
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
public function process(ContainerBuilder $container)
25+
{
26+
$factories = [];
27+
foreach ($container->findTaggedServiceIds('flysystem.storage') as $serviceId => $tags) {
28+
foreach ($tags as $tag) {
29+
if (isset($tag['storage'])) {
30+
$factories[$tag['storage']] = new Reference($serviceId);
31+
}
32+
}
33+
}
34+
35+
$lazyFactory = $container->getDefinition('flysystem.adapter.lazy.factory');
36+
$lazyFactory->setArgument(0, ServiceLocatorTagPass::register($container, $factories));
37+
}
38+
}

src/DependencyInjection/FlysystemExtension.php

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
use League\Flysystem\FilesystemInterface;
1616
use League\Flysystem\PluginInterface;
1717
use League\FlysystemBundle\Adapter\AdapterDefinitionFactory;
18+
use League\FlysystemBundle\Lazy\LazyFactory;
1819
use Symfony\Component\DependencyInjection\ContainerBuilder;
1920
use Symfony\Component\DependencyInjection\Definition;
2021
use Symfony\Component\DependencyInjection\Reference;
2122
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
23+
use Symfony\Component\OptionsResolver\OptionsResolver;
2224

2325
/**
2426
* @author Titouan Galopin <galopintitouan@gmail.com>
@@ -32,31 +34,66 @@ public function load(array $configs, ContainerBuilder $container)
3234
$configuration = new Configuration();
3335
$config = $this->processConfiguration($configuration, $configs);
3436

35-
$adapterFactory = new AdapterDefinitionFactory();
36-
3737
$container
3838
->registerForAutoconfiguration(PluginInterface::class)
3939
->addTag('flysystem.plugin')
4040
;
4141

42+
$container
43+
->setDefinition('flysystem.adapter.lazy.factory', new Definition(LazyFactory::class))
44+
->setPublic(false)
45+
;
46+
47+
$this->createStoragesDefinitions($config, $container);
48+
}
49+
50+
private function createStoragesDefinitions(array $config, ContainerBuilder $container)
51+
{
52+
$definitionFactory = new AdapterDefinitionFactory();
53+
4254
foreach ($config['storages'] as $storageName => $storageConfig) {
43-
// Create adapter service definition
44-
if ($adapter = $adapterFactory->createDefinition($storageConfig['adapter'], $storageConfig['options'])) {
55+
// If the storage is a lazy one, it's resolved at runtime
56+
if ('lazy' === $storageConfig['adapter']) {
57+
$container->setDefinition($storageName, $this->createLazyStorageDefinition($storageName, $storageConfig['options']));
58+
59+
continue;
60+
}
61+
62+
// Create adapter definition
63+
if ($adapter = $definitionFactory->createDefinition($storageConfig['adapter'], $storageConfig['options'])) {
4564
// Native adapter
4665
$container->setDefinition('flysystem.adapter.'.$storageName, $adapter)->setPublic(false);
4766
} else {
4867
// Custom adapter
4968
$container->setAlias('flysystem.adapter.'.$storageName, $storageConfig['adapter'])->setPublic(false);
5069
}
5170

52-
// Create storage service definition
53-
$definition = $this->createStorageDefinition($storageName, new Reference('flysystem.adapter.'.$storageName), $storageConfig);
71+
// Create storage definition
72+
$container->setDefinition(
73+
$storageName,
74+
$this->createStorageDefinition($storageName, new Reference('flysystem.adapter.'.$storageName), $storageConfig)
75+
);
5476

55-
$container->setDefinition($storageName, $definition);
77+
// Register named autowiring alias
5678
$container->registerAliasForArgument($storageName, FilesystemInterface::class, $storageName)->setPublic(false);
5779
}
5880
}
5981

82+
private function createLazyStorageDefinition(string $storageName, array $options)
83+
{
84+
$resolver = new OptionsResolver();
85+
$resolver->setRequired('source');
86+
$resolver->setAllowedTypes('source', 'string');
87+
88+
$definition = new Definition(FilesystemInterface::class);
89+
$definition->setPublic(false);
90+
$definition->setFactory([new Reference('flysystem.adapter.lazy.factory'), 'createStorage']);
91+
$definition->setArgument(0, $resolver->resolve($options)['source']);
92+
$definition->setArgument(1, $storageName);
93+
94+
return $definition;
95+
}
96+
6097
private function createStorageDefinition(string $storageName, Reference $adapter, array $config)
6198
{
6299
$definition = new Definition(Filesystem::class);

src/FlysystemBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace League\FlysystemBundle;
1313

14+
use League\FlysystemBundle\DependencyInjection\Compiler\LazyFactoryPass;
1415
use League\FlysystemBundle\DependencyInjection\Compiler\PluginPass;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -30,5 +31,6 @@ public function build(ContainerBuilder $container)
3031
parent::build($container);
3132

3233
$container->addCompilerPass(new PluginPass());
34+
$container->addCompilerPass(new LazyFactoryPass());
3335
}
3436
}

src/Lazy/LazyFactory.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the flysystem-bundle project.
5+
*
6+
* (c) Titouan Galopin <galopintitouan@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace League\FlysystemBundle\Lazy;
13+
14+
use Psr\Container\ContainerInterface;
15+
16+
/**
17+
* @author Titouan Galopin <galopintitouan@gmail.com>
18+
*
19+
* @internal
20+
*/
21+
class LazyFactory
22+
{
23+
private $storages;
24+
25+
public function __construct(ContainerInterface $storages)
26+
{
27+
$this->storages = $storages;
28+
}
29+
30+
public function createStorage(string $source, string $storageName)
31+
{
32+
if (!$this->storages->has($source)) {
33+
throw new \InvalidArgumentException('You have requested a non-existent source storage "'.$source.'" in lazy storage "'.$storageName.'".');
34+
}
35+
36+
return $this->storages->get($source);
37+
}
38+
}

tests/DependencyInjection/FlysytemExtensionTest.php

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,38 @@
2525

2626
class FlysytemExtensionTest extends TestCase
2727
{
28-
public function testCreateFileystems()
28+
public function provideFilesystems()
29+
{
30+
$fsNames = [
31+
'fs_aws',
32+
'fs_azure',
33+
'fs_cache',
34+
'fs_custom',
35+
'fs_dropbox',
36+
'fs_ftp',
37+
'fs_gcloud',
38+
'fs_lazy',
39+
'fs_local',
40+
'fs_rackspace',
41+
'fs_replicate',
42+
'fs_sftp',
43+
'fs_webdav',
44+
'fs_zip',
45+
];
46+
47+
foreach ($fsNames as $fsName) {
48+
yield $fsName => [$fsName];
49+
}
50+
}
51+
52+
/**
53+
* @dataProvider provideFilesystems
54+
*/
55+
public function testFileystems(string $fsName)
2956
{
3057
(new Dotenv())->populate([
3158
'AWS_BUCKET' => 'bucket-name',
59+
'LAZY_SOURCE' => 'fs_memory',
3260
'FTP_PORT' => 21,
3361
]);
3462

@@ -41,11 +69,9 @@ public function testCreateFileystems()
4169
$container->set($service, $mock);
4270
}
4371

44-
foreach ($this->getFilesystems() as $fsName) {
45-
$fs = $container->get('flysystem.test.'.$fsName);
46-
$this->assertInstanceOf(FilesystemInterface::class, $fs, 'Filesystem "'.$fsName.'" should be an instance of FilesystemInterface');
47-
$this->assertEquals('plugin', $fs->pluginTest());
48-
}
72+
$fs = $container->get('flysystem.test.'.$fsName);
73+
$this->assertInstanceOf(FilesystemInterface::class, $fs, 'Filesystem "'.$fsName.'" should be an instance of FilesystemInterface');
74+
$this->assertEquals('plugin', $fs->pluginTest());
4975
}
5076

5177
private function getClientMocks()
@@ -62,23 +88,4 @@ private function getClientMocks()
6288
'webdav_client_service' => $this->createMock(WebDAVClient::class),
6389
];
6490
}
65-
66-
private function getFilesystems()
67-
{
68-
return [
69-
'fs_aws',
70-
'fs_azure',
71-
'fs_cache',
72-
'fs_custom',
73-
'fs_dropbox',
74-
'fs_ftp',
75-
'fs_gcloud',
76-
'fs_local',
77-
'fs_rackspace',
78-
'fs_replicate',
79-
'fs_sftp',
80-
'fs_webdav',
81-
'fs_zip',
82-
];
83-
}
8491
}

tests/Kernel/config/flysystem.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ flysystem:
5050
prefix: 'optional/path/prefix'
5151
api_url: 'https://storage.googleapis.com'
5252

53+
fs_lazy:
54+
adapter: 'lazy'
55+
options:
56+
source: '%env(LAZY_SOURCE)%'
57+
5358
fs_local:
5459
adapter: 'local'
5560
options:

tests/Kernel/config/services.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ services:
1313
flysystem.test.fs_dropbox: { alias: 'fs_dropbox' }
1414
flysystem.test.fs_ftp: { alias: 'fs_ftp' }
1515
flysystem.test.fs_gcloud: { alias: 'fs_gcloud' }
16+
flysystem.test.fs_lazy: { alias: 'fs_lazy' }
1617
flysystem.test.fs_local: { alias: 'fs_local' }
1718
flysystem.test.fs_memory: { alias: 'fs_memory' }
1819
flysystem.test.fs_null: { alias: 'fs_null' }

0 commit comments

Comments
 (0)