Skip to content

Commit

Permalink
CS-5747: create gridfs-config bundle
Browse files Browse the repository at this point in the history
- implemented business logic
  • Loading branch information
VikVlas authored and vsoroka committed Oct 20, 2020
0 parents commit c96a12a
Show file tree
Hide file tree
Showing 20 changed files with 2,802 additions and 0 deletions.
23 changes: 23 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
OroPlatform

The MIT License (MIT)

Copyright (c) 2013, Oro, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# OroGridFsConfigBundle

OroGridFsConfigBundle provides configuration enhancements for Oro applications to enable usage of [GridFS Documentation](https://docs.mongodb.com/manual/core/gridfs/) as filesystem.

Please see [documentation](https://doc.oroinc.com/master/backend/bundles/platform/GridFSConfigBundle/) for more details.
31 changes: 31 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "oro/gridfs-config",
"description": "GridFS adapter configuration for Gaufrette",
"type": "symfony-bundle",
"keywords": ["Oro", "OroPlatform", "Mongo", "GridFs"],
"homepage": "https://github.com/oroinc/gridfs-config",
"license": "MIT",
"autoload": {
"psr-4": {"Oro\\Bundle\\GridFSConfigBundle\\": "src/Oro/Bundle/GridFSConfigBundle"},
"exclude-from-classmap": ["/Tests/"]
},
"authors": [
{
"name": "Oro, Inc",
"homepage": "http://oroinc.com"
}
],
"require": {
"oro/platform": "3.1.*",
"ext-mongodb": "*",
"mongodb/mongodb": "^1.1",
"knplabs/knp-gaufrette-bundle": "0.3.*"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
}
}
117 changes: 117 additions & 0 deletions src/Oro/Bundle/GridFSConfigBundle/Adapter/GridFS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace Oro\Bundle\GridFSConfigBundle\Adapter;

use Gaufrette\Adapter\GridFS as BaseGridFS;
use Oro\Bundle\GridFSConfigBundle\GridFS\Bucket;

/**
* Gaufrette adapter for the GridFS filesystem on MongoDB database.
*
* For prevent duplicates in mongodb fs.files collection:
* the same filename, but one with length=0, another - with real length, unique index on filename.
* Removed "metadata" on write, added "contentType", removed begining "/":
* required for nginx gridFs module for send content properly.
*/
class GridFS extends BaseGridFS
{
/** @var Bucket */
private $bucket;

/**
* @param Bucket $bucket
*/
public function __construct(Bucket $bucket)
{
parent::__construct($bucket);
$this->bucket = $bucket;
}

/**
* {@inheritdoc}
*/
public function read($key)
{
return parent::read($this->formatKey($key));
}

/**
* {@inheritdoc}
*/
public function write($key, $content)
{
if (empty($content)) {
return 0;
}

// remove old file with same filename if one exist
$this->delete($key);

$stream = $this->getBucket()->openUploadStream(
$this->formatKey($key),
['contentType' => $this->guessContentType($content)]
);

try {
return fwrite($stream, $content);
} finally {
fclose($stream);
}

return false;
}

/**
* {@inheritDoc}
*/
public function exists($key)
{
return parent::exists($this->formatKey($key));
}

/**
* {@inheritDoc}
*/
public function delete($key)
{
return parent::delete($this->formatKey($key));
}

/**
* {@inheritDoc}
*/
public function rename($sourceKey, $targetKey)
{
return parent::rename($this->formatKey($sourceKey), $this->formatKey($targetKey));
}

/**
* @return Bucket
*/
public function getBucket(): Bucket
{
return $this->bucket;
}

/**
* @param string $content
*
* @return string
*/
protected function guessContentType(string $content): string
{
$fileInfo = new \finfo(FILEINFO_MIME_TYPE);

return $fileInfo->buffer($content);
}

/**
* @param string $key
*
* @return string
*/
private function formatKey(string $key): string
{
return ltrim($key, '/');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Oro\Bundle\GridFSConfigBundle\DependencyInjection\Factory;

use Knp\Bundle\GaufretteBundle\DependencyInjection\Factory\AdapterFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Factory for create GridFs Adapter
*/
class GridFSAdapterFactory implements AdapterFactoryInterface
{
public const DSN_STRING_PARAMETER = 'mongodb_gridfs_dsn';

/**
* {@inheritdoc}
*/
public function create(ContainerBuilder $container, $id, array $config)
{
$dbConfig = $config[self::DSN_STRING_PARAMETER];
preg_match('|mongodb:\/\/.*\/(?<db>\w+)$|', $dbConfig, $matches);

$driverManagerDefinition = new ChildDefinition('oro.mongodb.driver.manager');
$driverManagerDefinition->addArgument($dbConfig);
$container->setDefinition('oro.mongodb.driver.manager.' . $id, $driverManagerDefinition);

$bucketDefinition = new ChildDefinition('oro.gridfs.bucket');
$bucketDefinition->addArgument($driverManagerDefinition);
$bucketDefinition->addArgument($matches['db']);
$container->setDefinition('oro.gridfs.bucket.' . $id, $bucketDefinition);

$adapterDefinition = new ChildDefinition('oro_gridfs.adapter.gridfs');
$adapterDefinition->addArgument($bucketDefinition);
$container->setDefinition($id, $adapterDefinition);
}

/**
* {@inheritdoc}
*/
public function getKey()
{
return 'oro_gridfs';
}

/**
* {@inheritdoc}
*/
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode(self::DSN_STRING_PARAMETER)->isRequired()->cannotBeEmpty()->end()
->end();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace Oro\Bundle\GridFSConfigBundle\DependencyInjection;

use Oro\Bundle\GridFSConfigBundle\DependencyInjection\Factory\GridFSAdapterFactory;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class OroGridFSConfigExtension extends Extension implements PrependExtensionInterface
{
private const PARAM_MONGODB_DSN_PREFIX = 'mongodb_gridfs_dsn_';

/**
* @{inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}

/**
* @{inheritdoc}
*/
public function prepend(ContainerBuilder $container)
{
// register oro_gridfs gaufrette adapter
$container->setParameter('oro_gridfs.config_dir', __DIR__.'/../Resources/config');
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('oro_gridfs.yml');

//process configuration in mongodb_gridfs_dsn_* parameters
$this->processContainerParameters($container);
}

/**
* @param ContainerBuilder $container
*/
private function processContainerParameters(ContainerBuilder $container): void
{
$parametergrConfigs = $this->getGridfsDsnConfigs($container);
if (count($parametergrConfigs) === 0) {
return;
}

$gaufretteConfigs = $container->getExtensionConfig('knp_gaufrette');
$adapterNames = $this->collectConfiguredGaufretteAdaptersNames($gaufretteConfigs);

$config = [];
$prefixLength = strlen(self::PARAM_MONGODB_DSN_PREFIX);
foreach ($parametergrConfigs as $gridfsDsnConfigKey => $dsnString) {
$adapterName = substr($gridfsDsnConfigKey, $prefixLength);
if (!in_array($adapterName, $adapterNames)) {
throw new \RuntimeException(
sprintf('Wrong Gaufrette DSN configuration. "%s" adapter cannot be found', $adapterName)
);
}
$config[$adapterName] = [
'oro_gridfs' => [GridFSAdapterFactory::DSN_STRING_PARAMETER => $dsnString],
];
}

$gaufretteConfigs[] = ['adapters' => $config];
$container->setExtensionConfig('knp_gaufrette', $gaufretteConfigs);
}

/**
* @param ContainerBuilder $container
*
* @return array
*/
private function getGridfsDsnConfigs(ContainerBuilder $container): array
{
$parametersConfigs = $container->getParameterBag()->all();
return array_filter(
$parametersConfigs,
function ($key) {
return strpos($key, self::PARAM_MONGODB_DSN_PREFIX) === 0;
},
ARRAY_FILTER_USE_KEY
);
}

/**
* @param array $gaufretteConfigs
*
* @return array
*/
private function collectConfiguredGaufretteAdaptersNames(array $gaufretteConfigs): array
{
$adapters = [];
foreach ($gaufretteConfigs as $config) {
if (empty($config['adapters'])) {
continue;
}
$adapters[] = array_keys($config['adapters']);
}

return array_unique(array_merge(...$adapters));
}
}
Loading

0 comments on commit c96a12a

Please sign in to comment.