Skip to content

Commit

Permalink
Init GridFS bucket from doctrine or configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed May 24, 2024
1 parent e3444b8 commit 75897e0
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 19 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"symfony/options-resolver": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
"doctrine/mongodb-odm-bundle": "^5.0",
"league/flysystem-async-aws-s3": "^3.1",
"league/flysystem-aws-s3-v3": "^3.1",
"league/flysystem-azure-blob-storage": "^3.1",
Expand Down
63 changes: 50 additions & 13 deletions docs/2-cloud-storage-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,53 @@ flysystem:
## MongoDB GridFS
```
composer require league/flysystem-google-cloud-storage
composer require league/flysystem-gridfs
```

The MongoDB GridFS storage requires a `MongoDB\GridFS\Bucket` instance.
If you use `DoctrineMongoDBODMBundle`, the

```yaml
# config/packages/flysystem.yaml

flysystem:
storages:
users.storage:
adapter: 'gridfs'
options:
# Name of a Doctrine MongoDB ODM connection
doctrine_connection: 'default'
# Use the default DB from the Doctrine MongoDB ODM configuration
database: ~
bucket: 'fs'
```
You can also use the full configuration:
```yaml
# config/packages/flysystem.yaml

flysystem:
storages:
users.storage:
adapter: 'gridfs'
options:
# MongoDB client configuration
mongodb_uri: '%env(MONGODB_URI)%'
mongodb_uri_options: []
mongodb_driver_options: []
# Database name is required
database: '%env(MONGODB_DB)%'
bucket: 'fs'
```
```dotenv
# .env

MONGODB_URI=mongodb://127.0.0.1:27017/
MONGODB_DB=flysystem
```

For a more advanced configuration, create a service [`MongoDB\GridFS\Bucket`](https://www.mongodb.com/docs/php-library/current/tutorial/gridfs/):

```yaml
# config/packages/flysystem.yaml
Expand All @@ -175,30 +218,24 @@ services:
mongodb_database:
class: 'MongoDB\Database'
factory: ['mongodb_client', 'selectDatabase']
arguments: ['%env(MONGODB_DATABASE)%']
arguments: ['%env(MONGODB_DB)%']

mongodb_gridfs_bucket:
class: 'MongoDB\GridFS\Bucket'
factory: ['@mongodb_database', 'selectGridFSBucket']
arguments:
- disableMD5: true
bucketName: fs

flysystem:
storages:
users.storage:
adapter: 'gridfs'
options:
# Service name
bucket: 'mongodb_gridfs_bucket'
```
```dotenv
# .env

MONGODB_URI=mongodb://127.0.0.1:27017/
MONGODB_DATABASE=flysystem
```

Note: if the DoctrineMongoDBODMBundle is enabled on the projection,
`doctrine_mongodb.odm.default_connection` provides the `MongoDB\Client` service.

## Next
[Interacting with FTP and SFTP servers](https://github.com/thephpleague/flysystem-bundle/blob/master/docs/3-interacting-with-ftp-and-sftp-servers.md)
55 changes: 49 additions & 6 deletions src/Adapter/Builder/GridFSAdapterDefinitionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@

namespace League\FlysystemBundle\Adapter\Builder;

use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
use Doctrine\ODM\MongoDB\DocumentManager;
use League\Flysystem\GridFS\GridFSAdapter;
use MongoDB\Client;
use MongoDB\GridFS\Bucket;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand All @@ -38,17 +42,56 @@ protected function getRequiredPackages(): array

protected function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefault('bucket', Bucket::class);
$resolver->setAllowedTypes('bucket', 'string');

$resolver->setDefault('prefix', '');
$resolver->setAllowedTypes('prefix', 'string');
$resolver->define('bucket')->default(null)->allowedTypes('string', 'null');
$resolver->define('prefix')->default('')->allowedTypes('string');
$resolver->define('database')->default(null)->allowedTypes('string', 'null');
$resolver->define('doctrine_connection')->allowedTypes('string');
$resolver->define('mongodb_uri')->allowedTypes('string');
$resolver->define('mongodb_uri_options')->default([])->allowedTypes('array');
$resolver->define('mongodb_driver_options')->default([])->allowedTypes('array');
}

protected function configureDefinition(Definition $definition, array $options, ?string $defaultVisibilityForDirectories): void
{
if (isset($options['doctrine_connection'])) {
$bucketDefinition = new Definition(Bucket::class);
$bucketDefinition->setFactory([self::class, 'initializeBucketFromDocumentManager']);
$bucketDefinition->setArguments([
new Reference(sprintf('doctrine_mongodb.odm.%s_document_manager', $options['doctrine_connection'])),
$options['database'],
$options['bucket'],
]);
} elseif (isset($options['mongodb_uri'])) {
$bucketDefinition = new Definition(Bucket::class);
$bucketDefinition->setFactory([self::class, 'initializeBucketFromConfig']);
$bucketDefinition->setArguments([
$options['mongodb_uri'],
$options['mongodb_uri_options'],
$options['mongodb_driver_options'],
$options['database'] ?? throw new InvalidArgumentException('MongoDB "database" name is required for Flysystem GridFS configuration'),
$options['bucket'],
]);
} elseif (!$options['bucket']) {
throw new InvalidArgumentException('Flysystem GridFS configuration requires a "bucket" service name, a "mongodb_uri" or a "doctrine_connection" name');
}

$definition->setClass(GridFSAdapter::class);
$definition->setArgument(0, new Reference($options['bucket']));
$definition->setArgument(0, $bucketDefinition ?? new Reference($options['bucket']));
$definition->setArgument(1, $options['prefix']);
}

public static function initializeBucketFromDocumentManager(DocumentManager $documentManager, ?string $dbName, ?string $bucketName): Bucket
{
return $documentManager
->getClient()
->selectDatabase($dbName ?? $documentManager->getConfiguration()->getDefaultDB())
->selectGridFSBucket(['bucketName' => $bucketName ?? 'fs', 'disableMD5' => true]);
}

public static function initializeBucketFromConfig(string $uri, array $uriOptions, array $driverOptions, ?string $dbName, ?string $bucketName): Bucket
{
return (new Client($uri, $uriOptions, $driverOptions))
->selectDatabase($dbName)
->selectGridFSBucket(['bucketName' => $bucketName ?? 'fs', 'disableMD5' => true]);
}
}
97 changes: 97 additions & 0 deletions tests/Adapter/Builder/GridFSAdapterDefinitionBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

/*
* This file is part of the flysystem-bundle project.
*
* (c) Titouan Galopin <galopintitouan@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Tests\League\FlysystemBundle\Adapter\Builder;

use Doctrine\ODM\MongoDB\Configuration;
use Doctrine\ODM\MongoDB\DocumentManager;
use League\Flysystem\GridFS\GridFSAdapter;
use League\FlysystemBundle\Adapter\Builder\GridFSAdapterDefinitionBuilder;
use MongoDB\Client;
use MongoDB\GridFS\Bucket;
use PHPUnit\Framework\TestCase;

class GridFSAdapterDefinitionBuilderTest extends TestCase
{
public function createBuilder(): GridFSAdapterDefinitionBuilder
{
return new GridFSAdapterDefinitionBuilder();
}

public function provideValidOptions(): \Generator
{
yield 'doctrine_minimal' => [[
'doctrine_connection' => 'default',
]];

yield 'doctrine_full' => [[
'doctrine_connection' => 'custom',
'database' => 'testing',
'bucket' => 'avatars',
]];

yield 'config_minimal' => [[
'mongodb_uri' => 'mongodb://localhost:27017/',
'database' => 'testing',
]];

yield 'config_full' => [[
'mongodb_uri' => 'mongodb://server1:27017,server2:27017/',
'mongodb_uri_options' => ['appname' => 'flysystem'],
'mongodb_driver_options' => ['disableClientPersistence' => false],
'database' => 'testing',
'bucket' => 'avatars',
]];

yield 'service' => [[
'bucket' => 'bucket',
]];
}

/**
* @dataProvider provideValidOptions
*/
public function testCreateDefinition($options)
{
$this->assertSame(GridFSAdapter::class, $this->createBuilder()->createDefinition($options, null)->getClass());
}

public function testInitializeBucketFromDocumentManager()
{
$client = new Client();
$config = new Configuration();
$config->setDefaultDB('testing');
$dm = $this->createMock(DocumentManager::class);
$dm->expects($this->once())->method('getClient')->willReturn($client);
$dm->expects($this->once())->method('getConfiguration')->willReturn($config);

$bucket = GridFSAdapterDefinitionBuilder::initializeBucketFromDocumentManager($dm, null, 'avatars');

$this->assertInstanceOf(Bucket::class, $bucket);
$this->assertSame('testing', $bucket->getDatabaseName());
$this->assertSame('avatars', $bucket->getBucketName());
}

public function testInitializeBucketFromConfig()
{
$bucket = GridFSAdapterDefinitionBuilder::initializeBucketFromConfig(
'mongodb://server:27017/',
['appname' => 'flysystem'],
['disableClientPersistence' => false],
'testing',
'avatars'
);

$this->assertInstanceOf(Bucket::class, $bucket);
$this->assertSame('testing', $bucket->getDatabaseName());
$this->assertSame('avatars', $bucket->getBucketName());
}
}

0 comments on commit 75897e0

Please sign in to comment.