Skip to content

Commit dfce8d5

Browse files
committed
Add lazy adapter doc
1 parent a5185e5 commit dfce8d5

3 files changed

Lines changed: 185 additions & 10 deletions

File tree

README.md

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,11 @@
66

77
[![SymfonyInsight](https://insight.symfony.com/projects/525fdfa3-d482-4218-b4b9-3c2efc305fac/big.svg)](https://insight.symfony.com/projects/525fdfa3-d482-4218-b4b9-3c2efc305fac)
88

9-
This repository is a light Symfony bundle integrating the [Flysystem](https://flysystem.thephpleague.com)
10-
library into Symfony applications. It provides an efficient abstraction for the filesystem,
11-
for instance to use local files in development and a cloud storage in production or to use a memory
12-
filesystem in tests to increase their speed.
9+
flysystem-bundle is a Symfony bundle integrating the [Flysystem](https://flysystem.thephpleague.com)
10+
library into Symfony applications.
1311

14-
This bundle relies on
15-
[named aliases](https://symfony.com/doc/current/service_container/autowiring.html#dealing-with-multiple-implementations-of-the-same-type)
16-
(introduced in Symfony 4.2) in order to create and configure multiple filesystems while still
17-
following the best practices of software architecture (SOLID principles).
12+
It provides an efficient abstraction for the filesystem in order to change the storage backend depending
13+
on the execution environment (local files in development, cloud storage in production and memory in tests).
1814

1915
## Installation
2016

@@ -26,7 +22,76 @@ You can install the bundle using Symfony Flex:
2622
composer require league/flysystem-bundle
2723
```
2824

29-
## Documentation
25+
## Basic usage
26+
27+
The default configuration file created by Symfony Flex provides enough configuration to
28+
use Flysystem in your application as soon as you install the bundle:
29+
30+
```yaml
31+
# config/packages/flysystem.yaml
32+
33+
flysystem:
34+
storages:
35+
default.storage:
36+
adapter: 'local'
37+
options:
38+
directory: '%kernel.project_dir%/var/storage/default'
39+
```
40+
41+
This configuration defines a single storage service (`default.storage`) based on the local adapter
42+
and configured to use the `%kernel.project_dir%/var/storage/default` directory.
43+
44+
For each storage defined under `flysystem.storages`, an associated service is created using the
45+
name you provide (in this case, a service `default.storage` will be created). The bundle also
46+
creates a named alias for each of these services.
47+
48+
This means you have two way of using the defined storages:
49+
50+
* either using autowiring, by typehinting against the `FilesystemInterface` and using the
51+
variable name matching one of your storages:
52+
53+
```php
54+
use League\Flysystem\FilesystemInterface;
55+
56+
class MyService
57+
{
58+
private $storage;
59+
60+
// The variable name $defaultStorage matters: it needs to be the camelized version
61+
// of the name of your storage.
62+
public function __construct(FilesystemInterface $defaultStorage)
63+
{
64+
$this->storage = $defaultStorage;
65+
}
66+
67+
// ...
68+
}
69+
```
70+
71+
The same goes for controllers:
72+
73+
```php
74+
use League\Flysystem\FilesystemInterface;
75+
76+
class MyController
77+
{
78+
// The variable name $defaultStorage matters: it needs to be the camelized version
79+
// of the name of your storage.
80+
public function index(FilesystemInterface $defaultStorage)
81+
{
82+
// ...
83+
}
84+
}
85+
```
86+
87+
* or using manual injection, by injecting the service named `default.storage` inside
88+
your services.
89+
90+
Once you have a FilesystemInterface, you can call methods from the
91+
[Filesystem API](https://flysystem.thephpleague.com/docs/usage/filesystem-api/)
92+
to interact with your storage.
93+
94+
## Full documentation
3095

3196
1. [Getting started](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/1-getting-started.md)
3297
2. Cloud storage providers:
@@ -39,7 +104,8 @@ composer require league/flysystem-bundle
39104
[WebDAV](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/2-cloud-storage-providers.md#webdav)
40105
3. [Interacting with FTP and SFTP servers](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/3-interacting-with-ftp-and-sftp-servers.md)
41106
4. [Caching metadata in Symfony cache](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/4-caching-metadata-in-symfony-cache.md)
42-
5. [Creating a custom adapter](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/5-creating-a-custom-adapter.md)
107+
5. [Using a lazy adapter to switch storage backend using an environment variable](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/5-using-lazy-adapter-to-switch-at-runtime.md)
108+
6. [Creating a custom adapter](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/6-creating-a-custom-adapter.md)
43109

44110
* [Security issue disclosure procedure](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/A-security-disclosure-procedure.md)
45111
* [Configuration reference](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/B-configuration-reference.md)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Using a lazy adapter to switch storage backend using an environment variable
2+
3+
One of the main reason why using a filesystem abstraction is useful is because
4+
you can switch the storage backend depending on the execution environment
5+
(local files in development, cloud storage in production and memory in tests).
6+
7+
The classical way of doing this would be to create a
8+
`config/packages/dev/flysystem.yaml` file that would override the configuration
9+
defined in `config/packages/flysystem.yaml`, thus creating a different storage
10+
service for each environment.
11+
12+
Using this technique is recommended in most cases: by declaring your services
13+
statically and relying on the environment to choose which one to use, you will
14+
profit from the performance optimizations done by the Symfony container to remove
15+
unused services.
16+
17+
However, this technique is not always flexible enough. What if you need
18+
one staging production environment with local storage and the real production
19+
environment with cloud storage?
20+
21+
In such cases, you need to choose the adapter to use at runtime instead of
22+
compile time. To do so, you can use a `lazy` adapter.
23+
24+
A `lazy` adapter is a "fake" adapter that will delay the creation of the actual
25+
storage at runtime. This will allow you to change the storage to create dynamically,
26+
for instance using an environment variable.
27+
28+
Let's take a real-world example:
29+
30+
```yaml
31+
# config/packages/flysystem.yaml
32+
33+
services:
34+
Aws\S3\S3Client:
35+
arguments:
36+
- version: '2006-03-01'
37+
region: 'fr-par'
38+
credentials:
39+
key: '%env(S3_STORAGE_KEY)%'
40+
secret: '%env(S3_STORAGE_SECRET)%'
41+
42+
flysystem:
43+
storages:
44+
uploads.storage.aws:
45+
adapter: 'aws'
46+
options:
47+
client: 'Aws\S3\S3Client'
48+
bucket: 'my-bucket'
49+
prefix: '%env(S3_STORAGE_PREFIX)%'
50+
51+
uploads.storage.local:
52+
adapter: 'local'
53+
options:
54+
directory: '%kernel.project_dir%/var/storage/uploads'
55+
56+
uploads.storage.memory:
57+
adapter: 'memory'
58+
59+
uploads.storage:
60+
adapter: 'lazy'
61+
options:
62+
source: '%env(APP_UPLOADS_SOURCE)%'
63+
```
64+
65+
In this example, we define 3 actual storages: aws, local and memory. They
66+
have a `uploads.storage.` prefix to note their relationship with `uploads.storage`
67+
but this prefix does not have any impact on the behavior itself.
68+
69+
By using a `lazy` adapter for `uploads.storage`, we are able to provide a source
70+
which will be actually used when the service will need to be instantiated. In this case,
71+
we rely on an environment variable to choose the actual storage to use.
72+
73+
This technique allows us to specify a different storage to use in different environments:
74+
75+
```
76+
# To use the AWS storage
77+
APP_UPLOADS_SOURCE=uploads.storage.aws
78+
79+
# To use the local storage
80+
APP_UPLOADS_SOURCE=uploads.storage.local
81+
82+
# To use the memory storage
83+
APP_UPLOADS_SOURCE=uploads.storage.memory
84+
```
85+
86+
Other than being created at runtime, the `lazy` adapter is behaving in the exact
87+
same way as any other storage:
88+
89+
* you can use it with autowiring, by typehinting against the `FilesystemInterface` and using the
90+
variable name matching its name:
91+
92+
```php
93+
use League\Flysystem\FilesystemInterface;
94+
95+
class MyService
96+
{
97+
private $storage;
98+
99+
public function __construct(FilesystemInterface $uploadsStorage)
100+
{
101+
$this->storage = $uploadsStorage;
102+
}
103+
104+
// ...
105+
}
106+
```
107+
108+
* you can use it in manual injection by injecting the service named `uploads.storage` inside
109+
your services.
File renamed without changes.

0 commit comments

Comments
 (0)