├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Command └── FilesystemKeysCommand.php ├── DependencyInjection ├── Compiler │ ├── AdapterFactoryManagerPass.php │ └── AdapterManagerPass.php ├── Factory │ ├── AdapterFactoryInterface.php │ ├── AsyncAwsS3AdapterFactory.php │ ├── AwsS3AdapterFactory.php │ ├── AzureBlobStorageAdapterFactory.php │ ├── DoctrineDbalAdapterFactory.php │ ├── FtpAdapterFactory.php │ ├── GoogleCloudStorageAdapterFactory.php │ ├── GridFSAdapterFactory.php │ ├── InMemoryAdapterFactory.php │ ├── LocalAdapterFactory.php │ ├── PhpseclibSftpAdapterFactory.php │ ├── SafeLocalAdapterFactory.php │ └── ServiceAdapterFactory.php ├── FactoryConfiguration.php ├── KnpGaufretteExtension.php └── MainConfiguration.php ├── FilesystemMap.php ├── KnpGaufretteBundle.php ├── LICENSE ├── README.md ├── Resources ├── config │ ├── adapter_factories.xml │ └── gaufrette.xml └── docs │ ├── adapters │ ├── apc.md │ ├── async-aws-s3.md │ ├── awss3.md │ ├── azure.md │ ├── cache.md │ ├── doctrine_dbal.md │ ├── dropbox.md │ ├── ftp.md │ ├── googlecloud.md │ ├── gridfs.md │ ├── local.md │ ├── memory.md │ ├── mogilefs.md │ ├── phpseclib_sftp.md │ ├── safe_local.md │ ├── service.md │ └── sftp.md │ ├── stream.md │ └── use-case-examples.md ├── Tests ├── FilesystemMapTest.php └── Functional │ ├── ConfigurationTest.php │ ├── Resources │ └── config │ │ ├── config.yml │ │ ├── config_dev.yml │ │ ├── config_test.yml │ │ ├── config_wrapper_1.yml │ │ ├── config_wrapper_2.yml │ │ └── config_wrapper_3.yml │ └── TestKernel.php ├── UPGRADE.md ├── composer.json └── phpunit.xml.dist /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '0 0 1 * *' 10 | 11 | jobs: 12 | tests: 13 | name: PHPUnit 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Setup PHP 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: ${{ matrix.php }} 25 | 26 | - name: Install dependencies 27 | run: composer update --prefer-dist --no-progress --no-suggest --ansi 28 | 29 | - name: Run PHPUnit tests 30 | run: vendor/bin/simple-phpunit --coverage-text 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Tests/Resources/cache 2 | var/ 3 | vendor/ 4 | composer.lock 5 | .phpunit.result.cache 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | cache: 6 | directories: 7 | - $HOME/.composer/cache 8 | 9 | matrix: 10 | include: 11 | - php: '7.1' 12 | - php: '7.2' 13 | - php: '7.3' 14 | - php: '7.4' 15 | 16 | install: 17 | - composer update --prefer-dist --no-progress --no-suggest --ansi 18 | 19 | script: 20 | - vendor/bin/simple-phpunit --coverage-text 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v0.8.0 - 2022-10-21 2 | =================== 3 | 4 | Adds : 5 | 6 | - BC Break: Adding Types (remove deprecation notices triggered by Symfony) 7 | _Please notice that the v0.8.0 is a major version, therefore if you extended any class or interface, you MUST implement it with types now._ 8 | - Support for Gaufrette 0.11 9 | - With support for the new version of Google Client (compatible with PHP 8.0+) 10 | 11 | Fixes : 12 | 13 | - Command documentation now print the right information (#242) 14 | 15 | Removes : 16 | 17 | - Support for PHP < 7.4 18 | 19 | v0.7.2 20 | ====== 21 | 22 | Fixes: 23 | 24 | - Add support for PHP 8.1 (#256) 25 | 26 | v0.7.1 27 | ====== 28 | 29 | Fixes : 30 | 31 | - Be able to install Gaufrette [v0.9.0](https://github.com/KnpLabs/Gaufrette/releases/tag/v0.9.0) 32 | (#233). 33 | 34 | v0.7.0 35 | ====== 36 | 37 | Changes : 38 | 39 | - Bump minimum Symfony 4 version to 4.2 to fix vulnerability issue (#228) 40 | - Symfony 5 support (#227) 41 | - PHP 7.4 support (#227) 42 | 43 | Fixes : 44 | 45 | - Symplify TreeBuilder usage backward compatibility (#223) 46 | 47 | Thank you @flug, @nm2107 and @p365labs for your contributions ! 48 | 49 | v0.6.1 50 | ====== 51 | 52 | ## Fixes 53 | 54 | - Keep compatibility with Symfony 3.4 as it is LTS (#221) 55 | - Fix Symfony 4.2 command deprecation about services usage (#210) 56 | - Fix Symfony 3.4 deprecation: Autowiring based on types (#215) 57 | 58 | Thank you @ahilke, @nicolasmure and @timgregg for your contributions ! 59 | 60 | v0.6.0 61 | ====== 62 | 63 | Changes: 64 | - Require PHP 7.1 as minimum (previous php versions are EOL) (#204) 65 | - PHP 7.3 support (#204) 66 | - Update Gaufrette dep to v0.8 (#204) 67 | - Update Symfony deps to v4 (#204) 68 | 69 | Fixes: 70 | - Make composer respects semver versioning (#196) 71 | - Update README for Symfony 4 directory structure (#206) 72 | - Remove TreeBuilder deprecations (#207) 73 | 74 | Documentation fixes: 75 | - Fixed documentation for phpseclib 2.0 (#189) 76 | - Simplified aws s3 docs (#193) 77 | - Pretty print doc block (#195) 78 | 79 | Thanks to @aaronadal, @Awkan, @Nek-, @nicolasmure and @OskarStark for their 80 | contributions! 81 | 82 | v0.5.3 83 | ====== 84 | 85 | - Fix composer.json validity (#184) 86 | - Be able to install Gaufrette v0.6 (#185) 87 | 88 | v0.5.2 89 | ====== 90 | 91 | - Declare command as service to fix sf3.4 deprecation (#183) 92 | 93 | v0.5.1 94 | ====== 95 | 96 | - Be able to install Gaufrette 0.5 (#178) 97 | 98 | v0.5.0 99 | ====== 100 | 101 | * Add `utf8` parameter to FTP adapter config 102 | * Add some docs about S3 regions 103 | * Fix config example for S3 adapter (#153) 104 | * Add `multi_container_mode` to Azure adapter config (#158) 105 | * Add missing documentation about `detect_content_type` for S3 adapter (#161) 106 | * Fix configuration processing (#163) 107 | * Fix deprecation warnings with Symfony >= 3.3 (#165) 108 | * Add docs about metapackages (#168) 109 | * Fix doc link (#169) 110 | * Adding Symfony 4 support (#171) 111 | * Use PHPUnit\Framework\TestCase instead of PHPUnit_Framework_TestCase (#172) 112 | * Bump Gaufrette version (#173) 113 | * Add use cases documentation (#175) 114 | * Declare filesystem services as public (#176) 115 | * Drop support for old PHP versions 5.3, 5.4, 5.5 (#177) 116 | 117 | Thanks to: @000panther, @NiR-, @jspizziri, @kesslerdev, @vyacheslavk, @Lctrs, @nicolasmure, @silvioq, @bocharsky-bw, @carusogabriel, @7thcubic, @aguidis, @bluntelk, @rjd22. 118 | -------------------------------------------------------------------------------- /Command/FilesystemKeysCommand.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class FilesystemKeysCommand extends Command 18 | { 19 | /** 20 | * @var FilesystemMapInterface 21 | */ 22 | private $filesystemMap; 23 | 24 | public function __construct(FilesystemMapInterface $filesystemMap) 25 | { 26 | $this->filesystemMap = $filesystemMap; 27 | 28 | parent::__construct(); 29 | } 30 | /** 31 | * {@inheritDoc} 32 | */ 33 | protected function configure(): void 34 | { 35 | $this 36 | ->setName('gaufrette:filesystem:keys') 37 | ->setDescription('List all the file keys of a filesystem') 38 | ->addArgument('filesystem', InputArgument::REQUIRED, 'The filesystem to use') 39 | ->addArgument('glob', InputArgument::OPTIONAL, 'An optional glob pattern') 40 | ->setHelp(<<%command.name% command lists all the file keys of the specified filesystem: 42 | 43 | php %command.full_name% my_filesystem 44 | 45 | You can also optionaly specify a glob pattern to filter the results: 46 | 47 | php %command.full_name% my_filesystem media_* 48 | EOT 49 | ); 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | protected function execute(InputInterface $input, OutputInterface $output): int 56 | { 57 | $filesystemName = $input->getArgument('filesystem'); 58 | $glob = $input->getArgument('glob'); 59 | 60 | if (!$this->filesystemMap->has($filesystemName)) { 61 | throw new \RuntimeException(sprintf('There is no \'%s\' filesystem defined.', $filesystemName)); 62 | } 63 | 64 | $filesystem = $this->filesystemMap->get($filesystemName); 65 | $keys = $filesystem->keys(); 66 | 67 | if (!empty($glob)) { 68 | $glob = new Glob($glob); 69 | $keys = $glob->filter($keys); 70 | } 71 | 72 | $count = count($keys); 73 | 74 | $message = $count ? sprintf( 75 | 'Bellow %s the %s key%s that were found:', 76 | $count > 1 ? 'are' : 'is', 77 | $count, 78 | $count > 1 ? 's': '' 79 | ) : "0 keys were found."; 80 | 81 | $output->writeln($message); 82 | 83 | $output->setDecorated(true); 84 | foreach ($keys as $key) { 85 | $output->writeln(' - ' . $key . ''); 86 | } 87 | 88 | return 0; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/AdapterFactoryManagerPass.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class AdapterFactoryManagerPass implements CompilerPassInterface 15 | { 16 | public function process(ContainerBuilder $container): void 17 | { 18 | if (!$container->hasDefinition('knp_gaufrette.adapter_factory_manager')) { 19 | return; 20 | } 21 | 22 | $definition = $container->getDefinition('knp_gaufrette.adapter_factory_manager'); 23 | 24 | $calls = $definition->getMethodCalls(); 25 | $definition->setMethodCalls(array()); 26 | 27 | foreach ($container->findTaggedServiceIds('gaufrette.adapter_factory') as $id => $attributes) { 28 | if (!empty($attributes['type'])) { 29 | $definition->addMethodCall('set', array($attributes['type'], new Reference($id))); 30 | } 31 | } 32 | 33 | $definition->setMethodCalls(array_merge($definition->getMethodCalls(), $calls)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/AdapterManagerPass.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class AdapterManagerPass implements CompilerPassInterface 15 | { 16 | public function process(ContainerBuilder $container): void 17 | { 18 | if (!$container->hasDefinition('knp_gaufrette.adapter_manager')) { 19 | return; 20 | } 21 | 22 | $definition = $container->getDefinition('knp_gaufrette.adapter_manager'); 23 | $calls = $definition->getMethodCalls(); 24 | $definition->setMethodCalls(array()); 25 | 26 | foreach ($container->findTaggedServiceIds('gaufrette.adapter') as $id => $attributes) { 27 | if (!empty($attributes['alias'])) { 28 | $definition->addMethodCall('set', array($attributes['alias'], new Reference($id))); 29 | } 30 | } 31 | 32 | $definition->setMethodCalls(array_merge($definition->getMethodCalls(), $calls)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/AdapterFactoryInterface.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | interface AdapterFactoryInterface 14 | { 15 | /** 16 | * Creates the adapter, registers it and returns its id 17 | * 18 | * @param ContainerBuilder $container A ContainerBuilder instance 19 | * @param string $id The id of the service 20 | * @param array $config An array of configuration 21 | */ 22 | public function create(ContainerBuilder $container, $id, array $config): void; 23 | 24 | /** 25 | * Returns the key for the factory configuration 26 | * 27 | * @return string 28 | */ 29 | public function getKey(): string; 30 | 31 | /** 32 | * Adds configuration nodes for the factory 33 | * 34 | * @param NodeDefinition $builder 35 | */ 36 | public function addConfiguration(NodeDefinition $builder): void; 37 | } 38 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/AsyncAwsS3AdapterFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($id, $childDefinition) 24 | ->addArgument(new Reference($config['service_id'])) 25 | ->addArgument($config['bucket_name']) 26 | ->addArgument($config['options']) 27 | ->addArgument($config['detect_content_type']) 28 | ; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function getKey(): string 35 | { 36 | return 'async_aws_s3'; 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | public function addConfiguration(NodeDefinition $builder): void 43 | { 44 | $builder 45 | ->children() 46 | ->scalarNode('service_id')->isRequired()->cannotBeEmpty()->end() 47 | ->scalarNode('bucket_name')->isRequired()->cannotBeEmpty()->end() 48 | ->booleanNode('detect_content_type')->defaultFalse()->end() 49 | ->arrayNode('options') 50 | ->addDefaultsIfNotSet() 51 | ->children() 52 | ->scalarNode('directory')->defaultValue('')->end() 53 | ->booleanNode('create')->defaultFalse()->end() 54 | ->scalarNode('acl')->defaultValue('private')->end() 55 | ->end() 56 | ->end() 57 | ->end() 58 | ; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/AwsS3AdapterFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($id, $childDefinition) 24 | ->addArgument(new Reference($config['service_id'])) 25 | ->addArgument($config['bucket_name']) 26 | ->addArgument($config['options']) 27 | ->addArgument($config['detect_content_type']) 28 | ; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function getKey(): string 35 | { 36 | return 'aws_s3'; 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | public function addConfiguration(NodeDefinition $builder): void 43 | { 44 | $builder 45 | ->children() 46 | ->scalarNode('service_id')->isRequired()->cannotBeEmpty()->end() 47 | ->scalarNode('bucket_name')->isRequired()->cannotBeEmpty()->end() 48 | ->booleanNode('detect_content_type')->defaultFalse()->end() 49 | ->arrayNode('options') 50 | ->addDefaultsIfNotSet() 51 | ->children() 52 | ->scalarNode('directory')->defaultValue('')->end() 53 | ->booleanNode('create')->defaultFalse()->end() 54 | ->scalarNode('acl')->defaultValue('private')->end() 55 | ->end() 56 | ->end() 57 | ->end() 58 | ; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/AzureBlobStorageAdapterFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($id, $definition) 25 | ->addArgument(new Reference($config['blob_proxy_factory_id'])) 26 | ->addArgument($config['container_name']) 27 | ->addArgument($config['create_container']) 28 | ->addArgument($config['detect_content_type']); 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function getKey(): string 35 | { 36 | return 'azure_blob_storage'; 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | public function addConfiguration(NodeDefinition $builder): void 43 | { 44 | $builder 45 | ->validate() 46 | ->ifTrue(function ($v) { 47 | return empty($v['container_name']) && !$v['multi_container_mode']; 48 | }) 49 | ->thenInvalid('You should either provide a container name or enable the multi container mode.') 50 | ->end() 51 | ->children() 52 | ->scalarNode('blob_proxy_factory_id')->isRequired()->cannotBeEmpty()->end() 53 | ->scalarNode('container_name')->isRequired()->end() 54 | ->booleanNode('create_container')->defaultValue(false)->end() 55 | ->booleanNode('detect_content_type')->defaultValue(true)->end() 56 | ->booleanNode('multi_container_mode')->defaultFalse()->end() 57 | ->end() 58 | ; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/DoctrineDbalAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class DoctrineDbalAdapterFactory implements AdapterFactoryInterface 17 | { 18 | /** 19 | * {@inheritDoc} 20 | */ 21 | public function create(ContainerBuilder $container, $id, array $config): void 22 | { 23 | $childDefinition = class_exists('\Symfony\Component\DependencyInjection\ChildDefinition') 24 | ? new ChildDefinition('knp_gaufrette.adapter.doctrine_dbal') 25 | : new DefinitionDecorator('knp_gaufrette.adapter.doctrine_dbal'); 26 | 27 | $definition = $container 28 | ->setDefinition($id, $childDefinition) 29 | ->addArgument(new Reference('doctrine.dbal.' . $config['connection_name'] . '_connection')) 30 | ->addArgument($config['table']) 31 | ; 32 | 33 | if (isset($config['columns'])) { 34 | $definition->addArgument($config['columns']); 35 | } 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | public function getKey(): string 42 | { 43 | return 'doctrine_dbal'; 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | public function addConfiguration(NodeDefinition $builder): void 50 | { 51 | $builder 52 | ->children() 53 | ->scalarNode('connection_name')->isRequired()->cannotBeEmpty()->end() 54 | ->scalarNode('table')->isRequired()->cannotBeEmpty()->end() 55 | ->arrayNode('columns') 56 | ->children() 57 | ->scalarNode('key')->end() 58 | ->scalarNode('content')->end() 59 | ->scalarNode('mtime')->end() 60 | ->scalarNode('checksum')->end() 61 | ->end() 62 | ->end() 63 | ->end() 64 | ; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/FtpAdapterFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($id, $childDefinition) 26 | ->addArgument($config['directory']) 27 | ->addArgument($config['host']) 28 | ->addArgument($config) 29 | ; 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public function getKey(): string 36 | { 37 | return 'ftp'; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public function addConfiguration(NodeDefinition $builder): void 44 | { 45 | $builder 46 | ->children() 47 | ->scalarNode('directory')->isRequired()->end() 48 | ->scalarNode('host')->isRequired()->end() 49 | ->scalarNode('port')->defaultValue(21)->end() 50 | ->scalarNode('username')->defaultNull()->end() 51 | ->scalarNode('password')->defaultNull()->end() 52 | ->scalarNode('timeout')->defaultValue(90)->end() 53 | ->booleanNode('passive')->defaultFalse()->end() 54 | ->booleanNode('create')->defaultFalse()->end() 55 | ->booleanNode('ssl')->defaultFalse()->end() 56 | ->booleanNode('utf8')->defaultFalse()->end() 57 | ->scalarNode('mode') 58 | ->defaultValue(defined('FTP_ASCII') ? FTP_ASCII : null) 59 | ->beforeNormalization() 60 | ->ifString() 61 | ->then(function($v) { return constant($v); }) 62 | ->end() 63 | ->end() 64 | ; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/GoogleCloudStorageAdapterFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($id, $childDefinition) 25 | ->addArgument(new Reference($config['service_id'])) 26 | ->addArgument($config['bucket_name']) 27 | ->addArgument($config['options']) 28 | ->addArgument($config['detect_content_type']) 29 | ; 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public function getKey(): string 36 | { 37 | return 'google_cloud_storage'; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public function addConfiguration(NodeDefinition $builder): void 44 | { 45 | $builder 46 | ->children() 47 | ->scalarNode('service_id')->isRequired()->cannotBeEmpty()->end() 48 | ->scalarNode('bucket_name')->isRequired()->cannotBeEmpty()->end() 49 | ->booleanNode('detect_content_type')->defaultTrue()->end() 50 | ->arrayNode('options') 51 | ->addDefaultsIfNotSet() 52 | ->children() 53 | ->scalarNode('directory')->defaultValue('')->end() 54 | ->scalarNode('acl')->defaultValue('private')->end() 55 | ->scalarNode('project_id')->end() 56 | ->scalarNode('bucket_location')->end() 57 | ->booleanNode('create')->defaultFalse()->end() 58 | ->end() 59 | ->end() 60 | ->end() 61 | ; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/GridFSAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class GridFSAdapterFactory implements AdapterFactoryInterface 17 | { 18 | /** 19 | * {@inheritDoc} 20 | */ 21 | public function create(ContainerBuilder $container, $id, array $config): void 22 | { 23 | $childDefinition = class_exists('\Symfony\Component\DependencyInjection\ChildDefinition') 24 | ? new ChildDefinition('knp_gaufrette.adapter.gridfs') 25 | : new DefinitionDecorator('knp_gaufrette.adapter.gridfs'); 26 | 27 | $container 28 | ->setDefinition($id, $childDefinition) 29 | ->addArgument(new Reference($config['mongogridfs_id'])) 30 | ; 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | public function getKey(): string 37 | { 38 | return 'gridfs'; 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | public function addConfiguration(NodeDefinition $node): void 45 | { 46 | $node 47 | ->children() 48 | ->scalarNode('mongogridfs_id')->isRequired()->cannotBeEmpty()->end() 49 | ->end() 50 | ; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/InMemoryAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class InMemoryAdapterFactory implements AdapterFactoryInterface 16 | { 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | public function create(ContainerBuilder $container, $id, array $config): void 21 | { 22 | $childDefinition = class_exists('\Symfony\Component\DependencyInjection\ChildDefinition') 23 | ? new ChildDefinition('knp_gaufrette.adapter.in_memory') 24 | : new DefinitionDecorator('knp_gaufrette.adapter.in_memory'); 25 | 26 | $container 27 | ->setDefinition($id, $childDefinition) 28 | ->replaceArgument(0, $config['files']) 29 | ; 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public function getKey(): string 36 | { 37 | return 'in_memory'; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public function addConfiguration(NodeDefinition $node): void 44 | { 45 | $node 46 | ->children() 47 | ->arrayNode('files') 48 | ->fixXmlConfig('file') 49 | ->useAttributeAsKey('filename') 50 | ->prototype('array') 51 | ->children() 52 | ->scalarNode('content')->end() 53 | ->scalarNode('checksum')->end() 54 | ->scalarNode('mtime')->end() 55 | ->end() 56 | ->end() 57 | ->end() 58 | ->end() 59 | ; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/LocalAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class LocalAdapterFactory implements AdapterFactoryInterface 16 | { 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | public function create(ContainerBuilder $container, $id, array $config): void 21 | { 22 | $childDefinition = class_exists('\Symfony\Component\DependencyInjection\ChildDefinition') 23 | ? new ChildDefinition('knp_gaufrette.adapter.local') 24 | : new DefinitionDecorator('knp_gaufrette.adapter.local'); 25 | 26 | $container 27 | ->setDefinition($id, $childDefinition) 28 | ->replaceArgument(0, $config['directory']) 29 | ->replaceArgument(1, $config['create']) 30 | ; 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | public function getKey(): string 37 | { 38 | return 'local'; 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | public function addConfiguration(NodeDefinition $node): void 45 | { 46 | $node 47 | ->children() 48 | ->scalarNode('directory')->isRequired()->end() 49 | ->booleanNode('create')->defaultTrue()->end() 50 | ->end() 51 | ; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/PhpseclibSftpAdapterFactory.php: -------------------------------------------------------------------------------- 1 | setDefinition($id, $childDefinition) 27 | ->addArgument(new Reference($config['phpseclib_sftp_id'])) 28 | ->addArgument($config['directory']) 29 | ->addArgument($config['create']) 30 | ; 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | public function getKey(): string 37 | { 38 | return 'phpseclib_sftp'; 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | public function addConfiguration(NodeDefinition $builder): void 45 | { 46 | $builder 47 | ->children() 48 | ->scalarNode('phpseclib_sftp_id')->isRequired()->end() 49 | ->scalarNode('directory')->defaultNull()->end() 50 | ->booleanNode('create')->defaultFalse()->end() 51 | ->end() 52 | ; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/SafeLocalAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class SafeLocalAdapterFactory implements AdapterFactoryInterface 16 | { 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | public function create(ContainerBuilder $container, $id, array $config): void 21 | { 22 | $childDefinition = class_exists('\Symfony\Component\DependencyInjection\ChildDefinition') 23 | ? new ChildDefinition('knp_gaufrette.adapter.safe_local') 24 | : new DefinitionDecorator('knp_gaufrette.adapter.safe_local'); 25 | 26 | $container 27 | ->setDefinition($id, $childDefinition) 28 | ->replaceArgument(0, $config['directory']) 29 | ->replaceArgument(1, $config['create']) 30 | ; 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | public function getKey(): string 37 | { 38 | return 'safe-local'; 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | public function addConfiguration(NodeDefinition $node): void 45 | { 46 | $node 47 | ->children() 48 | ->scalarNode('directory')->isRequired()->end() 49 | ->booleanNode('create')->defaultTrue()->end() 50 | ->end() 51 | ; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DependencyInjection/Factory/ServiceAdapterFactory.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class ServiceAdapterFactory implements AdapterFactoryInterface 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function create(ContainerBuilder $container, $id, array $config): void 19 | { 20 | $container->setAlias($id, $config['id']); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function getKey(): string 27 | { 28 | return 'service'; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function addConfiguration(NodeDefinition $builder): void 35 | { 36 | $builder 37 | ->children() 38 | ->scalarNode('id')->isRequired()->end() 39 | ->end() 40 | ; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DependencyInjection/FactoryConfiguration.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class FactoryConfiguration implements ConfigurationInterface 14 | { 15 | /** 16 | * Generates the configuration tree builder 17 | */ 18 | public function getConfigTreeBuilder(): TreeBuilder 19 | { 20 | $treeBuilder = new TreeBuilder('knp_gaufrette'); 21 | $rootNode = $treeBuilder->getRootNode(); 22 | $rootNode 23 | ->ignoreExtraKeys() 24 | ->fixXmlConfig('factory', 'factories') 25 | ->children() 26 | ->arrayNode('factories') 27 | ->prototype('scalar')->end() 28 | ->end() 29 | ->end() 30 | ->end() 31 | ; 32 | 33 | return $treeBuilder; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DependencyInjection/KnpGaufretteExtension.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class KnpGaufretteExtension extends Extension 21 | { 22 | private $factories; 23 | 24 | /** 25 | * Loads the extension 26 | * 27 | * @param array $configs 28 | * @param ContainerBuilder $container 29 | * 30 | * @return void 31 | */ 32 | public function load(array $configs, ContainerBuilder $container): void 33 | { 34 | $config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs); 35 | 36 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 37 | $loader->load('gaufrette.xml'); 38 | 39 | $adapters = array(); 40 | 41 | foreach ($config['adapters'] as $name => $adapter) { 42 | $adapters[$name] = $this->createAdapter($name, $adapter, $container, $this->factories); 43 | } 44 | 45 | $map = array(); 46 | foreach ($config['filesystems'] as $name => $filesystem) { 47 | $map[$name] = $this->createFilesystem($name, $filesystem, $container, $adapters); 48 | } 49 | 50 | $container->getDefinition('knp_gaufrette.filesystem_map') 51 | ->setPublic(true) 52 | ->replaceArgument(0, $map); 53 | 54 | if (isset($config['stream_wrapper'])) { 55 | $container->setParameter('knp_gaufrette.stream_wrapper.protocol', $config['stream_wrapper']['protocol']); 56 | $container->setParameter('knp_gaufrette.stream_wrapper.filesystems', $config['stream_wrapper']['filesystems']); 57 | } 58 | } 59 | 60 | /** 61 | * @return ConfigurationInterface|null 62 | */ 63 | public function getConfiguration(array $configs, ContainerBuilder $container): ?ConfigurationInterface 64 | { 65 | // first assemble the adapter factories 66 | $factoryConfig = new FactoryConfiguration(); 67 | $config = $this->processConfiguration($factoryConfig, $configs); 68 | $factories = $this->createAdapterFactories($config, $container); 69 | 70 | // then normalize the configs 71 | return new MainConfiguration($factories); 72 | } 73 | 74 | private function createAdapter($name, array $config, ContainerBuilder $container, array $factories): string 75 | { 76 | foreach ($config as $key => $adapter) { 77 | if (array_key_exists($key, $factories)) { 78 | $id = sprintf('gaufrette.%s_adapter', $name); 79 | $factories[$key]->create($container, $id, $adapter); 80 | 81 | return $id; 82 | } 83 | } 84 | 85 | throw new \LogicException(sprintf('The adapter \'%s\' is not configured.', $name)); 86 | } 87 | 88 | /** 89 | * @return Reference a reference to the created filesystem 90 | */ 91 | private function createFilesystem($name, array $config, ContainerBuilder $container, array $adapters): Reference 92 | { 93 | if (!array_key_exists($config['adapter'], $adapters)) { 94 | throw new \LogicException(sprintf('The adapter \'%s\' is not defined.', $config['adapter'])); 95 | } 96 | 97 | $adapter = $adapters[$config['adapter']]; 98 | $id = sprintf('gaufrette.%s_filesystem', $name); 99 | 100 | $definition = class_exists('\Symfony\Component\DependencyInjection\ChildDefinition') 101 | ? new ChildDefinition('knp_gaufrette.filesystem') 102 | : new DefinitionDecorator('knp_gaufrette.filesystem'); 103 | 104 | $container 105 | ->setDefinition($id, $definition) 106 | ->replaceArgument(0, new Reference($adapter)) 107 | ; 108 | 109 | if (!empty($config['alias'])) { 110 | $container->getDefinition($id)->setPublic(false); 111 | $container->setAlias($config['alias'], new Alias($id, true)); 112 | } 113 | 114 | return new Reference($id); 115 | } 116 | 117 | /** 118 | * Creates the adapter factories 119 | * 120 | * @param array $config 121 | * @param ContainerBuilder $container 122 | */ 123 | private function createAdapterFactories($config, ContainerBuilder $container): array 124 | { 125 | if (null !== $this->factories) { 126 | return $this->factories; 127 | } 128 | 129 | // load bundled adapter factories 130 | $tempContainer = new ContainerBuilder(); 131 | $parameterBag = $container->getParameterBag(); 132 | $loader = new XmlFileLoader($tempContainer, new FileLocator(__DIR__.'/../Resources/config')); 133 | 134 | $loader->load('adapter_factories.xml'); 135 | 136 | // load user-created adapter factories 137 | foreach ($config['factories'] as $factory) { 138 | $loader->load($parameterBag->resolveValue($factory)); 139 | } 140 | 141 | $services = $tempContainer->findTaggedServiceIds('gaufrette.adapter.factory'); 142 | $factories = []; 143 | foreach (array_keys($services) as $id) { 144 | $factory = $tempContainer->get($id); 145 | $factories[str_replace('-', '_', $factory->getKey())] = $factory; 146 | } 147 | 148 | return $this->factories = $factories; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /DependencyInjection/MainConfiguration.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class MainConfiguration implements ConfigurationInterface 15 | { 16 | private $factories; 17 | 18 | /** 19 | * Constructor 20 | * 21 | * @param array $factories 22 | */ 23 | public function __construct(array $factories) 24 | { 25 | $this->factories = $factories; 26 | } 27 | 28 | /** 29 | * Generates the configuration tree builder 30 | * 31 | * @return TreeBuilder 32 | */ 33 | public function getConfigTreeBuilder(): TreeBuilder 34 | { 35 | $treeBuilder = new TreeBuilder('knp_gaufrette'); 36 | $rootNode = $treeBuilder->getRootNode(); 37 | $this->addAdaptersSection($rootNode, $this->factories); 38 | $this->addFilesystemsSection($rootNode); 39 | $this->addStreamWrapperSection($rootNode); 40 | 41 | $rootNode 42 | // add a faux-entry for factories, so that no validation error is thrown 43 | ->fixXmlConfig('factory', 'factories') 44 | ->children() 45 | ->arrayNode('factories')->ignoreExtraKeys()->end() 46 | ->end() 47 | ; 48 | 49 | return $treeBuilder; 50 | } 51 | 52 | private function addAdaptersSection(ArrayNodeDefinition $node, array $factories): void 53 | { 54 | $adapterNodeBuilder = $node 55 | ->fixXmlConfig('adapter') 56 | ->children() 57 | ->arrayNode('adapters') 58 | ->useAttributeAsKey('name') 59 | ->prototype('array') 60 | ->performNoDeepMerging() 61 | ->children() 62 | ; 63 | 64 | foreach ($factories as $name => $factory) { 65 | $factoryNode = $adapterNodeBuilder->arrayNode($name)->canBeUnset(); 66 | 67 | $factory->addConfiguration($factoryNode); 68 | } 69 | } 70 | 71 | private function addFilesystemsSection(ArrayNodeDefinition $node): void 72 | { 73 | $node 74 | ->fixXmlConfig('filesystem') 75 | ->children() 76 | ->arrayNode('filesystems') 77 | ->useAttributeAsKey('name') 78 | ->prototype('array') 79 | ->children() 80 | ->scalarNode('adapter')->isRequired()->end() 81 | ->scalarNode('alias')->defaultNull()->end() 82 | ->end() 83 | ->end() 84 | ->end() 85 | ; 86 | } 87 | 88 | private function addStreamWrapperSection(ArrayNodeDefinition $node): void 89 | { 90 | $node 91 | ->children() 92 | ->arrayNode('stream_wrapper') 93 | ->children() 94 | ->scalarNode('protocol')->defaultValue('gaufrette')->treatNullLike('gaufrette')->end() 95 | ->arrayNode('filesystems') 96 | ->beforeNormalization() 97 | ->ifTrue(function ($array) { 98 | return !(bool)count(array_filter(array_keys($array), 'is_string')); 99 | }) 100 | ->then(function ($array) { 101 | return array_combine($array, $array); 102 | }) 103 | ->end() 104 | ->useAttributeAsKey('key') 105 | ->prototype('scalar') 106 | ->end() 107 | ->end() 108 | ->end() 109 | ->end() 110 | ->end() 111 | ; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /FilesystemMap.php: -------------------------------------------------------------------------------- 1 | maps = $maps; 29 | } 30 | 31 | /** 32 | * Retrieves a filesystem by its name. 33 | * 34 | * @param string $name name of a filesystem 35 | * 36 | * @throw \InvalidArgumentException if the filesystem does not exist 37 | */ 38 | public function get($name): FilesystemInterface 39 | { 40 | if (!$this->has($name)) { 41 | throw new \InvalidArgumentException(sprintf('No filesystem is registered for name "%s"', $name)); 42 | } 43 | 44 | return $this->maps[$name]; 45 | } 46 | 47 | /** 48 | * @param string $name name of a filesystem 49 | * 50 | * @return bool 51 | */ 52 | public function has($name): bool 53 | { 54 | return isset($this->maps[$name]); 55 | } 56 | 57 | public function getIterator(): \Traversable 58 | { 59 | return new \ArrayIterator($this->maps); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /KnpGaufretteBundle.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class KnpGaufretteBundle extends Bundle 15 | { 16 | /** 17 | * @return void 18 | */ 19 | public function boot(): void 20 | { 21 | parent::boot(); 22 | 23 | if (!$this->container->hasParameter('knp_gaufrette.stream_wrapper.protocol') 24 | || !$this->container->hasParameter('knp_gaufrette.stream_wrapper.filesystems')) { 25 | return; 26 | } 27 | 28 | StreamWrapper::register($this->container->getParameter('knp_gaufrette.stream_wrapper.protocol')); 29 | $wrapperFsMap = StreamWrapper::getFilesystemMap(); 30 | 31 | $fileSystems = $this->container->getParameter('knp_gaufrette.stream_wrapper.filesystems'); 32 | 33 | /* 34 | * If there are no filesystems configured to be wrapped, 35 | * all filesystems within the map will be wrapped. 36 | */ 37 | if (empty($fileSystems)) { 38 | $fileSystems = $this->container->get('knp_gaufrette.filesystem_map'); 39 | foreach ($fileSystems as $domain => $fileSystem) { 40 | $wrapperFsMap->set($domain, $fileSystem); 41 | } 42 | } else { 43 | foreach ($fileSystems as $domain => $fileSystem) { 44 | $wrapperFsMap->set($domain, $this->container->get('knp_gaufrette.filesystem_map')->get($fileSystem)); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011 by Antoine Hérault 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Gaufrette Bundle 2 | ================ 3 | 4 | [![Build Status](https://github.com/KnpLabs/KnpGaufretteBundle/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/KnpLabs/KnpGaufretteBundle/actions/workflows/ci.yml) 5 | 6 | Provides a [Gaufrette][gaufrette-homepage] integration for your Symfony projects. 7 | 8 | [![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) 9 | 10 | About Gaufrette 11 | =============== 12 | 13 | Gaufrette is a PHP library providing a filesystem abstraction layer. 14 | This abstraction layer allows you to develop applications without needing to know where all their media files will be stored or how. 15 | 16 | Documentation is available the [official page of Gaufrette][gaufrette-homepage]. 17 | 18 | Installation 19 | ============ 20 | 21 | ## Prerequisites 22 | 23 | As this bundle is an integration for Symfony of the [Gaufrette][gaufrette-homepage] library, it requires you to first install [Gaufrette][gaufrette-homepage] in your project. 24 | 25 | Note that, you need to install separately the adapters you want to use. You can find more details about these packages [here](https://github.com/KnpLabs/Gaufrette#metapackages-for-adapters), 26 | and the full list adapters [on packagist](https://packagist.org/packages/gaufrette/). 27 | 28 | ## With composer 29 | 30 | ```bash 31 | composer require knplabs/knp-gaufrette-bundle 32 | ``` 33 | 34 | ## Register the bundle 35 | 36 | You must register the bundle in your kernel: 37 | 38 | ``` php 39 | ['all' => true], 44 | ]; 45 | ``` 46 | 47 | Configuration 48 | ============= 49 | 50 | The Gaufrette bundle allows you to declare your filesystems as services without having to reach into the famous "Service Container". 51 | Indeed, you can do it with the configuration! 52 | 53 | The configuration of the Gaufrette bundle is divided into two parts: the `adapters` and the `filesystems`. 54 | 55 | ## Configuring the Adapters 56 | 57 | ``` yaml 58 | # config/packages/knp_gaufrette.yaml 59 | knp_gaufrette: 60 | adapters: 61 | foo: 62 | local: 63 | directory: /path/to/my/filesystem 64 | ``` 65 | 66 | The defined adapters are then used to create the filesystems. 67 | 68 | You can use on of these adapters: 69 | * [Local Adapter](Resources/docs/adapters/local.md) 70 | * [Safe Local Adapter](Resources/docs/adapters/safe_local.md) 71 | * [Service](Resources/docs/adapters/service.md) 72 | * [In Memory](Resources/docs/adapters/memory.md) 73 | * [Azure Blob Storage](Resources/docs/adapters/azure.md) 74 | * [GridFS](Resources/docs/adapters/gridfs.md) 75 | * [MogileFS](Resources/docs/adapters/mogilefs.md) 76 | * [Ftp](Resources/docs/adapters/ftp.md) 77 | * [Sftp](Resources/docs/adapters/sftp.md) 78 | * [Phpseclib Sftp](Resources/docs/adapters/phpseclib_sftp.md) 79 | * [Apc](Resources/docs/adapters/apc.md) 80 | * [AsyncAws S3](Resources/docs/adapters/async-aws-s3.md) 81 | * [AWS S3](Resources/docs/adapters/awss3.md) 82 | * [Open Cloud](Resources/docs/adapters/opencloud.md) 83 | * [GoogleCloudStorage](Resources/docs/adapters/googlecloud.md) 84 | * [Cache](Resources/docs/adapters/cache.md) 85 | * [Stream Wrapper](Resources/docs/stream.md) 86 | * [Doctrine DBAL](Resources/docs/adapters/doctrine_dbal.md) 87 | * [Dropbox](Resources/docs/adapters/dropbox.md) 88 | 89 | ## Configuring the Filesystems 90 | 91 | ``` yaml 92 | # config/packages/knp_gaufrette.yaml 93 | knp_gaufrette: 94 | adapters: 95 | # ... 96 | filesystems: 97 | bar: 98 | adapter: foo 99 | alias: foo_filesystem 100 | ``` 101 | 102 | Each defined filesystem must have an `adapter` with its value set to an adapter's key. 103 | The filesystem defined above will result in a service with id `gaufrette.bar_filesystem`. 104 | The `alias` parameter allows us to define an alias for it (`foo_filesystem` in this case). 105 | 106 | The filesystem map 107 | ================== 108 | 109 | You can access all declared filesystems through the map service. 110 | In the previous exemple, we declared a `bar` filesystem: 111 | 112 | ``` php 113 | $container->get('knp_gaufrette.filesystem_map')->get('bar'); 114 | ``` 115 | 116 | Returns the `bar` instance of `Gaufrette\Filesystem`. 117 | 118 | Use cases 119 | ================== 120 | 121 | [Check out](https://github.com/KnpLabs/KnpGaufretteBundle/blob/master/Resources/docs/use-case-examples.md) basic examples of the library. 122 | 123 | [gaufrette-homepage]: https://github.com/KnpLabs/Gaufrette 124 | 125 | ## Maintainers 126 | 127 | KNPLabs is looking for maintainers ([see why](https://knplabs.com/en/blog/news-for-our-foss-projects-maintenance)). 128 | 129 | If you are interested, feel free to open a PR to ask to be added as a maintainer. 130 | 131 | We’ll be glad to hear from you :) 132 | -------------------------------------------------------------------------------- /Resources/config/adapter_factories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Resources/config/gaufrette.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Knp\Bundle\GaufretteBundle\FilesystemMap 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Resources/docs/adapters/apc.md: -------------------------------------------------------------------------------- 1 | # Apc 2 | 3 | A non-persistent adapter, use it in the dev environment, in demo sites, ... 4 | 5 | ## Parameters 6 | 7 | * `prefix` The prefix to this filesystem (APC 'namespace', it is recommended that this end in a dot '.') *(required)* 8 | * `ttl` Time to live *(default 0)* 9 | 10 | ## Example 11 | 12 | ``` yaml 13 | # app/config/config.yml 14 | knp_gaufrette: 15 | adapters: 16 | foo: 17 | apc: 18 | prefix: APC 'namespace' prefix 19 | ttl: 0 20 | ``` -------------------------------------------------------------------------------- /Resources/docs/adapters/async-aws-s3.md: -------------------------------------------------------------------------------- 1 | # AsyncAws S3 2 | 3 | ## Notes 4 | 5 | Note that when you create a bucket it [is located in a specific region](http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html). 6 | The full list of regions is available [here](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region). 7 | 8 | ## Adapter for Amazon S3 SDK v3 (recommended) 9 | 10 | ``` 11 | composer require async-aws/simple-s3 12 | ``` 13 | 14 | ### Service definition 15 | 16 | An example service definition of the `AsyncAws\SimpleS3\SimpleS3Client`: 17 | 18 | ```yaml 19 | services: 20 | acme.async_aws_s3.client: 21 | class: AsyncAws\SimpleS3\SimpleS3Client 22 | arguments: 23 | - region: '%amazon_s3.region%' 24 | accessKeyId: '%amazon_s3.key%' 25 | accessKeySecret: '%amazon_s3.secret%/K7MDENG/bPxRfiCYEXAMPLEKEY' 26 | ``` 27 | 28 | ### Parameters 29 | 30 | * `service_id` The service id of the `AsyncAws\SimpleS3\SimpleS3Client` to use. *(required)* 31 | * `bucket_name` The name of the S3 bucket to use. *(required)* 32 | * `detect_content_type` Auto detect the content type. *(default false)* 33 | * `options` A list of additional options passed to the adapter. 34 | * `create` Whether to create the bucket if it doesn't exist. *(default false)* 35 | * `directory` A directory to operate in. *(default '')* 36 | This directory will be created in the root of the bucket and all files will be read and written there. 37 | * `acl` Default ACL to apply to the objects 38 | 39 | ### Example 40 | 41 | Once the service is set up use its key as the `service_id` in the gaufrette configuration: 42 | 43 | ``` yaml 44 | # app/config/config.yml 45 | knp_gaufrette: 46 | adapters: 47 | profile_photos: 48 | async_aws_s3: 49 | service_id: 'acme.async_aws_s3.client' 50 | bucket_name: 'images' 51 | detect_content_type: true 52 | options: 53 | directory: 'profile_photos' 54 | ``` 55 | -------------------------------------------------------------------------------- /Resources/docs/adapters/awss3.md: -------------------------------------------------------------------------------- 1 | # AWS S3 2 | 3 | ## Table of contents 4 | 5 | - [Amazon SDK v3 (recommended)](#adapter-for-amazon-s3-sdk-v3-recommended) 6 | - [Amazon SDK v2](#adapter-for-amazon-s3-sdk-v2) 7 | - [Amazon SDK v1 (deprecated)](#adapter-for-amazon-s3-sdk-v1-deprecated-by-amazon) 8 | 9 | ## Notes 10 | 11 | Note that when you create a bucket it [is located in a specific region](http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html). 12 | The full list of regions is available [here](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region). 13 | 14 | ## Adapter for Amazon S3 SDK v3 (recommended) 15 | 16 | ``` 17 | composer require aws/aws-sdk-php:^3.0 18 | ``` 19 | 20 | ### Service definition 21 | 22 | An example service definition of the `Aws\S3\S3Client`: 23 | 24 | ```yaml 25 | services: 26 | acme.aws_s3.client: 27 | class: Aws\S3\S3Client 28 | factory: [Aws\S3\S3Client, 'factory'] 29 | arguments: 30 | - 31 | version: latest 32 | region: %amazon_s3.region% 33 | credentials: 34 | key: %amazon_s3.key% 35 | secret: %amazon_s3.secret% 36 | ``` 37 | 38 | ### Parameters 39 | 40 | * `service_id` The service id of the `Aws\S3\S3Client` to use. *(required)* 41 | * `bucket_name` The name of the S3 bucket to use. *(required)* 42 | * `detect_content_type` Auto detect the content type. *(default false)* 43 | * `options` A list of additional options passed to the adapter. 44 | * `create` Whether to create the bucket if it doesn't exist. *(default false)* 45 | * `directory` A directory to operate in. *(default '')* 46 | This directory will be created in the root of the bucket and all files will be read and written there. 47 | * `acl` Default ACL to apply to the objects 48 | 49 | ### Example 50 | 51 | Once the service is set up use its key as the `service_id` in the gaufrette configuration: 52 | 53 | ``` yaml 54 | # app/config/config.yml 55 | knp_gaufrette: 56 | adapters: 57 | profile_photos: 58 | aws_s3: 59 | service_id: 'acme.aws_s3.client' 60 | bucket_name: 'images' 61 | detect_content_type: true 62 | options: 63 | directory: 'profile_photos' 64 | ``` 65 | 66 | ## Adapter for Amazon S3 SDK v2 67 | 68 | ``` 69 | composer require aws/aws-sdk-php:^2.0 70 | ``` 71 | 72 | ### Service definition 73 | 74 | An example service definition of the `Aws\S3\S3Client`: 75 | 76 | ```yaml 77 | services: 78 | acme.aws_s3.client: 79 | class: Aws\S3\S3Client 80 | factory: [Aws\S3\S3Client, 'factory'] 81 | arguments: 82 | - 83 | key: %amazon_s3.key% 84 | secret: %amazon_s3.secret% 85 | region: %amazon_s3.region% 86 | ``` 87 | 88 | ### Parameters 89 | 90 | * `service_id` The service id of the `Aws\S3\S3Client` to use. *(required)* 91 | * `bucket_name` The name of the S3 bucket to use. *(required)* 92 | * `detect_content_type` Auto detect the content type. *(default false)* 93 | * `options` A list of additional options passed to the adapter. 94 | * `create` Whether to create the bucket if it doesn't exist. *(default false)* 95 | * `directory` A directory to operate in. *(default '')* 96 | This directory will be created in the root of the bucket and all files will be read and written there. 97 | * `acl` Default ACL to apply to the objects 98 | 99 | ### Example 100 | 101 | Once the service is set up use its key as the `service_id` in the gaufrette configuration: 102 | 103 | ``` yaml 104 | # app/config/config.yml 105 | knp_gaufrette: 106 | adapters: 107 | profile_photos: 108 | aws_s3: 109 | service_id: 'acme.aws_s3.client' 110 | bucket_name: 'images' 111 | detect_content_type: true 112 | options: 113 | directory: 'profile_photos' 114 | ``` 115 | 116 | ## Adapter for Amazon S3 SDK v1 (DEPRECATED by Amazon) 117 | 118 | ``` 119 | composer require amazonwebservices/aws-sdk-for-php 120 | ``` 121 | 122 | ### Service definition 123 | 124 | To use the Amazon S3 adapter you need to provide a valid `AmazonS3` instance (as defined in the Amazon SDK). This can 125 | easily be set up as using Symfony's service configuration: 126 | 127 | ``` yaml 128 | # app/config/config.yml 129 | services: 130 | amazonS3: 131 | class: AmazonS3 132 | arguments: 133 | options: 134 | key: '%aws_key%' 135 | secret: '%aws_secret_key%' 136 | ``` 137 | 138 | ### Parameters 139 | 140 | * `amazon_s3_id`: the id of the AmazonS3 service used for the underlying connection 141 | * `bucket_name`: the name of the bucket to use 142 | * `options`: additional (optional) settings 143 | * `directory`: the directory to use, within the specified bucket 144 | * `region` 145 | * `create` 146 | 147 | ### Example 148 | 149 | Once the service is set up use its key as the `amazon_s3_id` in the gaufrette configuration: 150 | 151 | ``` yaml 152 | # app/config/config.yml 153 | knp_gaufrette: 154 | adapters: 155 | foo: 156 | amazon_s3: 157 | amazon_s3_id: amazonS3 158 | bucket_name: foo_bucket 159 | options: 160 | directory: foo_directory 161 | ``` 162 | 163 | Note that the SDK seems to have some issues with bucket names with dots in them, e.g. "com.mycompany.bucket" seems to have issues but "com-mycompany-bucket" works. 164 | -------------------------------------------------------------------------------- /Resources/docs/adapters/azure.md: -------------------------------------------------------------------------------- 1 | # Azure Blob Storage 2 | 3 | Adapter for Microsoft Azure Blob Storage service. To use this adapter you need to install the 4 | [Azure SDK for php](http://www.windowsazure.com/en-us/develop/php/common-tasks/download-php-sdk/) into your project. 5 | 6 | Further more you need a valid *connection string* and you must define a Blob Proxy factory service with it. You can use 7 | the default `\Gaufrette\Adapter\AzureBlobStorage\BlobProxyFactory` this way: 8 | 9 | ``` yaml 10 | # app/config/config.yml 11 | services: 12 | azure_blob_proxy_factory: 13 | class: Gaufrette\Adapter\AzureBlobStorage\BlobProxyFactory 14 | arguments: [%azure_blob_storage_connection_string%] 15 | ``` 16 | 17 | You must set the parameter `azure_blob_storage_connection_string` to contain your windows azure blob storage connection 18 | string. You can retrieve your connection string in your [Windows Azure management console](https://manage.windowsazure.com). 19 | It looks like this: `BlobEndpoint=http://.blob.core.windows.net/;AccountName=;AccountKey=`. 20 | 21 | ## Parameters 22 | 23 | * `blob_proxy_factory_id` Reference to the blob proxy factory service 24 | * `container_name` The name of the container (*optional if the `multi_container_mode` is enabled*) 25 | * `create_container` Boolean value that indicates whether to create the container if it does not exists (*optional*: default *false*) 26 | * `detect_content_type` Boolean value that indicates whether to auto determinate and set the content type on new blobs (*optional*: default *true*) 27 | * `multi_container_mode` Boolean value that indicates whether multi-container mode is enabled (the container will be determined using the first part of the file key) (*optional*: default *false*) 28 | 29 | ## Example 30 | 31 | ``` yaml 32 | # app/config/config.yml 33 | knp_gaufrette: 34 | adapters: 35 | foo: 36 | azure_blob_storage: 37 | blob_proxy_factory_id: azure_blob_proxy_factory 38 | container_name: my_container 39 | create_container: true 40 | ``` 41 | 42 | With multi-container mode enabled: 43 | 44 | ``` yaml 45 | # app/config/config.yml 46 | knp_gaufrette: 47 | adapters: 48 | foo: 49 | azure_blob_storage: 50 | blob_proxy_factory_id: azure_blob_proxy_factory 51 | container_name: ~ 52 | mult_container_mode: true 53 | ``` 54 | -------------------------------------------------------------------------------- /Resources/docs/adapters/cache.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | Adapter which allows you to cache other adapters 4 | 5 | ## Parameters 6 | 7 | * `source` The source adapter that must be cached *(required)* 8 | * `cache` The adapter used to cache the source *(required)* 9 | * `ttl` Time to live, in seconds *(default 0)* 10 | * `serializer` The adapter used to cache serializations *(default null)* 11 | 12 | ## Example 13 | 14 | ``` yaml 15 | # app/config/config.yml 16 | knp_gaufrette: 17 | adapters: 18 | media_ftp: 19 | ftp: 20 | host: example.com 21 | username: user 22 | password: pass 23 | directory: /example/ftp 24 | create: true 25 | mode: FTP_BINARY 26 | media_apc: 27 | apc: 28 | prefix: APC 'namespace' prefix 29 | ttl: 0 30 | media_cache: 31 | cache: 32 | source: media_ftp 33 | cache: media_apc 34 | ttl: 7200 35 | filesystems: 36 | media: 37 | adapter: media_cache 38 | ``` 39 | -------------------------------------------------------------------------------- /Resources/docs/adapters/doctrine_dbal.md: -------------------------------------------------------------------------------- 1 | # Doctrine DBAL 2 | 3 | Adapter that allows you to store data into a database. 4 | 5 | ## Parameters 6 | 7 | * `connection_name` The doctrine dbal connection name like `default` 8 | * `table` The table name like `media_data` 9 | * `key`: The primary key in the table 10 | * `content`: The field name of the file content 11 | * `mtime`: The field name of the timestamp 12 | * `checksum`: The field name of the checksum 13 | 14 | ## Example 15 | 16 | ``` yaml 17 | # app/config/config.yml 18 | knp_gaufrette: 19 | adapters: 20 | database: 21 | doctrine_dbal: 22 | connection_name: default 23 | table: data 24 | columns: 25 | key: id 26 | content: text 27 | mtime: date 28 | checksum: checksum 29 | ``` 30 | -------------------------------------------------------------------------------- /Resources/docs/adapters/dropbox.md: -------------------------------------------------------------------------------- 1 | # Dropbox 2 | 3 | Adapter for Dropbox. In order to use it, you should add `dropbox-php/dropbox-php` as your composer dependency. 4 | 5 | ## Parameters 6 | 7 | * `api_id` The id of the service that provides Dropbox API access. 8 | 9 | ## Example 10 | 11 | > In order to get a Dropbox token and token_secret, you need to add a new Dropbox App in your account, and then you'll need to go through the oAuth authorization process 12 | 13 | ``` yaml 14 | # app/config/config.yml 15 | knp_gaufrette: 16 | adapters: 17 | foo: 18 | dropbox: 19 | api_id: acme_test.dropbox.api 20 | ``` 21 | 22 | In your AcmeTestBundle, add following service definitions: 23 | 24 | ``` yaml 25 | # src/Acme/TestBundle/Resources/config/services.yml 26 | parameters: 27 | acme_test.dropbox.key: my_consumer_key 28 | acme_test.dropbox.secret: my_consumer_secret 29 | acme_test.dropbox.token: some_token 30 | acme_test.dropbox.token_secret: some_token_secret 31 | 32 | services: 33 | acme_test.dropbox.oauth: 34 | class: Dropbox_OAuth_Curl 35 | arguments: [%acme_test.dropbox.key%, %acme_test.dropbox.secret%] 36 | calls: 37 | - [setToken, ["%acme_test.dropbox.token%", "%acme_test.dropbox.token_secret%"]] 38 | acme_test.dropbox.api: 39 | class: Dropbox_API 40 | arguments: [@acme_test.dropbox.oauth, "sandbox"] 41 | ``` -------------------------------------------------------------------------------- /Resources/docs/adapters/ftp.md: -------------------------------------------------------------------------------- 1 | # FTP 2 | 3 | Adapter for FTP. 4 | 5 | ## Parameters 6 | 7 | * `directory` The remote directory *(required)* 8 | * `host` FTP host *(required)* 9 | * `username` FTP username *(default null)* 10 | * `password` FTP password *(default null)* 11 | * `port` FTP port *(default 21)* 12 | * `passive` FTP passive mode *(default false)* 13 | * `create` Whether to create the directory if it does not exist *(default false)* 14 | * `mode` FTP transfer mode *(defaut FTP_ASCII)* 15 | 16 | ## Example 17 | 18 | ``` yaml 19 | # app/config/config.yml 20 | knp_gaufrette: 21 | adapters: 22 | foo: 23 | ftp: 24 | host: example.com 25 | username: user 26 | password: pass 27 | directory: /example/ftp 28 | create: true 29 | mode: FTP_BINARY 30 | ``` 31 | -------------------------------------------------------------------------------- /Resources/docs/adapters/googlecloud.md: -------------------------------------------------------------------------------- 1 | # Google Cloud 2 | 3 | Adapter for Google APIs Client Library for PHP. 4 | 5 | ``` 6 | composer require google/apiclient:^2.12 7 | ``` 8 | 9 | ## Parameters 10 | 11 | * `service_id` The service id of the `\Google_Service_Storage` to use. *(required)* 12 | * `bucket_name` The name of the GCS bucket to use. *(required)* 13 | * `detect_content_type`: if `true` will detect the content type for each file *(default `true`)* 14 | * `options` A list of additional options passed to the adapter. 15 | * `directory` A directory to operate in. *(default '')* 16 | * `acl` Whether the uploaded files should be `private` or `public` *(default `private`)* 17 | * `create`: if `true`, gaufrette will create the bucket automatically *(default `false`)* 18 | * `project_id`: required for automatic bucket creation 19 | * `bucket_location`: required for automatic bucket creation 20 | 21 | ## Defining services 22 | 23 | You need to create a custom factory service which creates a `\Google\Client` and authorizes with the correct scopes 24 | and then returns a `\Google\Service\Storage` class connected to the client class: 25 | 26 | ```yaml 27 | services: 28 | app.google_cloud_storage.service: 29 | class: Google\Service\Storage 30 | factory: ['App\Factory\GoogleCloudStorageServiceFactory', 'createGoogleCloudStorage'] 31 | ``` 32 | 33 | The factory may be something like this: 34 | 35 | ```php 36 | setApplicationName('Gaufrette'); 52 | $client->addScope(\Google\Service\Storage::DEVSTORAGE_FULL_CONTROL); 53 | $client->useApplicationDefaultCredentials(); 54 | 55 | return new \Google\Service\Storage($client); 56 | } 57 | } 58 | ``` 59 | 60 | ⚠️ We do not recommend to set credentials directly in the factory, [read how to make a service factory with Symfony](https://symfony.com/doc/current/service_container/factories.html). 61 | 62 | 63 | ## Example 64 | 65 | Once the service is set up use its key as the `service_id` in the gaufrette configuration: 66 | 67 | ``` yaml 68 | # app/config/config.yml 69 | knp_gaufrette: 70 | adapters: 71 | profile_photos: 72 | google_cloud_storage: 73 | service_id: 'app.google_cloud_storage.service' 74 | bucket_name: 'images' 75 | options: 76 | directory: 'profile_photos' 77 | ``` 78 | -------------------------------------------------------------------------------- /Resources/docs/adapters/gridfs.md: -------------------------------------------------------------------------------- 1 | # MongoDB GridFS 2 | 3 | Adapter that allows you to use a MongoDB GridFS for storing files. 4 | 5 | ## Parameters 6 | 7 | * `mongogridfs_id` The id of the service that provides MongoGridFS object instance for adapter *(required)* 8 | 9 | ## Example 10 | 11 | ``` yaml 12 | # app/config/config.yml 13 | knp_gaufrette: 14 | adapters: 15 | foo: 16 | gridfs: 17 | mongogridfs_id: acme_test.gridfs 18 | ``` 19 | 20 | In your AcmeTestBundle, add following service definitions: 21 | 22 | ``` yaml 23 | # src/Acme/TestBundle/Resources/config/services.yml 24 | parameters: 25 | acme_test.mongo.server: "mongodb://localhost:27017" 26 | acme_test.mongo.options: 27 | connect: true 28 | acme_test.mongodb.name: "test_database" 29 | acme_test.gridfs.prefix: "fs" #Default 30 | services: 31 | acme_test.mongo: 32 | class: Mongo 33 | arguments: [%acme_test.mongo.server%, %acme_test.mongo.options%] 34 | acme_test.mongodb: 35 | class: MongoDB 36 | arguments: [@acme_test.mongo, %acme_test.mongodb.name%] 37 | acme_test.gridfs: 38 | class: MongoGridFS 39 | arguments: [@acme_test.mongodb, %acme_test.gridfs.prefix%] 40 | ``` 41 | 42 | Note that it is possible to prepare MongoGridFS service any way you like. This is just one way to do it. 43 | -------------------------------------------------------------------------------- /Resources/docs/adapters/local.md: -------------------------------------------------------------------------------- 1 | # Local Adapter 2 | 3 | A simple local filesystem based adapter. 4 | 5 | ## Parameters 6 | 7 | * `directory` The directory of the filesystem *(required)* 8 | * `create` Whether to create the directory if it does not exist *(default true)* 9 | 10 | ## Example 11 | 12 | ``` yaml 13 | # app/config/config.yml 14 | knp_gaufrette: 15 | adapters: 16 | foo: 17 | local: 18 | directory: /path/to/my/filesystem 19 | create: true 20 | ``` 21 | -------------------------------------------------------------------------------- /Resources/docs/adapters/memory.md: -------------------------------------------------------------------------------- 1 | # In Memory 2 | 3 | Adapter for test purposes, it stores files in an internal array. 4 | 5 | ## Parameters 6 | 7 | * `files` An array of files *(optional)* 8 | 9 | The `files` is an array of files where each file is a sub-array having the `content`, `checksum` and `mtime` optional keys. 10 | 11 | ## Example 12 | 13 | ``` yaml 14 | # app/config/config.yml 15 | knp_gaufrette: 16 | adapters: 17 | foo: 18 | in_memory: 19 | files: 20 | 'file1.txt': ~ 21 | 'file2.txt': 22 | content: Some content 23 | checksum: abc1efg2hij3 24 | mtime: 123456890123 25 | ``` 26 | -------------------------------------------------------------------------------- /Resources/docs/adapters/mogilefs.md: -------------------------------------------------------------------------------- 1 | # MogileFS 2 | 3 | Adapter that allows you to use MogileFS for storing files. 4 | 5 | ## Parameters 6 | 7 | * `domain` MogileFS domain 8 | * `hosts` Available trackers 9 | 10 | ## Example 11 | 12 | ``` yaml 13 | # app/config/config.yml 14 | knp_gaufrette: 15 | adapters: 16 | foo: 17 | mogilefs: 18 | domain: foobar 19 | hosts: ["192.168.0.1:7001", "192.168.0.2:7001"] 20 | ``` 21 | -------------------------------------------------------------------------------- /Resources/docs/adapters/phpseclib_sftp.md: -------------------------------------------------------------------------------- 1 | # Phpseclib Sftp 2 | 3 | Adapter for phpseclib SFTP (SSH-FTP). 4 | 5 | ## Parameters 6 | 7 | * `phpseclib_sftp_id` The id of the service that provides SFTP access. 8 | * `directory` The remote directory *(default null)*. 9 | * `create` Whether to create the directory if it does not exist *(default false)*. 10 | 11 | ## Example 12 | 13 | ``` yaml 14 | # app/config/config.yml 15 | knp_gaufrette: 16 | adapters: 17 | foo: 18 | phpseclib_sftp: 19 | phpseclib_sftp_id: acme_test.sftp 20 | directory: /example/sftp 21 | create: true 22 | ``` 23 | 24 | In your AcmeTestBundle, add following service definitions: 25 | 26 | ``` yaml 27 | # src/Acme/TestBundle/Resources/config/services.yml 28 | parameters: 29 | acme_test.ssh.host: my_host_name 30 | acme_test.ssh.username: user_name 31 | acme_test.ssh.password: some_secret 32 | 33 | services: 34 | acme_test.sftp: 35 | class: phpseclib\Net\SFTP #for phpseclib 1.x you need to use Net_SFTP 36 | arguments: [%acme_test.ssh.host%] 37 | calls: 38 | - [login, [%acme_test.ssh.username%, %acme_test.ssh.password%]] 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /Resources/docs/adapters/safe_local.md: -------------------------------------------------------------------------------- 1 | # Safe Local Adapter 2 | 3 | Almost as simple as the **local** adapter, but it encodes key to avoid having to deal with the directories structure. 4 | 5 | ## Parameters 6 | 7 | * `directory` The directory of the filesystem *(required)* 8 | * `create` Whether to create the directory if it does not exist *(default true)* 9 | 10 | ## Example 11 | 12 | ``` yaml 13 | # app/config/config.yml 14 | knp_gaufrette: 15 | adapters: 16 | foo: 17 | safe_local: 18 | directory: /path/to/my/filesystem 19 | create: true 20 | ``` 21 | -------------------------------------------------------------------------------- /Resources/docs/adapters/service.md: -------------------------------------------------------------------------------- 1 | # Service 2 | 3 | Allows you to use a user defined adapter service. 4 | 5 | ## Parameters 6 | 7 | * `id` The id of the service *(required)* 8 | 9 | ## Example 10 | 11 | ``` yaml 12 | # app/config/config.yml 13 | knp_gaufrette: 14 | adapters: 15 | foo: 16 | service: 17 | id: my.adapter.service 18 | ``` 19 | -------------------------------------------------------------------------------- /Resources/docs/adapters/sftp.md: -------------------------------------------------------------------------------- 1 | # SFTP (SSH-FTP) 2 | 3 | Adapter for SFTP (SSH-FTP). 4 | 5 | ## Parameters 6 | 7 | * `sftp_id` The id of the service that provides SFTP access. 8 | * `directory` The remote directory *(default null)*. 9 | * `create` Whether to create the directory if it does not exist *(default false)*. 10 | 11 | ## Example 12 | 13 | ``` yaml 14 | # app/config/config.yml 15 | knp_gaufrette: 16 | adapters: 17 | foo: 18 | sftp: 19 | sftp_id: acme_test.sftp 20 | directory: /example/sftp 21 | create: true 22 | ``` 23 | 24 | In your AcmeTestBundle, add following service definitions: 25 | 26 | ``` yaml 27 | # src/Acme/TestBundle/Resources/config/services.yml 28 | parameters: 29 | acme_test.ssh.host: my_host_name 30 | acme_test.ssh.username: user_name 31 | acme_test.ssh.password: some_secret 32 | 33 | services: 34 | acme_test.ssh.configuration: 35 | class: Ssh\Configuration 36 | arguments: [%acme_test.ssh.host%] 37 | 38 | acme_test.ssh.authentication: 39 | class: Ssh\Authentication\Password 40 | arguments: [%acme_test.ssh.username%, %acme_test.ssh.password%] 41 | 42 | acme_test.ssh.session: 43 | class: Ssh\Session 44 | arguments: [@acme_test.ssh.configuration, @acme_test.ssh.authentication] 45 | 46 | acme_test.sftp: 47 | class: Ssh\Sftp 48 | arguments: [@acme_test.ssh.session] 49 | ``` 50 | -------------------------------------------------------------------------------- /Resources/docs/stream.md: -------------------------------------------------------------------------------- 1 | # Stream Wrapper 2 | 3 | The `stream_wrapper` settings allow you to register filesystems with a specified domain and 4 | then use as a stream wrapper anywhere in your code like: 5 | `gaufrette://domain/file.txt` 6 | 7 | ## Parameters 8 | 9 | * `protocol` The protocol name like `gaufrette://…` *(default gaufrette)* 10 | * `filesystems` An array that contains filesystems that you want to register to this stream_wrapper. 11 | If you set array keys these will be used as an alias for the filesystem (see examples below) *(default all filesystems without aliases)* 12 | 13 | ## Example 1 14 | 15 | Using default settings, the protocol is "gaufrette" and all filesystems will be served 16 | 17 | ``` yaml 18 | # app/config/config.yml 19 | knp_gaufrette: 20 | adapters: 21 | backup: #... 22 | amazon: #... 23 | 24 | filesystems: 25 | backup1: 26 | adapter: backup 27 | amazonS3: 28 | adapter: amazon 29 | 30 | stream_wrapper: ~ 31 | ``` 32 | 33 | ``` 34 | gaufrette://backup1/... 35 | gaufrette://amazonS3/... 36 | ``` 37 | 38 | ## Example 2 39 | 40 | We define the protocol as "data", all filesystem will still be served (by default) 41 | 42 | ``` yaml 43 | # app/config/config.yml 44 | knp_gaufrette: 45 | filesystems: 46 | #... 47 | 48 | stream_wrapper: 49 | protocol: data 50 | ``` 51 | 52 | ``` 53 | data://backup1/... 54 | data://amazonS3/... 55 | ``` 56 | 57 | ## Example 3 58 | 59 | We define the protocol as data and define which filesystem(s) will be available 60 | 61 | ``` yaml 62 | # app/config/config.yml 63 | knp_gaufrette: 64 | filesystems: 65 | #... 66 | 67 | stream_wrapper: 68 | protocol: data 69 | filesystems: 70 | - backup1 71 | ``` 72 | 73 | ``` 74 | data://backup1/... (works since it is defined above) 75 | data://amazonS3/... (will not be available) 76 | ``` 77 | 78 | ## Example 4 79 | 80 | We define the protocol as data and define which filesystems will be available using array keys to set domain aliases 81 | 82 | ``` yaml 83 | # app/config/config.yml 84 | knp_gaufrette: 85 | filesystems: 86 | #... 87 | 88 | stream_wrapper: 89 | protocol: data 90 | filesystems: 91 | backup: backup1 92 | pictures: amazonS3 93 | ``` 94 | 95 | ``` 96 | data://backup/... 97 | data://pictures/... 98 | ``` 99 | -------------------------------------------------------------------------------- /Resources/docs/use-case-examples.md: -------------------------------------------------------------------------------- 1 | # Symfony use cases 2 | 3 | The goal is to suggest how to handle generic tasks with the framework. 4 | 5 | ---------- 6 | 7 | ## Upload a file 8 | 9 | Depending on the number of filesystems you have, you may need to retrieve the one you need with the `knp_gaufrette.filesystem_map` service. 10 | Otherwise you simply need to inject the `knp_gaufrette.filesystem` service. 11 | 12 | Then, once you fetch the associated adapter, you are able to perform the desired operation and apply additional logic depending the current adapter. 13 | 14 | In the case of the `AwsS3` adapter: 15 | 16 | ```php 17 | /** @var AwsS3 $adapter */ 18 | $adapter = $this->filesystem->getAdapter(); 19 | 20 | // When we don't set the correct content type manually S3 will assume application/octet-stream 21 | // and therefore will offer the file as download to the user. 22 | // (cf https://florian.ec/articles/upload-files-to-amazon-s3-with-symfony2-and-gaufrette/) 23 | if ($adapter instanceof AwsS3) { 24 | $adapter->setMetadata($filename, ['contentType' => 'application/pdf']); 25 | } 26 | 27 | $adapter->write($myAbsolutePath, file_get_contents($tempPath)); 28 | ``` 29 | 30 | ## Download a file stream 31 | 32 | Another common need would be to download a file from a filesystem. Instead of loading the whole file content in the memory, why not using a stream ? 33 | 34 | Gaufrette provides a default stream wrapper and you could use it easily in a response for example: 35 | 36 | ```php 37 | public function downloadAction() 38 | { 39 | $fileStream = sprintf('gaufrette://your_defined_fs/%s', 'absolute/path/to/file.pdf'); 40 | 41 | $response = new BinaryFileResponse($fileStream); 42 | $response->headers->set('Content-Type', 'application/pdf'); 43 | $response->setContentDisposition( 44 | ResponseHeaderBag::DISPOSITION_ATTACHMENT, 45 | 'file.pdf' 46 | ); 47 | 48 | return $response; 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /Tests/FilesystemMapTest.php: -------------------------------------------------------------------------------- 1 | filesystemMap = new FilesystemMap(array('amazon_fs' => $this->getFilesystem(), 'local_fs' => $this->getFilesystem())); 15 | } 16 | 17 | /** 18 | * @test 19 | */ 20 | public function shouldGetFilesystemByKey() 21 | { 22 | if(class_exists('Gaufrette\FilesystemInterface')) { 23 | $this->assertInstanceOf('Gaufrette\FilesystemInterface', $this->filesystemMap->get('amazon_fs'), 'should get filesystem object by key'); 24 | $this->assertInstanceOf('Gaufrette\FilesystemInterface', $this->filesystemMap->get('local_fs'), 'should get filesystem object by key'); 25 | } else { 26 | $this->assertInstanceOf('Gaufrette\Filesystem', $this->filesystemMap->get('amazon_fs'), 'should get filesystem object by key'); 27 | $this->assertInstanceOf('Gaufrette\Filesystem', $this->filesystemMap->get('local_fs'), 'should get filesystem object by key'); 28 | } 29 | 30 | } 31 | 32 | /** 33 | * @test 34 | */ 35 | public function shouldNotGetFilesystemWhenKeyWasNotSet() 36 | { 37 | $this->expectException(\InvalidArgumentException::class); 38 | 39 | $this->filesystemMap->get('test'); 40 | } 41 | 42 | /** 43 | * @return Gaufrette\Filesystem 44 | */ 45 | private function getFilesystem() 46 | { 47 | return $this->getMockBuilder('Gaufrette\Filesystem') 48 | ->disableOriginalConstructor() 49 | ->getMock(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Functional/ConfigurationTest.php: -------------------------------------------------------------------------------- 1 | cacheDir = __DIR__.'/Resources/cache'; 17 | if (file_exists($this->cacheDir)) { 18 | $filesystem = new Filesystem(); 19 | $filesystem->remove($this->cacheDir); 20 | } 21 | 22 | mkdir($this->cacheDir, 0777, true); 23 | 24 | $this->kernel = new TestKernel('test', false); 25 | $this->kernel->boot(); 26 | } 27 | 28 | public function tearDown(): void 29 | { 30 | if (file_exists($this->cacheDir)) { 31 | $filesystem = new Filesystem(); 32 | $filesystem->remove($this->cacheDir); 33 | } 34 | } 35 | 36 | /** 37 | * @test 38 | * @functional 39 | */ 40 | public function shouldAllowForFilesystemAlias() 41 | { 42 | $this->assertInstanceOf('Gaufrette\Filesystem', $this->kernel->getContainer()->get('foo_filesystem')); 43 | } 44 | 45 | /** 46 | * @test 47 | * @functional 48 | */ 49 | public function shouldWorkForOtherEnv() 50 | { 51 | $kernel = new TestKernel('dev', false); 52 | $kernel->boot(); 53 | 54 | $container = $kernel->getContainer(); 55 | $this->assertInstanceOf('Gaufrette\Filesystem', $container->get('foo_filesystem')); 56 | } 57 | 58 | /** 59 | * @test 60 | * @functional 61 | */ 62 | public function shouldAllowAccessToAllPublicServices() 63 | { 64 | $this->assertInstanceOf('Knp\Bundle\GaufretteBundle\FilesystemMap', $this->kernel->getContainer()->get('knp_gaufrette.filesystem_map')); 65 | } 66 | 67 | /** 68 | * @test 69 | */ 70 | public function shouldAllowAccessToFilesystemThoughFilesystemMap() 71 | { 72 | $this->assertInstanceOf('Gaufrette\Filesystem', $this->kernel->getContainer()->get('knp_gaufrette.filesystem_map')->get('foo')); 73 | } 74 | 75 | /** 76 | * @test 77 | * @functional 78 | */ 79 | public function shouldAllowAccessToLocalFilesystem() 80 | { 81 | $this->assertInstanceOf('Gaufrette\Adapter\Local', $this->kernel->getContainer()->get('foo_filesystem')->getAdapter()); 82 | } 83 | 84 | /** 85 | * @test 86 | * @functional 87 | */ 88 | public function shouldAllowAccessToFtpFilesystem() 89 | { 90 | $this->assertInstanceOf('Gaufrette\Adapter\Ftp', $this->kernel->getContainer()->get('ftp_filesystem')->getAdapter()); 91 | } 92 | 93 | /** 94 | * @test 95 | * @functional 96 | */ 97 | public function shouldAllowToNotConfigureStreamWrapper() 98 | { 99 | $this->assertFalse($this->kernel->getContainer()->hasParameter('knp_gaufrette.stream_wrapper.protocol')); 100 | } 101 | 102 | /** 103 | * @test 104 | * @functional 105 | */ 106 | public function shouldConfigureStreamWrapperWithDefaultValues() 107 | { 108 | $kernel = new TestKernel('wrapper_1', false); 109 | $kernel->boot(); 110 | $container = $kernel->getContainer(); 111 | 112 | $this->assertTrue($container->hasParameter('knp_gaufrette.stream_wrapper.protocol')); 113 | $this->assertEquals('gaufrette', $container->getParameter('knp_gaufrette.stream_wrapper.protocol')); 114 | 115 | $wrapperFsMap = StreamWrapper::getFilesystemMap(); 116 | 117 | $expectedDomains = array( 118 | 'foo', 119 | 'ftp', 120 | ); 121 | 122 | foreach ($expectedDomains as $eachExpectedDomain) { 123 | $this->assertTrue($wrapperFsMap->has($eachExpectedDomain)); 124 | } 125 | } 126 | 127 | /** 128 | * @test 129 | * @functional 130 | */ 131 | public function shouldAllowToDefineProtocolOfStreamWrapper() 132 | { 133 | $kernel = new TestKernel('wrapper_2', false); 134 | $kernel->boot(); 135 | $container = $kernel->getContainer(); 136 | 137 | $this->assertTrue($container->hasParameter('knp_gaufrette.stream_wrapper.protocol')); 138 | $this->assertEquals('tada', $container->getParameter('knp_gaufrette.stream_wrapper.protocol')); 139 | } 140 | 141 | /** 142 | * @test 143 | * @functional 144 | */ 145 | public function shouldAllowToDefineWhichFileSystemsShouldBeAddToStreamWrapper() 146 | { 147 | $kernel = new TestKernel('wrapper_2', false); 148 | $kernel->boot(); 149 | $container = $kernel->getContainer(); 150 | $fileSystems = $container->getParameter('knp_gaufrette.stream_wrapper.filesystems'); 151 | 152 | $this->assertEquals(array('pictures' => 'foo', 'text' => 'ftp'), $fileSystems); 153 | 154 | $wrapperFsMap = StreamWrapper::getFilesystemMap(); 155 | 156 | foreach($fileSystems as $key => $fs) { 157 | $this->assertTrue($wrapperFsMap->has($key)); 158 | } 159 | } 160 | 161 | /** 162 | * @test 163 | * @functional 164 | */ 165 | public function shouldAllowToDefineFileSystemsWithoutDomain() 166 | { 167 | $kernel = new TestKernel('wrapper_3', false); 168 | $kernel->boot(); 169 | $container = $kernel->getContainer(); 170 | $fileSystems = $container->getParameter('knp_gaufrette.stream_wrapper.filesystems'); 171 | 172 | $this->assertTrue($container->hasParameter('knp_gaufrette.stream_wrapper.protocol')); 173 | $this->assertEquals('tada', $container->getParameter('knp_gaufrette.stream_wrapper.protocol')); 174 | $this->assertEquals(array('ftp' => 'ftp'), $fileSystems); 175 | 176 | $wrapperFsMap = StreamWrapper::getFilesystemMap(); 177 | 178 | foreach($fileSystems as $key => $fs) { 179 | $this->assertTrue($wrapperFsMap->has($key)); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Tests/Functional/Resources/config/config.yml: -------------------------------------------------------------------------------- 1 | knp_gaufrette: 2 | adapters: 3 | foo_local: 4 | local: 5 | directory: "%kernel.project_dir%" 6 | create: true 7 | foo_ftp: 8 | ftp: 9 | host: example.com 10 | username: user 11 | password: pass 12 | directory: /example/ftp 13 | create: true 14 | mode: FTP_BINARY 15 | 16 | filesystems: 17 | foo: 18 | adapter: foo_local 19 | alias: foo_filesystem 20 | ftp: 21 | adapter: foo_ftp 22 | alias: ftp_filesystem 23 | -------------------------------------------------------------------------------- /Tests/Functional/Resources/config/config_dev.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | -------------------------------------------------------------------------------- /Tests/Functional/Resources/config/config_test.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | 4 | knp_gaufrette: 5 | adapters: 6 | foo: 7 | in_memory: ~ 8 | -------------------------------------------------------------------------------- /Tests/Functional/Resources/config/config_wrapper_1.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | 4 | knp_gaufrette: 5 | stream_wrapper: ~ 6 | -------------------------------------------------------------------------------- /Tests/Functional/Resources/config/config_wrapper_2.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | 4 | knp_gaufrette: 5 | stream_wrapper: 6 | protocol: tada 7 | filesystems: 8 | pictures: foo 9 | text: ftp 10 | -------------------------------------------------------------------------------- /Tests/Functional/Resources/config/config_wrapper_3.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | 4 | knp_gaufrette: 5 | stream_wrapper: 6 | protocol: tada 7 | filesystems: 8 | - ftp 9 | -------------------------------------------------------------------------------- /Tests/Functional/TestKernel.php: -------------------------------------------------------------------------------- 1 | load(__DIR__.'/Resources/config/config_'.$this->getEnvironment().'.yml'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | UPGRADE FROM 0.2 to 0.3 2 | ======================= 3 | 4 | No known BC breaks. 5 | 6 | UPGRADE FROM 0.1 to 0.2 7 | ======================= 8 | 9 | ### AmazonS3 10 | 11 | * In 0.2 we pass additional options for AmazonS3 Gaufrette provider AmazonS3 config was changed (old way is DEPRECATED) 12 | 13 | before: 14 | 15 | ```yml 16 | knp_gaufrette: 17 | adapters: 18 | adaptername: 19 | amazon_s3: 20 | amazon_s3_id: amazon_s3.service.id 21 | bucket_name: mybucketname 22 | create: true 23 | ``` 24 | 25 | after: 26 | 27 | ```yml 28 | knp_gaufrette: 29 | adapters: 30 | adaptername: 31 | amazon_s3: 32 | amazon_s3_id: amazon_s3.service.id 33 | bucket_name: mybucketname 34 | options: 35 | create: true 36 | ``` 37 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "knplabs/knp-gaufrette-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Allows to easily use the Gaufrette library in a Symfony project", 5 | "keywords": ["file", "filesystem", "media", "abstraction"], 6 | "homepage": "http://knplabs.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Antoine Hérault", 11 | "email": "antoine.herault@gmail.com" 12 | }, 13 | { 14 | "name": "The contributors", 15 | "homepage": "https://github.com/knplabs/KnpGaufretteBundle/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": "^7.4 || ^8.0", 20 | "knplabs/gaufrette": "^0.11", 21 | "symfony/config": "^5.0|^6.0|^7.0", 22 | "symfony/dependency-injection": "^5.0|^6.0|^7.0", 23 | "symfony/http-kernel": "^5.0|^6.0|^7.0" 24 | }, 25 | "require-dev": { 26 | "symfony/phpunit-bridge": "^7.0", 27 | "symfony/console": "^5.0|^6.0|^7.0", 28 | "symfony/filesystem": "^5.0|^6.0|^7.0", 29 | "symfony/yaml": "^5.0|^6.0|^7.0" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Knp\\Bundle\\GaufretteBundle\\": "" 34 | } 35 | }, 36 | "extra": { 37 | "branch-alias": { 38 | "dev-master": "0.8.x-dev" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | . 7 | 8 | 9 | Resources 10 | Tests 11 | vendor 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Tests 22 | 23 | 24 | 25 | --------------------------------------------------------------------------------