Skip to content

Commit f1bf394

Browse files
authored
Merge pull request thephpleague#33 from thephpleague/dsn
Add Lazy adapter to all runtime switch between adapters
2 parents fd9e1fb + 9fa2986 commit f1bf394

10 files changed

Lines changed: 205 additions & 32 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
/**
20+
* @author Titouan Galopin <galopintitouan@gmail.com>
21+
*
22+
* @internal
23+
*/
24+
class LazyFactoryPass implements CompilerPassInterface
25+
{
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function process(ContainerBuilder $container)
30+
{
31+
$factories = [];
32+
foreach ($container->findTaggedServiceIds('flysystem.storage') as $serviceId => $tags) {
33+
foreach ($tags as $tag) {
34+
if (isset($tag['storage'])) {
35+
$factories[$tag['storage']] = new Reference($serviceId);
36+
}
37+
}
38+
}
39+
40+
$lazyFactory = $container->getDefinition('flysystem.adapter.lazy.factory');
41+
$lazyFactory->setArgument(0, ServiceLocatorTagPass::register($container, $factories));
42+
}
43+
}

src/DependencyInjection/Compiler/PluginPass.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
use Symfony\Component\DependencyInjection\Definition;
1717
use Symfony\Component\DependencyInjection\Reference;
1818

19+
/**
20+
* @author BoShurik <boshurik@gmail.com>
21+
*
22+
* @internal
23+
*/
1924
class PluginPass implements CompilerPassInterface
2025
{
2126
/**

src/DependencyInjection/FlysystemExtension.php

Lines changed: 45 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,67 @@ 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+
$definition->addTag('flysystem.storage', ['storage' => $storageName]);
94+
95+
return $definition;
96+
}
97+
6098
private function createStorageDefinition(string $storageName, Reference $adapter, array $config)
6199
{
62100
$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: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,64 @@
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)
56+
{
57+
$kernel = $this->createFysystemKernel();
58+
$fs = $kernel->getContainer()->get('flysystem.test.'.$fsName);
59+
60+
$this->assertInstanceOf(FilesystemInterface::class, $fs, 'Filesystem "'.$fsName.'" should be an instance of FilesystemInterface');
61+
$this->assertEquals('plugin', $fs->pluginTest());
62+
}
63+
64+
/**
65+
* @dataProvider provideFilesystems
66+
*/
67+
public function testTaggedCollection(string $fsName)
68+
{
69+
$kernel = $this->createFysystemKernel();
70+
71+
if (!$kernel->getContainer()->has('storages_tagged_collection')) {
72+
$this->markTestSkipped('Symfony 4.3+ is required to use indexed tagged service collections');
73+
}
74+
75+
$storages = iterator_to_array($kernel->getContainer()->get('storages_tagged_collection')->locator);
76+
77+
$this->assertInstanceOf(FilesystemInterface::class, $storages[$fsName]);
78+
$this->assertEquals('plugin', $storages[$fsName]->pluginTest());
79+
}
80+
81+
private function createFysystemKernel()
2982
{
3083
(new Dotenv())->populate([
3184
'AWS_BUCKET' => 'bucket-name',
85+
'LAZY_SOURCE' => 'fs_memory',
3286
'FTP_PORT' => 21,
3387
]);
3488

@@ -41,11 +95,7 @@ public function testCreateFileystems()
4195
$container->set($service, $mock);
4296
}
4397

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-
}
98+
return $kernel;
4999
}
50100

51101
private function getClientMocks()
@@ -62,23 +112,4 @@ private function getClientMocks()
62112
'webdav_client_service' => $this->createMock(WebDAVClient::class),
63113
];
64114
}
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-
}
84115
}

tests/Kernel/FlysystemAppKernel.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ public function registerContainerConfiguration(LoaderInterface $loader)
4242
$loader->load(__DIR__.'/config/framework.yaml', 'yaml');
4343
$loader->load(__DIR__.'/config/flysystem.yaml', 'yaml');
4444
$loader->load(__DIR__.'/config/services.yaml', 'yaml');
45+
46+
if (self::VERSION_ID > 40300) {
47+
$loader->load(__DIR__.'/config/tagged_collection.yaml', 'yaml');
48+
}
4549
}
4650

4751
public function setAdapterClients(array $adapterClients)

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' }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
services:
2+
storages_tagged_collection:
3+
class: 'stdClass'
4+
public: true
5+
properties:
6+
locator: !tagged { tag: 'flysystem.storage', index_by: 'storage' }

0 commit comments

Comments
 (0)