From 10fe6a9843e1f768542d9acc50cf7176969fa9f7 Mon Sep 17 00:00:00 2001 From: Pieter Maene Date: Sun, 14 Jul 2019 17:22:00 +0200 Subject: [PATCH 1/5] Integrated Flysystem to unify filesystem accesses --- .gitignore | 15 +- composer.json | 2 + composer.lock | 495 +++++++++++++++++- config/autoload/flysystem.global.php | 38 ++ config/autoload/proxy.global.php | 2 +- config/autoload/zenddevelopertools.global.php | 44 +- config/flysystem.config.php.dist | 26 + config/modules.config.php | 1 + data/files/.gitignore | 2 + .../Component/Controller/ActionController.php | 2 + .../ServiceLocatorAware/FlySystemTrait.php | 43 ++ .../Resources/config/module.config.php | 19 +- 12 files changed, 646 insertions(+), 43 deletions(-) create mode 100644 config/autoload/flysystem.global.php create mode 100644 config/flysystem.config.php.dist create mode 100644 data/files/.gitignore create mode 100644 module/CommonBundle/Component/ServiceManager/ServiceLocatorAware/FlySystemTrait.php diff --git a/.gitignore b/.gitignore index 586796f169..d23e6ac9fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,18 @@ # These files should be explicitly created config/database.config.php +config/flysystem.config.php config/proxy.config.php config/redis.config.php config/sentry.config.php config/session.config.php # We don't want data in our repository -data/banner/images -data/br/companies -data/br/files data/cache -data/calendar/posters -data/certificates/private -data/cudi/files +data/files data/hydrators -data/page/files data/proxies -data/form/files public/_assetic -public/_common/profile -public/_gallery/albums -public/_publications/pdf -public/_publications/html -public/_br/img # Exclude dependencies vendor/ diff --git a/composer.json b/composer.json index 3f0fe6cf03..5f342962a6 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "clue/redis-react": "^2.2", "colinmollenhour/credis": "^1.10", "erusev/parsedown": "^1.7", + "league/flysystem-aws-s3-v3": "^1.0", "league/uri-parser": "^1.4", "misterion/ko-process": "^0.5", "mtdowling/cron-expression": "^1.2", @@ -49,6 +50,7 @@ "symfony/console": "^3.4", "symfony/event-dispatcher": "^3.4", "widmogrod/zf2-assetic-module": "^2.4", + "wshafer/psr11-flysystem": "^2.1", "twitter/bootstrap": "^3.3" }, diff --git a/composer.lock b/composer.lock index 6866a83c4f..de47be318c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "171170e13cd9dc274c8d164c0dd3a8c4", + "content-hash": "b2fe634cccc2a8d127162924f13c3f07", "packages": [ { "name": "alcaeus/mongo-php-adapter", @@ -72,6 +72,89 @@ ], "time": "2019-04-06T08:08:09+00:00" }, + { + "name": "aws/aws-sdk-php", + "version": "3.94.0", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "fcc8593b3da8465d1181c73689117d13101a1c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/fcc8593b3da8465d1181c73689117d13101a1c9a", + "reference": "fcc8593b3da8465d1181c73689117d13101a1c9a", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1", + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "^1.4.1", + "mtdowling/jmespath.php": "~2.2", + "php": ">=5.5" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "time": "2019-05-20T18:14:09+00:00" + }, { "name": "cboden/ratchet", "version": "v0.4.1", @@ -1779,6 +1862,122 @@ ], "time": "2017-07-23T21:35:13+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, { "name": "guzzlehttp/psr7", "version": "1.5.2", @@ -1923,6 +2122,184 @@ ], "time": "2016-11-11T18:43:20+00:00" }, + { + "name": "league/flysystem", + "version": "1.0.51", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "755ba7bf3fb9031e6581d091db84d78275874396" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/755ba7bf3fb9031e6581d091db84d78275874396", + "reference": "755ba7bf3fb9031e6581d091db84d78275874396", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7.10" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2019-03-30T13:22:34+00:00" + }, + { + "name": "league/flysystem-aws-s3-v3", + "version": "1.0.22", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", + "reference": "883b02c80ca9cd68cf58a9b4b2185beef24b836b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/883b02c80ca9cd68cf58a9b4b2185beef24b836b", + "reference": "883b02c80ca9cd68cf58a9b4b2185beef24b836b", + "shasum": "" + }, + "require": { + "aws/aws-sdk-php": "^3.0.0", + "league/flysystem": "^1.0.40", + "php": ">=5.5.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "^2.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\AwsS3v3\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Flysystem adapter for the AWS S3 SDK v3.x", + "time": "2019-01-31T15:07:25+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/08ef74e9be88100807a3b92cc9048a312bf01d6f", + "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "time": "2018-07-09T20:51:04+00:00" + }, { "name": "league/uri-parser", "version": "1.4.1", @@ -2159,6 +2536,61 @@ ], "time": "2017-01-23T04:29:33+00:00" }, + { + "name": "mtdowling/jmespath.php", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac", + "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "time": "2016-12-03T22:08:25+00:00" + }, { "name": "ocramius/package-versions", "version": "1.4.0", @@ -4057,6 +4489,67 @@ ], "time": "2018-01-13T15:39:38+00:00" }, + { + "name": "wshafer/psr11-flysystem", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/wshafer/psr11-flysystem.git", + "reference": "8d6fdddc910ddd48124b949eb916fa31b23b283c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wshafer/psr11-flysystem/zipball/8d6fdddc910ddd48124b949eb916fa31b23b283c", + "reference": "8d6fdddc910ddd48124b949eb916fa31b23b283c", + "shasum": "" + }, + "require": { + "league/flysystem": "^1.0.40", + "league/flysystem-cached-adapter": "^1.0", + "php": "^7.0", + "psr/container": "^1.0.0" + }, + "require-dev": { + "league/flysystem-aws-s3-v3": "^1.0", + "league/flysystem-azure": "^1.0", + "league/flysystem-memory": "^1.0", + "league/flysystem-sftp": "^1.0", + "league/flysystem-ziparchive": "^1.0", + "phpmd/phpmd": "@stable", + "phpunit/phpunit": "^6.0.8", + "predis/predis": "^1.1", + "satooshi/php-coveralls": "^1.0", + "spatie/flysystem-dropbox": "^1.0", + "squizlabs/php_codesniffer": "^2.8.1", + "symfony/dependency-injection": "^3.3" + }, + "type": "library", + "extra": { + "zf": { + "config-provider": "WShafer\\PSR11FlySystem\\ConfigProvider", + "module": "WShafer\\PSR11FlySystem" + } + }, + "autoload": { + "psr-4": { + "WShafer\\PSR11FlySystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Westin Shafer", + "email": "shafer_w2002@yahoo.com", + "homepage": "https://github.com/wshafer" + } + ], + "description": "Flysystem Facotories for PSR-11", + "homepage": "https://github.com/wshafer/psr11-flysystem", + "time": "2017-09-14T23:03:04+00:00" + }, { "name": "zendframework/zend-authentication", "version": "2.6.0", diff --git a/config/autoload/flysystem.global.php b/config/autoload/flysystem.global.php new file mode 100644 index 0000000000..8c92ee25d3 --- /dev/null +++ b/config/autoload/flysystem.global.php @@ -0,0 +1,38 @@ + + * @author Karsten Daemen + * @author Koen Certyn + * @author Bram Gotink + * @author Dario Incalza + * @author Pieter Maene + * @author Kristof Mariën + * @author Lars Vierbergen + * @author Daan Wendelen + * @author Mathijs Cuppens + * @author Floris Kint + * + * @license http://litus.cc/LICENSE + */ + +if (!file_exists(__DIR__ . '/../flysystem.config.php')) { + throw new RuntimeException( + 'The FlySystem configuration file (' . (__DIR__ . '/../flysystem.config.php') . ') was not found' + ); +} + +$flysystemConfig = include __DIR__ . '/../flysystem.config.php'; + +return array( + 'flysystem' => array( + 'adaptors' => array( + 'default' => array( + 'type' => $flysystemConfig['type'], + 'options' => $flysystemConfig['options'], + ), + ), + ), +); diff --git a/config/autoload/proxy.global.php b/config/autoload/proxy.global.php index c3b1d789ce..dc76aac201 100644 --- a/config/autoload/proxy.global.php +++ b/config/autoload/proxy.global.php @@ -27,7 +27,7 @@ $proxyConfig = include __DIR__ . '/../proxy.config.php'; if ($proxyConfig['use_proxy'] && !isset($proxyConfig['trusted_proxies'])) { throw new RuntimeException( - 'The RemoteAddr configuration did not specify any trusted proxies' + 'The proxy configuration did not specify any trusted proxies' ); } diff --git a/config/autoload/zenddevelopertools.global.php b/config/autoload/zenddevelopertools.global.php index 53e715b98b..1984171a7a 100644 --- a/config/autoload/zenddevelopertools.global.php +++ b/config/autoload/zenddevelopertools.global.php @@ -18,25 +18,29 @@ * @license http://litus.cc/LICENSE */ -return array( - 'zenddevelopertools' => array( - 'profiler' => array( - 'enabled' => true, - 'strict' => false, - 'flush_early' => false, - 'cache_dir' => 'data/cache', - 'matcher' => array(), - 'collectors' => array( - 'config' => null, - 'db' => null, +if (getenv('APPLICATION_ENV') == 'development') { + return array( + 'zenddevelopertools' => array( + 'profiler' => array( + 'enabled' => true, + 'strict' => false, + 'flush_early' => false, + 'cache_dir' => 'data/cache', + 'matcher' => array(), + 'collectors' => array( + 'config' => null, + 'db' => null, + ), + ), + 'toolbar' => array( + 'enabled' => getenv('APPLICATION_ENV') == 'development', + 'auto_hide' => true, + 'position' => 'bottom', + 'version_check' => true, + 'entries' => array(), ), ), - 'toolbar' => array( - 'enabled' => getenv('APPLICATION_ENV') == 'development', - 'auto_hide' => true, - 'position' => 'bottom', - 'version_check' => true, - 'entries' => array(), - ), - ), -); + ); +} + +return array(); diff --git a/config/flysystem.config.php.dist b/config/flysystem.config.php.dist new file mode 100644 index 0000000000..ae0fb86c1a --- /dev/null +++ b/config/flysystem.config.php.dist @@ -0,0 +1,26 @@ + + * @author Karsten Daemen + * @author Koen Certyn + * @author Bram Gotink + * @author Dario Incalza + * @author Pieter Maene + * @author Kristof Mariën + * @author Lars Vierbergen + * @author Daan Wendelen + * @author Mathijs Cuppens + * @author Floris Kint + * + * @license http://litus.cc/LICENSE + */ + +return array( + 'type' => 'local', + 'options' => array( + 'root' => __DIR__ . '/../data/files', + ), +); diff --git a/config/modules.config.php b/config/modules.config.php index a4ef1b8435..903760e763 100644 --- a/config/modules.config.php +++ b/config/modules.config.php @@ -35,6 +35,7 @@ 'DoctrineModule', 'DoctrineORMModule', 'DoctrineMongoODMModule', + 'WShafer\PSR11FlySystem', 'ZendTwig', 'ApiBundle', diff --git a/data/files/.gitignore b/data/files/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/data/files/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/module/CommonBundle/Component/Controller/ActionController.php b/module/CommonBundle/Component/Controller/ActionController.php index 8df770e6d6..c67c10ea34 100644 --- a/module/CommonBundle/Component/Controller/ActionController.php +++ b/module/CommonBundle/Component/Controller/ActionController.php @@ -27,6 +27,7 @@ use CommonBundle\Component\ServiceManager\ServiceLocatorAware\CacheTrait; use CommonBundle\Component\ServiceManager\ServiceLocatorAware\ConfigTrait; use CommonBundle\Component\ServiceManager\ServiceLocatorAware\DoctrineTrait; +use CommonBundle\Component\ServiceManager\ServiceLocatorAware\FlySystemTrait; use CommonBundle\Component\ServiceManager\ServiceLocatorAware\FormFactoryTrait; use CommonBundle\Component\ServiceManager\ServiceLocatorAware\MailTransportTrait; use CommonBundle\Component\ServiceManager\ServiceLocatorAware\RedisClientTrait; @@ -67,6 +68,7 @@ class ActionController extends \Zend\Mvc\Controller\AbstractActionController imp use CacheTrait; use ConfigTrait; use DoctrineTrait; + use FlySystemTrait; use FormFactoryTrait; use MailTransportTrait; use RedisClientTrait; diff --git a/module/CommonBundle/Component/ServiceManager/ServiceLocatorAware/FlySystemTrait.php b/module/CommonBundle/Component/ServiceManager/ServiceLocatorAware/FlySystemTrait.php new file mode 100644 index 0000000000..48ab89cc1e --- /dev/null +++ b/module/CommonBundle/Component/ServiceManager/ServiceLocatorAware/FlySystemTrait.php @@ -0,0 +1,43 @@ + + * @author Karsten Daemen + * @author Koen Certyn + * @author Bram Gotink + * @author Dario Incalza + * @author Pieter Maene + * @author Kristof Mariën + * @author Lars Vierbergen + * @author Daan Wendelen + * @author Mathijs Cuppens + * @author Floris Kint + * + * @license http://litus.cc/LICENSE + */ + +namespace CommonBundle\Component\ServiceManager\ServiceLocatorAware; + +/** + * A trait to define some common methods for classes with a ServiceLocator. + * + * @author Pieter Maene + */ + +trait FlySystemTrait +{ + /** + * @return \League\Flysystem\Filesystem + */ + public function getFilesystem() + { + return $this->getServiceLocator()->get('filesystem'); + } + + /** + * @return \Zend\ServiceManager\ServiceLocatorInterface + */ + abstract public function getServiceLocator(); +} diff --git a/module/CommonBundle/Resources/config/module.config.php b/module/CommonBundle/Resources/config/module.config.php index 51718bb672..46c1a2e300 100644 --- a/module/CommonBundle/Resources/config/module.config.php +++ b/module/CommonBundle/Resources/config/module.config.php @@ -48,8 +48,10 @@ use CommonBundle\Component\Validator\ServiceManager\AbstractValidatorFactory; use CommonBundle\Component\View\Helper\ServiceManager\AbstractHelperFactory; use Doctrine\Common\Cache\RedisCache as DoctrineRedisCache; +use League\Flysystem\Filesystem; use Raven_Client; use Symfony\Component\Console\Application as ConsoleApplication; +use WShafer\PSR11FlySystem\FlySystemFactory; use Zend\Cache\Storage\StorageInterface as CacheStorage; use Zend\Form\ElementFactory; use Zend\I18n\Translator\Resources as TranslatorResources; @@ -80,33 +82,34 @@ DoctrineCredentialAdapter::class => DoctrineCredentialAdapterFactory::class, DoctrineRedisCache::class => DoctrineRedisCacheFactory::class, DoctrineService::class => DoctrineServiceFactory::class, + Filesystem::class => FlySystemFactory::class, FormFactory::class => FormFactoryFactory::class, HydratorPluginManager::class => HydratorPluginManagerFactory::class, + ManagerInterface::class => SessionManagerFactory::class, Raven_Client::class => RavenClientFactory::class, RedisClient::class => RedisClientFactory::class, Sendmail::class => InvokableFactory::class, SentryClient::class => SentryClientFactory::class, SessionContainer::class => SessionContainerFactory::class, - ManagerInterface::class => SessionManagerFactory::class, ), 'abstract_factories' => array( AbstractInstallerFactory::class, ), 'aliases' => array( - 'authentication' => Authentication::class, 'authentication_credential_adapter' => DoctrineCredentialAdapter::class, 'authentication_service' => DoctrineService::class, + 'authentication' => Authentication::class, 'cache' => CacheStorage::class, 'console' => ConsoleApplication::class, - 'redis_client' => RedisClient::class, + 'doctrine.cache.redis' => DoctrineRedisCache::class, + 'filesystem' => Filesystem::class, 'hydrator_plugin_manager' => HydratorPluginManager::class, 'mail_transport' => Sendmail::class, 'raven_client' => Raven_Client::class, + 'redis_client' => RedisClient::class, 'sentry_client' => SentryClient::class, 'session_container' => SessionContainer::class, 'translator' => MvcTranslator::class, - - 'doctrine.cache.redis' => DoctrineRedisCache::class, ), ), @@ -118,12 +121,12 @@ Component\Controller\Plugin\Url::class => InvokableFactory::class, ), 'aliases' => array( - 'hasaccess' => Component\Controller\Plugin\HasAccess::class, - 'hasAccess' => Component\Controller\Plugin\HasAccess::class, - 'HasAccess' => Component\Controller\Plugin\HasAccess::class, 'flashmessenger' => Component\Controller\Plugin\FlashMessenger::class, 'flashMessenger' => Component\Controller\Plugin\FlashMessenger::class, 'FlashMessenger' => Component\Controller\Plugin\FlashMessenger::class, + 'hasaccess' => Component\Controller\Plugin\HasAccess::class, + 'hasAccess' => Component\Controller\Plugin\HasAccess::class, + 'HasAccess' => Component\Controller\Plugin\HasAccess::class, 'paginator' => Component\Controller\Plugin\Paginator::class, 'Paginator' => Component\Controller\Plugin\Paginator::class, 'url' => Component\Controller\Plugin\Url::class, From 7b400d36a70e7e94a360069991c592f631f7656c Mon Sep 17 00:00:00 2001 From: Pieter Maene Date: Sun, 14 Jul 2019 17:26:37 +0200 Subject: [PATCH 2/5] Added storage configuration file specifying filesystem directories --- .../Component/Controller/ActionController.php | 24 ++ .../CommonBundle/Component/Module/Config.php | 221 ++++++++---------- 2 files changed, 126 insertions(+), 119 deletions(-) diff --git a/module/CommonBundle/Component/Controller/ActionController.php b/module/CommonBundle/Component/Controller/ActionController.php index c67c10ea34..289b2c711f 100644 --- a/module/CommonBundle/Component/Controller/ActionController.php +++ b/module/CommonBundle/Component/Controller/ActionController.php @@ -526,4 +526,28 @@ protected function getEntityById($entityName, $paramKey = 'id', $entityKey = 'id return $entity; } + + /** + * @param string $directory + * @param string|array|null $resource + * @return string|null + */ + protected function getStoragePath($directory, $resource = null) + { + $config = $this->getConfig(); + if (!isset($config['litus']['storage']['directories'][$directory])) { + return null; + } + + $path = $config['litus']['storage']['directories'][$directory]; + if ($resource !== null) { + if (is_array($resource)) { + $resource = implode('/', $resource); + } + + $path .= '/' . $resource; + } + + return $path; + } } diff --git a/module/CommonBundle/Component/Module/Config.php b/module/CommonBundle/Component/Module/Config.php index be6b7e9090..609f840593 100644 --- a/module/CommonBundle/Component/Module/Config.php +++ b/module/CommonBundle/Component/Module/Config.php @@ -95,11 +95,11 @@ * $settings = array( * 'namespace' => , // required, the namespace of the bundle to configure * 'directory' => , // required, the directory of the module.config.php file - * 'has_entities' => true , // optional, whether or not the bundle has entities - * 'has_documents' => false , // optional, whether or not the bundle has documents * 'translation_files' => array() , // optional, files in ../translations for i18n - * 'has_views' => true , // optional, whether the bundle has Twig views + * + * 'has_entities' => true , // optional, whether or not the bundle has entities * 'has_layouts' => false , // optional, whether the bundle has Twig layouts + * 'has_views' => true , // optional, whether the bundle has Twig views * ); * $override = array( * // elements in this array are merged into the result of the method before it is returned @@ -113,104 +113,39 @@ class Config { /** - * Loads the file in the directory if it exists, returns empty array otherwise. - * - * @param string $directory the directory containing the file - * @param string $file the file to load - * @return mixed + * @return array */ - private static function load($directory, $file) - { - $file = $directory . '/' . $file; - if (file_exists($file)) { - return include $file; - } else { - return array(); - } - } - - private static function createTranslationConfig(array $settings) - { - if (!array_key_exists('translation_files', $settings)) { - return array(); - } - - $translationFiles = array(); - $directory = $settings['directory']; - foreach ($settings['translation_files'] as $translationFile) { - $translationFiles[] = array( - 'type' => 'phparray', - 'base_dir' => $directory . '/../translations', - 'pattern' => $translationFile . '.%s.php', - ); - } - - return $translationFiles; - } - - private static function createDoctrineConfig(array $settings) + public static function create(array $settings, array $override = array()) { - $doctrine = array(); $directory = $settings['directory']; - $namespace = $settings['namespace']; + $routerConfig = self::load($directory, 'router.config.php'); - // include entities by default - if (!array_key_exists('has_entities', $settings) || $settings['has_entities']) { - $doctrine['orm_default'] = array( - 'drivers' => array( - $namespace . '\Entity' => 'orm_annotation_driver', - ), - ); - $doctrine['orm_annotation_driver'] = array( - 'paths' => array( - $namespace => $directory . '/../../Entity', + return array_merge_recursive( + array( + 'router' => array( + 'routes' => array_key_exists('routes', $routerConfig) ? $routerConfig['routes'] : array(), ), - ); - } - - // don't include documents by default - if (array_key_exists('has_documents', $settings) && $settings['has_documents']) { - $doctrine['odm_default'] = array( - 'drivers' => array( - $namespace . '\Document' => 'odm_annotation_driver', + 'controllers' => array( + 'invokables' => array_key_exists('controllers', $routerConfig) ? $routerConfig['controllers'] : array(), ), - ); - $doctrine['odm_annotation_driver'] = array( - 'paths' => array( - $namespace => $directory . '/../../Document', + 'translator' => array( + 'translation_file_patterns' => self::createTranslationConfig($settings), ), - ); - } - - return $doctrine; - } - - private static function createViewManagerConfig(array $settings) - { - // include view by default - $hasView = !array_key_exists('has_views', $settings) || $settings['has_views']; - - // don't include layout by default - $hasLayout = array_key_exists('has_layouts', $settings) && $settings['has_layouts']; - - if (!$hasView && !$hasLayout) { - return array(); - } - - $directory = $settings['directory']; - $namespace = $settings['namespace']; - $bundleName = str_replace('bundle', '', strtolower($namespace)); + 'view_manager' => self::createViewManagerConfig($settings), - $templatePathStack = array(); - if ($hasLayout) { - $templatePathStack[$bundleName . '_layout'] = $directory . '/../layouts'; - } - if ($hasView) { - $templatePathStack[$bundleName . '_view'] = $directory . '/../views'; - } + 'assetic_configuration' => self::createAsseticConfig($settings), + 'doctrine' => array( + 'driver' => self::createDoctrineConfig($settings), + ), - return array( - 'template_path_stack' => $templatePathStack, + 'litus' => array( + 'admin' => self::load($directory, 'admin.config.php'), + 'console' => self::load($directory, 'console.config.php'), + 'install' => self::createInstallConfig($settings), + 'storage' => self::load($directory, 'storage.config.php'), + ), + ), + $override ); } @@ -266,43 +201,91 @@ private static function createInstallConfig(array $settings) ); } - /** - * - * @return array - */ - public static function create(array $settings, array $override = array()) + private static function createDoctrineConfig(array $settings) { + $doctrine = array(); $directory = $settings['directory']; - $routerConfig = self::load($directory, 'router.config.php'); + $namespace = $settings['namespace']; - return array_merge_recursive( - array( - 'router' => array( - 'routes' => array_key_exists('routes', $routerConfig) ? $routerConfig['routes'] : array(), + // include entities by default + if (!array_key_exists('has_entities', $settings) || $settings['has_entities']) { + $doctrine['orm_default'] = array( + 'drivers' => array( + $namespace . '\Entity' => 'orm_annotation_driver', ), - 'controllers' => array( - 'invokables' => array_key_exists('controllers', $routerConfig) ? $routerConfig['controllers'] : array(), + ); + $doctrine['orm_annotation_driver'] = array( + 'paths' => array( + $namespace => $directory . '/../../Entity', ), + ); + } - 'translator' => array( - 'translation_file_patterns' => self::createTranslationConfig($settings), - ), + return $doctrine; + } - 'doctrine' => array( - 'driver' => self::createDoctrineConfig($settings), - ), + private static function createTranslationConfig(array $settings) + { + if (!array_key_exists('translation_files', $settings)) { + return array(); + } - 'assetic_configuration' => self::createAsseticConfig($settings), + $translationFiles = array(); + $directory = $settings['directory']; + foreach ($settings['translation_files'] as $translationFile) { + $translationFiles[] = array( + 'type' => 'phparray', + 'base_dir' => $directory . '/../translations', + 'pattern' => $translationFile . '.%s.php', + ); + } - 'view_manager' => self::createViewManagerConfig($settings), + return $translationFiles; + } - 'litus' => array( - 'admin' => self::load($directory, 'admin.config.php'), - 'install' => self::createInstallConfig($settings), - 'console' => self::load($directory, 'console.config.php'), - ), - ), - $override + private static function createViewManagerConfig(array $settings) + { + // include view by default + $hasView = !array_key_exists('has_views', $settings) || $settings['has_views']; + + // don't include layout by default + $hasLayout = array_key_exists('has_layouts', $settings) && $settings['has_layouts']; + + if (!$hasView && !$hasLayout) { + return array(); + } + + $directory = $settings['directory']; + $namespace = $settings['namespace']; + $bundleName = str_replace('bundle', '', strtolower($namespace)); + + $templatePathStack = array(); + if ($hasLayout) { + $templatePathStack[$bundleName . '_layout'] = $directory . '/../layouts'; + } + if ($hasView) { + $templatePathStack[$bundleName . '_view'] = $directory . '/../views'; + } + + return array( + 'template_path_stack' => $templatePathStack, ); } + + /** + * Loads the file in the directory if it exists, returns empty array otherwise. + * + * @param string $directory the directory containing the file + * @param string $file the file to load + * @return mixed + */ + private static function load($directory, $file) + { + $file = $directory . '/' . $file; + if (file_exists($file)) { + return include $file; + } else { + return array(); + } + } } From 4264d3eb676bca298cbd1dd9b1c09d236f1a1c2a Mon Sep 17 00:00:00 2001 From: Pieter Maene Date: Sun, 14 Jul 2019 17:27:45 +0200 Subject: [PATCH 3/5] Refactored BannerBundle filesystem interactions --- data/banner/images/.gitignore | 2 - migrations/Version20190714140819.php | 55 +++++++++++++++ .../Controller/Admin/BannerController.php | 68 +++++++++++-------- .../Controller/BannerController.php | 21 +++--- module/BannerBundle/Entity/Node/Banner.php | 4 +- .../Resources/config/storage.config.php | 25 +++++++ .../views/banner/admin/banner/add.twig | 2 +- 7 files changed, 133 insertions(+), 44 deletions(-) delete mode 100644 data/banner/images/.gitignore create mode 100644 migrations/Version20190714140819.php create mode 100644 module/BannerBundle/Resources/config/storage.config.php diff --git a/data/banner/images/.gitignore b/data/banner/images/.gitignore deleted file mode 100644 index d6b7ef32c8..0000000000 --- a/data/banner/images/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/migrations/Version20190714140819.php b/migrations/Version20190714140819.php new file mode 100644 index 0000000000..46bb7f3892 --- /dev/null +++ b/migrations/Version20190714140819.php @@ -0,0 +1,55 @@ + + * @author Karsten Daemen + * @author Koen Certyn + * @author Bram Gotink + * @author Dario Incalza + * @author Pieter Maene + * @author Kristof Mariën + * @author Lars Vierbergen + * @author Daan Wendelen + * @author Mathijs Cuppens + * @author Floris Kint + * + * @license http://litus.cc/LICENSE + */ + +namespace Migrations; + +use Doctrine\DBAL\Schema\Schema; + +/** + * Version 20190714140819 + */ +class Version20190714140819 extends \Doctrine\Migrations\AbstractMigration +{ + /** + * @param \Doctrine\DBAL\Schema\Schema $schema + * @return void + */ + public function up(Schema $schema) : void + { + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() !== 'postgresql', + 'Migration can only be executed safely on PostgreSQL.' + ); + + $this->addSql('ALTER TABLE nodes_banners ALTER image TYPE VARCHAR(255)'); + $this->addSql('ALTER TABLE nodes_banners ALTER image DROP DEFAULT'); + } + + /** + * @param \Doctrine\DBAL\Schema\Schema $schema + * @return void + */ + public function down(Schema $schema) : void + { + $this->throwIrreversibleMigrationException(); + } +} diff --git a/module/BannerBundle/Controller/Admin/BannerController.php b/module/BannerBundle/Controller/Admin/BannerController.php index 3171e33626..dc5a507420 100644 --- a/module/BannerBundle/Controller/Admin/BannerController.php +++ b/module/BannerBundle/Controller/Admin/BannerController.php @@ -95,28 +95,28 @@ public function editAction() private function receive($file, Banner $banner) { - $filePath = $this->getEntityManager() - ->getRepository('CommonBundle\Entity\General\Config') - ->getConfigValue('banner.image_path'); - do { - $fileName = '/' . sha1(uniqid()); - } while (file_exists($filePath . $fileName)); - - rename($file['tmp_name'], $filePath . $fileName); + $image = sha1(uniqid()); + $path = $this->getStoragePath('banner_banners_images', $image); + } while ($this->getFilesystem()->has($path)); + + $stream = fopen($file['tmp_name'], 'r+'); + $this->getFilesystem()->writeStream($path, $stream); + if (is_resource($stream)) { + fclose($stream); + } - $banner->setImage($fileName); + $banner->setImage($image); } public function uploadAction() { $this->initAjax(); - $isNew = !($banner = $this->getBannerEntity(false)); + $form = $this->getForm('banner_banner_add'); - if ($isNew) { - $form = $this->getForm('banner_banner_add'); - } else { + $banner = $this->getEntityById('BannerBundle\Entity\Node\Banner'); + if ($banner !== null) { $form = $this->getForm('banner_banner_edit', $banner); } @@ -131,7 +131,7 @@ public function uploadAction() if ($form->isValid()) { $formData = $form->getData(); - if ($isNew) { + if ($banner === null) { $banner = $form->hydrateObject(); $this->receive($formData['file'], $banner); @@ -154,8 +154,17 @@ public function uploadAction() ), ) ); - } elseif (!$isNew) { + } else { if (isset($formData['file'])) { + $path = $this->getStoragePath( + 'banner_banners_images', + $banner->getImage() + ); + + if ($this->getFilesystem()->has($path)) { + $this->getFilesystem()->delete($path); + } + $this->receive($formData['file'], $banner); } @@ -208,6 +217,10 @@ public function deleteAction() return new ViewModel(); } + $this->getFilesystem()->delete( + Banner::getImagePath($banner->getImage()) + ); + $this->getEntityManager()->remove($banner); $this->getEntityManager()->flush(); @@ -221,27 +234,24 @@ public function deleteAction() } /** - * @param boolean $redirect * @return Banner|null */ - private function getBannerEntity($redirect = true) + private function getBannerEntity() { $banner = $this->getEntityById('BannerBundle\Entity\Node\Banner'); if (!($banner instanceof Banner)) { - if ($redirect) { - $this->flashMessenger()->error( - 'Error', - 'No baner was found!' - ); + $this->flashMessenger()->error( + 'Error', + 'No banner was found!' + ); - $this->redirect()->toRoute( - 'banner_admin_banner', - array( - 'action' => 'manage', - ) - ); - } + $this->redirect()->toRoute( + 'banner_admin_banner', + array( + 'action' => 'manage', + ) + ); return; } diff --git a/module/BannerBundle/Controller/BannerController.php b/module/BannerBundle/Controller/BannerController.php index 3b7e7e85ae..db699c3dae 100644 --- a/module/BannerBundle/Controller/BannerController.php +++ b/module/BannerBundle/Controller/BannerController.php @@ -34,27 +34,28 @@ class BannerController extends \CommonBundle\Component\Controller\ActionControll { public function viewAction() { - $imagePath = $this->getEntityManager() - ->getRepository('CommonBundle\Entity\General\Config') - ->getConfigValue('banner.image_path') . '/' . $this->getParam('image'); + $path = $this->getStoragePath( + 'banner_banners_images', + $this->getParam('image') + ); + + if (!$this->getFilesystem()->has($path)) { + return $this->notFoundAction(); + } $headers = new Headers(); $headers->addHeaders( array( 'Content-Disposition' => 'inline; filename="' . $this->getParam('image') . '"', - 'Content-Type' => mime_content_type($imagePath), - 'Content-Length' => filesize($imagePath), + 'Content-Type' => $this->getFilesystem()->getMimetype($path), + 'Content-Length' => $this->getFilesystem()->getSize($path), ) ); $this->getResponse()->setHeaders($headers); - $handle = fopen($imagePath, 'r'); - $data = fread($handle, filesize($imagePath)); - fclose($handle); - return new ViewModel( array( - 'data' => $data, + 'data' => $this->getFilesystem()->read($path), ) ); } diff --git a/module/BannerBundle/Entity/Node/Banner.php b/module/BannerBundle/Entity/Node/Banner.php index 003c2be60d..34168371cf 100644 --- a/module/BannerBundle/Entity/Node/Banner.php +++ b/module/BannerBundle/Entity/Node/Banner.php @@ -53,9 +53,9 @@ class Banner extends \CommonBundle\Entity\Node private $endDate; /** - * @var string The location of the image + * @var string The name of the image * - * @ORM\Column(type="text") + * @ORM\Column(type="string") */ private $image; diff --git a/module/BannerBundle/Resources/config/storage.config.php b/module/BannerBundle/Resources/config/storage.config.php new file mode 100644 index 0000000000..8655d8ceb0 --- /dev/null +++ b/module/BannerBundle/Resources/config/storage.config.php @@ -0,0 +1,25 @@ + + * @author Karsten Daemen + * @author Koen Certyn + * @author Bram Gotink + * @author Dario Incalza + * @author Pieter Maene + * @author Kristof Mariën + * @author Lars Vierbergen + * @author Daan Wendelen + * @author Mathijs Cuppens + * @author Floris Kint + * + * @license http://litus.cc/LICENSE + */ + +return array( + 'directories' => array( + 'banner_banners_images' => 'banner/banners_images', + ), +); diff --git a/module/BannerBundle/Resources/views/banner/admin/banner/add.twig b/module/BannerBundle/Resources/views/banner/admin/banner/add.twig index 6737980b7a..9146211300 100644 --- a/module/BannerBundle/Resources/views/banner/admin/banner/add.twig +++ b/module/BannerBundle/Resources/views/banner/admin/banner/add.twig @@ -25,7 +25,7 @@