@@ -32,5 +32,201 @@ storages:
3232flysystem :
3333 storages :
3434 users.storage :
35- adapter : ' App\Flysystem\MyCustomAdapter'
36- ` ` `
35+ service : ' App\Flysystem\MyCustomAdapter'
36+ ` ` `
37+
38+ ## Creating a custom adapter builder (advanced)
39+
40+ For more complex custom adapters that require configuration validation, IDE auto-completion,
41+ and integration with the bundle's configuration system, you can create a custom adapter builder.
42+
43+ This allows you to define your custom adapter directly in the configuration:
44+
45+ ` ` ` yaml
46+ # config/packages/flysystem.yaml
47+
48+ flysystem :
49+ storages :
50+ users.storage :
51+ my_custom : # Your custom adapter type
52+ option1 : ' value1'
53+ option2 : ' value2'
54+ ` ` `
55+
56+ ### Creating the adapter builder
57+
58+ Create a class implementing ` AdapterDefinitionBuilderInterface`:
59+
60+ ` ` ` php
61+ <?php
62+
63+ namespace App\F lysystem\B uilder;
64+
65+ use App\F lysystem\M yCustomAdapter;
66+ use League\F lysystemBundle\A dapter\B uilder\A dapterDefinitionBuilderInterface;
67+ use Symfony\C omponent\C onfig\D efinition\B uilder\N odeDefinition;
68+ use Symfony\C omponent\D ependencyInjection\C ontainerBuilder;
69+ use Symfony\C omponent\D ependencyInjection\D efinition;
70+
71+ class MyCustomAdapterDefinitionBuilder implements AdapterDefinitionBuilderInterface
72+ {
73+ public function getName(): string
74+ {
75+ return 'my_custom';
76+ }
77+
78+ public function getRequiredPackages(): array
79+ {
80+ // Return required packages for your adapter
81+ // Format: ['ClassName' => 'vendor/package-name']
82+ return [];
83+ }
84+
85+ public function addConfiguration(NodeDefinition $node): void
86+ {
87+ $node
88+ ->children()
89+ ->scalarNode('option1')
90+ ->isRequired()
91+ ->info('Description of option1')
92+ ->end()
93+ ->scalarNode('option2')
94+ ->defaultValue('default_value')
95+ ->info('Description of option2')
96+ ->end()
97+ ->booleanNode('option3')
98+ ->defaultFalse()
99+ ->info('Description of option3')
100+ ->end()
101+ ->end();
102+ }
103+
104+ public function createAdapter(ContainerBuilder $container, string $storageName, array $options, ?string $defaultVisibilityForDirectories): string
105+ {
106+ $adapterId = 'flysystem.adapter.' . $storageName;
107+
108+ $definition = new Definition(MyCustomAdapter::class);
109+ $definition->setPublic(false);
110+
111+ // Configure your adapter with the options
112+ $definition->setArgument(0, $options['option1']);
113+ $definition->setArgument(1, $options['option2']);
114+ $definition->setArgument(2, $options['option3']);
115+
116+ $container->setDefinition($adapterId, $definition);
117+
118+ return $adapterId;
119+ }
120+ }
121+ ` ` `
122+
123+ # ## Registering the adapter builder
124+
125+ # ### Via Bundle (recommended for reusable bundles)
126+
127+ If you're creating a bundle, register your builder in your bundle class :
128+
129+ ` ` ` php
130+ <?php
131+
132+ namespace App\M yCustomBundle;
133+
134+ use App\F lysystem\B uilder\M yCustomAdapterDefinitionBuilder;
135+ use League\F lysystemBundle\F lysystemBundle;
136+ use Symfony\C omponent\D ependencyInjection\C ontainerBuilder;
137+ use Symfony\C omponent\H ttpKernel\B undle\B undle;
138+
139+ class MyCustomBundle extends Bundle
140+ {
141+ public function build(ContainerBuilder $container): void
142+ {
143+ parent::build($container);
144+
145+ // Register your custom adapter builder
146+ $extension = $container->getExtension('flysystem');
147+ if ($extension instanceof FlysystemExtension) {
148+ $extension->addAdapterDefinitionBuilder(new MyCustomAdapterDefinitionBuilder());
149+ }
150+ }
151+ }
152+ ` ` `
153+
154+ # ### Via Kernel (for application-specific adapters)
155+
156+ For application-specific adapters, register your builder in your `Kernel` :
157+
158+ ` ` ` php
159+ <?php
160+
161+ namespace App;
162+
163+ use App\F lysystem\B uilder\M yCustomAdapterDefinitionBuilder;
164+ use League\F lysystemBundle\D ependencyInjection\F lysystemExtension;
165+ use Symfony\C omponent\D ependencyInjection\C ontainerBuilder;
166+ use Symfony\C omponent\H ttpKernel\K ernel as BaseKernel;
167+
168+ class Kernel extends BaseKernel
169+ {
170+ // ...
171+
172+ protected function build(ContainerBuilder $container): void
173+ {
174+ parent::build($container);
175+
176+ // Register your custom adapter builder
177+ $extension = $container->getExtension('flysystem');
178+ if ($extension instanceof FlysystemExtension) {
179+ $extension->addAdapterDefinitionBuilder(new MyCustomAdapterDefinitionBuilder());
180+ }
181+ }
182+ }
183+ ` ` `
184+
185+ Once registered, you can use the `debug:config flysystem` command to see your custom adapter
186+ and all its available options in the configuration tree.
187+
188+ # ## Testing your custom builder
189+
190+ Create a test class extending `AbstractAdapterDefinitionBuilderTest` :
191+
192+ ` ` ` php
193+ <?php
194+
195+ namespace Tests\A pp\F lysystem\B uilder;
196+
197+ use App\F lysystem\B uilder\M yCustomAdapterDefinitionBuilder;
198+ use App\F lysystem\M yCustomAdapter;
199+ use League\F lysystemBundle\T est\A bstractAdapterDefinitionBuilderTest;
200+ use Symfony\C omponent\D ependencyInjection\D efinition;
201+
202+ class MyCustomAdapterDefinitionBuilderTest extends AbstractAdapterDefinitionBuilderTest
203+ {
204+ protected function createBuilder(): MyCustomAdapterDefinitionBuilder
205+ {
206+ return new MyCustomAdapterDefinitionBuilder();
207+ }
208+
209+ public static function provideValidOptions(): \G enerator
210+ {
211+ yield 'minimal' => [[
212+ 'option1' => 'value1',
213+ ]];
214+
215+ yield 'full' => [[
216+ 'option1' => 'value1',
217+ 'option2' => 'custom_value',
218+ 'option3' => true,
219+ ]];
220+ }
221+
222+ protected function assertDefinition(Definition $definition): void
223+ {
224+ $this->assertSame(MyCustomAdapter::class, $definition->getClass());
225+ $this->assertSame('value1', $definition->getArgument(0));
226+ $this->assertSame('custom_value', $definition->getArgument(1));
227+ $this->assertTrue($definition->getArgument(2));
228+ }
229+ }
230+ ` ` `
231+
232+ This provides comprehensive testing of your builder's configuration and adapter creation logic.
0 commit comments