From 149bb0cc3573c7e6cb462da74ad9ef2ca699055b Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 12:33:45 +0200 Subject: [PATCH 01/15] Require gaufrette bundle --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 758d49c6..3acccd3e 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": "~7.0", + "knplabs/knp-gaufrette-bundle": "^0.7.1", "symfony/config": "~3.4|~4.2|~5.0", "symfony/dependency-injection": "~3.4|~4.2|~5.0", "symfony/event-dispatcher": "~3.4|~4.2|~5.0", From 0676f32e991743392f95309d302461f4d09b75cd Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 13:13:56 +0200 Subject: [PATCH 02/15] Add some vars to store gaufrette config --- Form/FormFlow.php | 29 +++++++++++++++++++++++++++++ Form/FormFlowInterface.php | 10 ++++++++++ 2 files changed, 39 insertions(+) diff --git a/Form/FormFlow.php b/Form/FormFlow.php index 3927c39e..9849fc26 100644 --- a/Form/FormFlow.php +++ b/Form/FormFlow.php @@ -70,6 +70,16 @@ abstract class FormFlow implements FormFlowInterface { */ protected $handleFileUploads = true; + /** + * @var bool If file uploads should be handled with Gaufrette + */ + protected $handleFileUploadsWithGaufrette = false; + + /** + * @var string Filesystem that Gaufrette will use + */ + protected $gaufretteFilesystem = null; + /** * @var string|null Directory for storing temporary files while handling uploads. If null, the system's default will be used. */ @@ -384,6 +394,25 @@ public function getHandleFileUploadsTempDir() { return $this->handleFileUploadsTempDir; } + /** + * {@inheritDoc} + */ + public function isHandleFileUploadsWithGaufrette() { + return $this->handleFileUploadsWithGaufrette; + } + + public function setGaufretteFilesystem($gaufretteFilesystem) { + $this->gaufretteFilesystem = $gaufretteFilesystem !== null ? (string) $gaufretteFilesystem : null; + + } + + /** + * {@inheritDoc} + */ + public function getGaufretteFilesystem() { + return $this->gaufretteFilesystem; + } + public function setAllowRedirectAfterSubmit($allowRedirectAfterSubmit) { $this->allowRedirectAfterSubmit = (bool) $allowRedirectAfterSubmit; } diff --git a/Form/FormFlowInterface.php b/Form/FormFlowInterface.php index 57f4121c..6ba4e51e 100644 --- a/Form/FormFlowInterface.php +++ b/Form/FormFlowInterface.php @@ -66,6 +66,16 @@ function isHandleFileUploads(); */ function getHandleFileUploadsTempDir(); + /** + * @var bool If file uploads should be handled with Gaufrette + */ + function isHandleFileUploadsWithGaufrette(); + + /** + * @return string|null Filesystem that Gaufrette will use + */ + function getGaufretteFilesystem(); + /** * @return bool */ From 50c9e1b749fb11a74f71c34f3b4f0119557be322 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 13:43:15 +0200 Subject: [PATCH 03/15] Support gaufrette on save function --- Storage/DataManager.php | 31 ++++++++++----- Storage/GaufretteFile.php | 56 +++++++++++++++++++++++++++ Storage/GaufretteStorage.php | 73 ++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 Storage/GaufretteFile.php create mode 100644 Storage/GaufretteStorage.php diff --git a/Storage/DataManager.php b/Storage/DataManager.php index 893820b0..ce84b16a 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -34,11 +34,18 @@ class DataManager implements ExtendedDataManagerInterface { */ private $storage; - /** - * @param StorageInterface $storage - */ - public function __construct(StorageInterface $storage) { + /** + * @var GaufretteStorage + */ + private $gaufretteStorage; + + /** + * @param StorageInterface $storage + * @param GaufretteStorage $gaufretteStorage + */ + public function __construct(StorageInterface $storage, GaufretteStorage $gaufretteStorage) { $this->storage = $storage; + $this->gaufretteStorage = $gaufretteStorage; } /** @@ -54,11 +61,17 @@ public function getStorage() { public function save(FormFlowInterface $flow, array $data) { // handle file uploads if ($flow->isHandleFileUploads()) { - array_walk_recursive($data, function(&$value, $key) { - if (SerializableFile::isSupported($value)) { - $value = new SerializableFile($value); - } - }); + array_walk_recursive($data, function(&$value, $key) use ($flow) { + if(!$flow->isHandleFileUploadsWithGaufrette()){ + if (SerializableFile::isSupported($value)) { + $value = new SerializableFile($value); + } + }else{ + if (GaufretteFile::isSupported($value)) { + $value = new GaufretteFile($this->gaufretteStorage, $flow->getGaufretteFilesystem(), $value); + } + } + }); } // drop old data diff --git a/Storage/GaufretteFile.php b/Storage/GaufretteFile.php new file mode 100644 index 00000000..cf3a4ffb --- /dev/null +++ b/Storage/GaufretteFile.php @@ -0,0 +1,56 @@ +UploadedFile currently. + * + * @author Kevin Cerro + * @copyright 2020 Kevin Cerro + * @license http://opensource.org/licenses/mit-license.php MIT License + */ +class GaufretteFile +{ + + private $gaufretteStorage; + + /** + * @var string Name of the file provided by Gaufrette on upload + */ + private $fileName; + + private $clientOriginalName; + private $clientMimeType; + + /** + * @param GaufretteStorage $gaufretteStorage + * @param string $filesystem + * @param mixed $file An object meant to be serialized. + */ + public function __construct(GaufretteStorage $gaufretteStorage, string $filesystem, $file) + { + if (!self::isSupported($file)) { + throw new InvalidTypeException($file, UploadedFile::class); + } + + //Upload file with Gaufrette + $this->gaufretteStorage = $gaufretteStorage; + $this->fileName = $this->gaufretteStorage->doUpload($filesystem, $file); + + //Keep client original name and mime type + $this->clientOriginalName = $file->getClientOriginalName(); + $this->clientMimeType = $file->getClientMimeType(); + } + + /** + * @param mixed $file + * @return bool + */ + public static function isSupported($file) + { + return $file instanceof UploadedFile; + } +} diff --git a/Storage/GaufretteStorage.php b/Storage/GaufretteStorage.php new file mode 100644 index 00000000..30fc118b --- /dev/null +++ b/Storage/GaufretteStorage.php @@ -0,0 +1,73 @@ +filesystemMap = $filesystemMap; + } + + public function doUpload(string $filesystem, UploadedFile $file) + { + $filesystem = $this->getFilesystem($filesystem); + $randomName = $this->generateRandomName($file->getExtension()); + + if ($filesystem->getAdapter() instanceof MetadataSupporter) { + $filesystem->getAdapter()->setMetadata($randomName, ['contentType' => $file->getMimeType()]); + } + + $filesystem->write($randomName, file_get_contents($file->getPathname()), true); + return $randomName; + } + + public function doRemove(string $filesystem, string $name) + { + $filesystem = $this->getFilesystem($filesystem); + + try { + return $filesystem->delete($name); + } catch (FileNotFound $e) { + return false; + } + } + + + /** + * Get filesystem adapter from the property mapping. + * @param string $filesystem + * @return FilesystemInterface + */ + private function getFilesystem(string $filesystem): FilesystemInterface + { + return $this->filesystemMap->get($filesystem); + } + + /** + * Generates random name + * @param string $extension + * @return string|string[] + */ + private function generateRandomName(string $extension) + { + $name = str_replace('.', '', \uniqid('', true)); + return sprintf('%s.%s', $name, $extension); + } +} \ No newline at end of file From a9cf5658405a7edb1557028967158b40f1dbd977 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 13:53:17 +0200 Subject: [PATCH 04/15] Add required services --- Resources/config/form_flow.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Resources/config/form_flow.xml b/Resources/config/form_flow.xml index 38308211..75fcdd08 100644 --- a/Resources/config/form_flow.xml +++ b/Resources/config/form_flow.xml @@ -12,6 +12,7 @@ Craue\FormFlowBundle\Form\FormFlow Craue\FormFlowBundle\Storage\SessionStorage + Craue\FormFlowBundle\Storage\GaufretteStorage Craue\FormFlowBundle\EventListener\PreviousStepInvalidEventListener Craue\FormFlowBundle\Form\FormFlowEvents::PREVIOUS_STEP_INVALID Craue\FormFlowBundle\EventListener\FlowExpiredEventListener @@ -25,8 +26,15 @@ + + + + + + + From 9802e44c09e80c06965130cca605e1e36aa1d299 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 14:04:44 +0200 Subject: [PATCH 05/15] Store only minimal data on GaufretteFile. This is due some Gaufrette adapters like AWS S3 adapter cannot be serialized. --- Storage/DataManager.php | 3 ++- Storage/GaufretteFile.php | 23 +++++++++-------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index ce84b16a..6d6e0a43 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -68,7 +68,8 @@ public function save(FormFlowInterface $flow, array $data) { } }else{ if (GaufretteFile::isSupported($value)) { - $value = new GaufretteFile($this->gaufretteStorage, $flow->getGaufretteFilesystem(), $value); + $fileName = $this->gaufretteStorage->doUpload($flow->getGaufretteFilesystem(), $value); + $value = new GaufretteFile($fileName, $value); } } }); diff --git a/Storage/GaufretteFile.php b/Storage/GaufretteFile.php index cf3a4ffb..b0341a11 100644 --- a/Storage/GaufretteFile.php +++ b/Storage/GaufretteFile.php @@ -14,9 +14,6 @@ */ class GaufretteFile { - - private $gaufretteStorage; - /** * @var string Name of the file provided by Gaufrette on upload */ @@ -26,23 +23,21 @@ class GaufretteFile private $clientMimeType; /** - * @param GaufretteStorage $gaufretteStorage - * @param string $filesystem - * @param mixed $file An object meant to be serialized. + * @param string $filename + * @param $originalFile */ - public function __construct(GaufretteStorage $gaufretteStorage, string $filesystem, $file) + public function __construct(string $filename, $originalFile) { - if (!self::isSupported($file)) { - throw new InvalidTypeException($file, UploadedFile::class); + if (!self::isSupported($originalFile)) { + throw new InvalidTypeException($originalFile, UploadedFile::class); } - //Upload file with Gaufrette - $this->gaufretteStorage = $gaufretteStorage; - $this->fileName = $this->gaufretteStorage->doUpload($filesystem, $file); + //Filename of uploaded file with Gaufrette + $this->fileName = $filename; //Keep client original name and mime type - $this->clientOriginalName = $file->getClientOriginalName(); - $this->clientMimeType = $file->getClientMimeType(); + $this->clientOriginalName = $originalFile->getClientOriginalName(); + $this->clientMimeType = $originalFile->getClientMimeType(); } /** From 01a9423cae451ee5274a73c097e2121dcb0a495f Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 14:25:55 +0200 Subject: [PATCH 06/15] Retrieve and delete files from Gaufrette Don't use file extension on gaufrette tmp file --- Storage/DataManager.php | 17 +++++++++++++---- Storage/GaufretteFile.php | 28 ++++++++++++++++++++++++++++ Storage/GaufretteStorage.php | 19 ++++++++++++------- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index 6d6e0a43..760bf374 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -107,10 +107,19 @@ public function load(FormFlowInterface $flow) { // handle file uploads if ($flow->isHandleFileUploads()) { $tempDir = $flow->getHandleFileUploadsTempDir(); - array_walk_recursive($data, function(&$value, $key) use ($tempDir) { - if ($value instanceof SerializableFile) { - $value = $value->getAsFile($tempDir); - } + array_walk_recursive($data, function(&$value, $key) use ($flow, $tempDir) { + if(!$flow->isHandleFileUploadsWithGaufrette()){ + if ($value instanceof SerializableFile) { + $value = $value->getAsFile($tempDir); + } + }else{ + if ($value instanceof GaufretteFile) { + $downloadedFile = $this->gaufretteStorage->doDownload($flow->getGaufretteFilesystem(), $value); + $value = $value->getAsUploadedFile($downloadedFile); + $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $value); + } + } + }); } diff --git a/Storage/GaufretteFile.php b/Storage/GaufretteFile.php index b0341a11..7d510b6e 100644 --- a/Storage/GaufretteFile.php +++ b/Storage/GaufretteFile.php @@ -3,6 +3,8 @@ namespace Craue\FormFlowBundle\Storage; use Craue\FormFlowBundle\Exception\InvalidTypeException; +use Craue\FormFlowBundle\Util\TempFileUtil; +use Gaufrette\File; use Symfony\Component\HttpFoundation\File\UploadedFile; /** @@ -40,6 +42,32 @@ public function __construct(string $filename, $originalFile) $this->clientMimeType = $originalFile->getClientMimeType(); } + /** + * @param File $file + * @return mixed The file retrieved from Gaufrette converted to UploadedFile + */ + public function getAsUploadedFile(File $file) { + $tempDir = sys_get_temp_dir(); + + // create a temporary file with its original content + $tempFile = tempnam($tempDir, 'craue_form_flow_serialized_file'); + file_put_contents($tempFile, $file->getContent()); + + TempFileUtil::addTempFile($tempFile); + + // avoid a deprecation notice regarding "passing a size as 4th argument to the constructor" + // TODO remove as soon as Symfony >= 4.1 is required + if (property_exists(UploadedFile::class, 'size')) { + return new UploadedFile($tempFile, $this->clientOriginalName, $this->clientMimeType, null, null, true); + } + + return new UploadedFile($tempFile, $this->clientOriginalName, $this->clientMimeType, null, true); + } + + public function getFileName() { + return $this->fileName; + } + /** * @param mixed $file * @return bool diff --git a/Storage/GaufretteStorage.php b/Storage/GaufretteStorage.php index 30fc118b..3eaf26cb 100644 --- a/Storage/GaufretteStorage.php +++ b/Storage/GaufretteStorage.php @@ -28,7 +28,7 @@ public function __construct(FilesystemMapInterface $filesystemMap) public function doUpload(string $filesystem, UploadedFile $file) { $filesystem = $this->getFilesystem($filesystem); - $randomName = $this->generateRandomName($file->getExtension()); + $randomName = $this->generateRandomName(); if ($filesystem->getAdapter() instanceof MetadataSupporter) { $filesystem->getAdapter()->setMetadata($randomName, ['contentType' => $file->getMimeType()]); @@ -38,12 +38,18 @@ public function doUpload(string $filesystem, UploadedFile $file) return $randomName; } - public function doRemove(string $filesystem, string $name) + public function doDownload(string $filesystem, GaufretteFile $gaufretteFile) + { + $filesystem = $this->getFilesystem($filesystem); + return $filesystem->get($gaufretteFile->getFileName()); + } + + public function doRemove(string $filesystem, GaufretteFile $gaufretteFile) { $filesystem = $this->getFilesystem($filesystem); try { - return $filesystem->delete($name); + return $filesystem->delete($gaufretteFile->getFileName()); } catch (FileNotFound $e) { return false; } @@ -62,12 +68,11 @@ private function getFilesystem(string $filesystem): FilesystemInterface /** * Generates random name - * @param string $extension + * @todo May we can improve this by setting the extension on the random name * @return string|string[] */ - private function generateRandomName(string $extension) + private function generateRandomName() { - $name = str_replace('.', '', \uniqid('', true)); - return sprintf('%s.%s', $name, $extension); + return str_replace('.', '', \uniqid('', true)); } } \ No newline at end of file From 311325a9845d59458bd094a03182ffd43fd8042c Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 14:35:09 +0200 Subject: [PATCH 07/15] Pass correct file as we are overriding value and doRemove expects a GaufretteFile --- Storage/DataManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index 760bf374..a32f38ed 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -115,8 +115,8 @@ public function load(FormFlowInterface $flow) { }else{ if ($value instanceof GaufretteFile) { $downloadedFile = $this->gaufretteStorage->doDownload($flow->getGaufretteFilesystem(), $value); - $value = $value->getAsUploadedFile($downloadedFile); $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $value); + $value = $value->getAsUploadedFile($downloadedFile); } } From 5b2741baaf6270f8358058e3a1151e546e3bfda8 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 14:39:49 +0200 Subject: [PATCH 08/15] Prevent that any exception deletes the file on Gaufrette before it gets replaced on data array --- Storage/DataManager.php | 4 +++- Storage/GaufretteStorage.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index a32f38ed..dfa748ea 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -3,6 +3,7 @@ namespace Craue\FormFlowBundle\Storage; use Craue\FormFlowBundle\Form\FormFlowInterface; +use Gaufrette\File; /** * Manages data of flows and their steps. @@ -115,8 +116,9 @@ public function load(FormFlowInterface $flow) { }else{ if ($value instanceof GaufretteFile) { $downloadedFile = $this->gaufretteStorage->doDownload($flow->getGaufretteFilesystem(), $value); - $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $value); + $fileName = $value->getFileName(); $value = $value->getAsUploadedFile($downloadedFile); + $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $fileName); } } diff --git a/Storage/GaufretteStorage.php b/Storage/GaufretteStorage.php index 3eaf26cb..5529252b 100644 --- a/Storage/GaufretteStorage.php +++ b/Storage/GaufretteStorage.php @@ -44,12 +44,12 @@ public function doDownload(string $filesystem, GaufretteFile $gaufretteFile) return $filesystem->get($gaufretteFile->getFileName()); } - public function doRemove(string $filesystem, GaufretteFile $gaufretteFile) + public function doRemove(string $filesystem, string $fileName) { $filesystem = $this->getFilesystem($filesystem); try { - return $filesystem->delete($gaufretteFile->getFileName()); + return $filesystem->delete($fileName); } catch (FileNotFound $e) { return false; } From 27c18854fe8487c8508c8e3f1e7ac918d12028c4 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 14:56:11 +0200 Subject: [PATCH 09/15] Delete gaufrette temp file on drop --- Storage/DataManager.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index dfa748ea..792c562e 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -116,12 +116,9 @@ public function load(FormFlowInterface $flow) { }else{ if ($value instanceof GaufretteFile) { $downloadedFile = $this->gaufretteStorage->doDownload($flow->getGaufretteFilesystem(), $value); - $fileName = $value->getFileName(); $value = $value->getAsUploadedFile($downloadedFile); - $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $fileName); } } - }); } @@ -143,7 +140,15 @@ public function drop(FormFlowInterface $flow) { $savedFlows = $this->storage->get(DataManagerInterface::STORAGE_ROOT, []); // remove data for only this flow instance - unset($savedFlows[$flow->getName()][$flow->getInstanceId()]); + foreach($savedFlows[$flow->getName()][$flow->getInstanceId()] as $value) { + if ($flow->isHandleFileUploadsWithGaufrette()) { + if ($value instanceof GaufretteFile) { + $fileName = $value->getFileName(); + $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $fileName); + } + } + }; + unset($savedFlows[$flow->getName()][$flow->getInstanceId()]); $this->storage->set(DataManagerInterface::STORAGE_ROOT, $savedFlows); } From 786cf01ac6cf9934d457c41cf30f3aacb834ccaf Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 2 May 2020 17:16:04 +0200 Subject: [PATCH 10/15] Use random generated name always --- Storage/DataManager.php | 13 ++++--------- Storage/GaufretteFile.php | 8 +++----- Storage/GaufretteStorage.php | 6 +++++- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index 792c562e..35d6078b 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -69,7 +69,10 @@ public function save(FormFlowInterface $flow, array $data) { } }else{ if (GaufretteFile::isSupported($value)) { - $fileName = $this->gaufretteStorage->doUpload($flow->getGaufretteFilesystem(), $value); + $fileName = $value->getClientOriginalName(); + if(!$this->gaufretteStorage->hasFile($flow->getGaufretteFilesystem(), $fileName)){ + $fileName = $this->gaufretteStorage->doUpload($flow->getGaufretteFilesystem(), $value); + } $value = new GaufretteFile($fileName, $value); } } @@ -140,14 +143,6 @@ public function drop(FormFlowInterface $flow) { $savedFlows = $this->storage->get(DataManagerInterface::STORAGE_ROOT, []); // remove data for only this flow instance - foreach($savedFlows[$flow->getName()][$flow->getInstanceId()] as $value) { - if ($flow->isHandleFileUploadsWithGaufrette()) { - if ($value instanceof GaufretteFile) { - $fileName = $value->getFileName(); - $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $fileName); - } - } - }; unset($savedFlows[$flow->getName()][$flow->getInstanceId()]); $this->storage->set(DataManagerInterface::STORAGE_ROOT, $savedFlows); diff --git a/Storage/GaufretteFile.php b/Storage/GaufretteFile.php index 7d510b6e..d104c9f7 100644 --- a/Storage/GaufretteFile.php +++ b/Storage/GaufretteFile.php @@ -21,7 +21,6 @@ class GaufretteFile */ private $fileName; - private $clientOriginalName; private $clientMimeType; /** @@ -37,8 +36,7 @@ public function __construct(string $filename, $originalFile) //Filename of uploaded file with Gaufrette $this->fileName = $filename; - //Keep client original name and mime type - $this->clientOriginalName = $originalFile->getClientOriginalName(); + //Keep client original mime type $this->clientMimeType = $originalFile->getClientMimeType(); } @@ -58,10 +56,10 @@ public function getAsUploadedFile(File $file) { // avoid a deprecation notice regarding "passing a size as 4th argument to the constructor" // TODO remove as soon as Symfony >= 4.1 is required if (property_exists(UploadedFile::class, 'size')) { - return new UploadedFile($tempFile, $this->clientOriginalName, $this->clientMimeType, null, null, true); + return new UploadedFile($tempFile, $this->fileName, $this->clientMimeType, null, null, true); } - return new UploadedFile($tempFile, $this->clientOriginalName, $this->clientMimeType, null, true); + return new UploadedFile($tempFile, $this->fileName, $this->clientMimeType, null, true); } public function getFileName() { diff --git a/Storage/GaufretteStorage.php b/Storage/GaufretteStorage.php index 5529252b..eea98e5c 100644 --- a/Storage/GaufretteStorage.php +++ b/Storage/GaufretteStorage.php @@ -55,6 +55,10 @@ public function doRemove(string $filesystem, string $fileName) } } + public function hasFile(string $filesystem, string $fileName) + { + return $this->getFilesystem($filesystem)->has($fileName); + } /** * Get filesystem adapter from the property mapping. @@ -68,7 +72,7 @@ private function getFilesystem(string $filesystem): FilesystemInterface /** * Generates random name - * @todo May we can improve this by setting the extension on the random name + * TODO May we can improve this by setting the extension on the random name * @return string|string[] */ private function generateRandomName() From 279bf266e0159249afaee1cec9ed7842480b5a28 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 3 May 2020 13:37:17 +0200 Subject: [PATCH 11/15] Allow to get gaufrette storage --- Storage/DataManager.php | 7 +++++++ Storage/DataManagerInterface.php | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index 35d6078b..95d3b3b2 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -56,6 +56,13 @@ public function getStorage() { return $this->storage; } + /** + * {@inheritDoc} + */ + public function getGaufretteStorage() { + return $this->gaufretteStorage; + } + /** * {@inheritDoc} */ diff --git a/Storage/DataManagerInterface.php b/Storage/DataManagerInterface.php index 07555428..402a21b0 100644 --- a/Storage/DataManagerInterface.php +++ b/Storage/DataManagerInterface.php @@ -21,6 +21,11 @@ interface DataManagerInterface { */ function getStorage(); + /** + * @return GaufretteStorage + */ + function getGaufretteStorage(); + /** * Saves data of the given flow. * @param FormFlowInterface $flow From db1bdf69816c1c15878312f8015b96791caa4b86 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 3 May 2020 13:50:02 +0200 Subject: [PATCH 12/15] Call cleanup to remove tmp files from gaufrette --- Form/FormFlow.php | 4 ++++ Storage/DataManager.php | 24 ++++++++++++++++++++++++ Storage/DataManagerInterface.php | 7 +++++++ Storage/GaufretteStorage.php | 4 ++-- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Form/FormFlow.php b/Form/FormFlow.php index 9849fc26..ed0b2e44 100644 --- a/Form/FormFlow.php +++ b/Form/FormFlow.php @@ -488,6 +488,10 @@ protected function applySkipping($stepNumber, $direction = 1) { * {@inheritDoc} */ public function reset() { + if(!empty($this->currentStepNumber) && $this->getCurrentStepNumber() >= $this->getLastStepNumber()){ + $this->getDataManager()->cleanup($this); + } + $this->dataManager->drop($this); $this->currentStepNumber = $this->getFirstStepNumber(); $this->newInstance = true; diff --git a/Storage/DataManager.php b/Storage/DataManager.php index 95d3b3b2..ac7b3ead 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -143,6 +143,30 @@ public function exists(FormFlowInterface $flow) { return isset($savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY]); } + /** + * {@inheritDoc} + */ + public function cleanup(FormFlowInterface $flow) { + $data = []; + + // try to find data for the given flow + $savedFlows = $this->storage->get(DataManagerInterface::STORAGE_ROOT, []); + if (isset($savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY])) { + $data = $savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY]; + } + + // handle file uploads + if ($flow->isHandleFileUploads()) { + array_walk_recursive($data, function(&$value, $key) use ($flow) { + if($flow->isHandleFileUploadsWithGaufrette()){ + if ($value instanceof GaufretteFile) { + $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $value); + } + } + }); + } + } + /** * {@inheritDoc} */ diff --git a/Storage/DataManagerInterface.php b/Storage/DataManagerInterface.php index 402a21b0..283b55c8 100644 --- a/Storage/DataManagerInterface.php +++ b/Storage/DataManagerInterface.php @@ -47,6 +47,13 @@ function exists(FormFlowInterface $flow); */ function load(FormFlowInterface $flow); + /** + * Cleanups Gaufrette temp data of the given flow. + * @param FormFlowInterface $flow + * @return bool + */ + function cleanup(FormFlowInterface $flow); + /** * Drops data of the given flow. * @param FormFlowInterface $flow diff --git a/Storage/GaufretteStorage.php b/Storage/GaufretteStorage.php index eea98e5c..25864153 100644 --- a/Storage/GaufretteStorage.php +++ b/Storage/GaufretteStorage.php @@ -44,12 +44,12 @@ public function doDownload(string $filesystem, GaufretteFile $gaufretteFile) return $filesystem->get($gaufretteFile->getFileName()); } - public function doRemove(string $filesystem, string $fileName) + public function doRemove(string $filesystem, GaufretteFile $gaufretteFile) { $filesystem = $this->getFilesystem($filesystem); try { - return $filesystem->delete($fileName); + return $filesystem->delete($gaufretteFile->getFileName()); } catch (FileNotFound $e) { return false; } From a75ca3730b1c3cc77d743939b9afa5824f47cd4a Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 3 May 2020 13:56:21 +0200 Subject: [PATCH 13/15] Add some docs --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 065196e3..1f5206c0 100644 --- a/README.md +++ b/README.md @@ -588,6 +588,23 @@ class CreateVehicleFlow extends FormFlow { } ``` +File uploads can be handled by Gaufrette, a library that provides a filesystem abstraction layer.This can be very useful when yo dou a cluster deployment or you store sessions on Redis. +Just define a Gaufrette filesystem and add this 2 lines: + +```php +// in src/MyCompany/MyBundle/Form/CreateVehicleFlow.php +class CreateVehicleFlow extends FormFlow { + + protected $handleFileUploadsWithGaufrette = true; + protected $gaufretteFilesystem = 'tmp_uploads'; + + // ... + +} +``` +More info here: +https://github.com/KnpLabs/KnpGaufretteBundle#configuring-the-filesystems + ## Enabling redirect after submit This feature will allow performing a redirect after submitting a step to load the page containing the next step using a GET request. From ca04ee86146cf4344492fea18e82bf303b51d171 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 3 May 2020 14:05:04 +0200 Subject: [PATCH 14/15] Fix tab --- Storage/DataManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Storage/DataManager.php b/Storage/DataManager.php index ac7b3ead..d767b17d 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -174,7 +174,7 @@ public function drop(FormFlowInterface $flow) { $savedFlows = $this->storage->get(DataManagerInterface::STORAGE_ROOT, []); // remove data for only this flow instance - unset($savedFlows[$flow->getName()][$flow->getInstanceId()]); + unset($savedFlows[$flow->getName()][$flow->getInstanceId()]); $this->storage->set(DataManagerInterface::STORAGE_ROOT, $savedFlows); } From 30a75dafe35cb9694485bf97d5e7e0aeb7244343 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 3 May 2020 14:17:30 +0200 Subject: [PATCH 15/15] Use tabs to indent --- Form/FormFlow.php | 39 ++++----- Form/FormFlowInterface.php | 18 ++-- Storage/DataManager.php | 122 +++++++++++++-------------- Storage/DataManagerInterface.php | 20 ++--- Storage/GaufretteFile.php | 96 ++++++++++----------- Storage/GaufretteStorage.php | 140 ++++++++++++++++--------------- 6 files changed, 219 insertions(+), 216 deletions(-) diff --git a/Form/FormFlow.php b/Form/FormFlow.php index ed0b2e44..b9c2fbc3 100644 --- a/Form/FormFlow.php +++ b/Form/FormFlow.php @@ -73,12 +73,12 @@ abstract class FormFlow implements FormFlowInterface { /** * @var bool If file uploads should be handled with Gaufrette */ - protected $handleFileUploadsWithGaufrette = false; + protected $handleFileUploadsWithGaufrette = false; /** * @var string Filesystem that Gaufrette will use */ - protected $gaufretteFilesystem = null; + protected $gaufretteFilesystem = null; /** * @var string|null Directory for storing temporary files while handling uploads. If null, the system's default will be used. @@ -394,24 +394,19 @@ public function getHandleFileUploadsTempDir() { return $this->handleFileUploadsTempDir; } - /** - * {@inheritDoc} - */ - public function isHandleFileUploadsWithGaufrette() { - return $this->handleFileUploadsWithGaufrette; - } - - public function setGaufretteFilesystem($gaufretteFilesystem) { - $this->gaufretteFilesystem = $gaufretteFilesystem !== null ? (string) $gaufretteFilesystem : null; - - } + /** + * {@inheritDoc} + */ + public function isHandleFileUploadsWithGaufrette() { + return $this->handleFileUploadsWithGaufrette; + } - /** - * {@inheritDoc} - */ - public function getGaufretteFilesystem() { - return $this->gaufretteFilesystem; - } + /** + * {@inheritDoc} + */ + public function getGaufretteFilesystem() { + return $this->gaufretteFilesystem; + } public function setAllowRedirectAfterSubmit($allowRedirectAfterSubmit) { $this->allowRedirectAfterSubmit = (bool) $allowRedirectAfterSubmit; @@ -488,9 +483,9 @@ protected function applySkipping($stepNumber, $direction = 1) { * {@inheritDoc} */ public function reset() { - if(!empty($this->currentStepNumber) && $this->getCurrentStepNumber() >= $this->getLastStepNumber()){ - $this->getDataManager()->cleanup($this); - } + if(!empty($this->currentStepNumber) && $this->getCurrentStepNumber() >= $this->getLastStepNumber()){ + $this->getDataManager()->cleanup($this); + } $this->dataManager->drop($this); $this->currentStepNumber = $this->getFirstStepNumber(); diff --git a/Form/FormFlowInterface.php b/Form/FormFlowInterface.php index 6ba4e51e..bb0e3868 100644 --- a/Form/FormFlowInterface.php +++ b/Form/FormFlowInterface.php @@ -66,15 +66,15 @@ function isHandleFileUploads(); */ function getHandleFileUploadsTempDir(); - /** - * @var bool If file uploads should be handled with Gaufrette - */ - function isHandleFileUploadsWithGaufrette(); - - /** - * @return string|null Filesystem that Gaufrette will use - */ - function getGaufretteFilesystem(); + /** + * @var bool If file uploads should be handled with Gaufrette + */ + function isHandleFileUploadsWithGaufrette(); + + /** + * @return string|null Filesystem that Gaufrette will use + */ + function getGaufretteFilesystem(); /** * @return bool diff --git a/Storage/DataManager.php b/Storage/DataManager.php index d767b17d..2ad9b13a 100644 --- a/Storage/DataManager.php +++ b/Storage/DataManager.php @@ -35,15 +35,15 @@ class DataManager implements ExtendedDataManagerInterface { */ private $storage; - /** - * @var GaufretteStorage - */ + /** + * @var GaufretteStorage + */ private $gaufretteStorage; - /** - * @param StorageInterface $storage - * @param GaufretteStorage $gaufretteStorage - */ + /** + * @param StorageInterface $storage + * @param GaufretteStorage $gaufretteStorage + */ public function __construct(StorageInterface $storage, GaufretteStorage $gaufretteStorage) { $this->storage = $storage; $this->gaufretteStorage = $gaufretteStorage; @@ -56,12 +56,12 @@ public function getStorage() { return $this->storage; } - /** - * {@inheritDoc} - */ - public function getGaufretteStorage() { - return $this->gaufretteStorage; - } + /** + * {@inheritDoc} + */ + public function getGaufretteStorage() { + return $this->gaufretteStorage; + } /** * {@inheritDoc} @@ -69,21 +69,21 @@ public function getGaufretteStorage() { public function save(FormFlowInterface $flow, array $data) { // handle file uploads if ($flow->isHandleFileUploads()) { - array_walk_recursive($data, function(&$value, $key) use ($flow) { - if(!$flow->isHandleFileUploadsWithGaufrette()){ - if (SerializableFile::isSupported($value)) { - $value = new SerializableFile($value); - } - }else{ - if (GaufretteFile::isSupported($value)) { - $fileName = $value->getClientOriginalName(); - if(!$this->gaufretteStorage->hasFile($flow->getGaufretteFilesystem(), $fileName)){ - $fileName = $this->gaufretteStorage->doUpload($flow->getGaufretteFilesystem(), $value); - } - $value = new GaufretteFile($fileName, $value); - } - } - }); + array_walk_recursive($data, function(&$value, $key) use ($flow) { + if(!$flow->isHandleFileUploadsWithGaufrette()){ + if (SerializableFile::isSupported($value)) { + $value = new SerializableFile($value); + } + }else{ + if (GaufretteFile::isSupported($value)) { + $fileName = $value->getClientOriginalName(); + if(!$this->gaufretteStorage->hasFile($flow->getGaufretteFilesystem(), $fileName)){ + $fileName = $this->gaufretteStorage->doUpload($flow->getGaufretteFilesystem(), $value); + } + $value = new GaufretteFile($fileName, $value); + } + } + }); } // drop old data @@ -119,16 +119,16 @@ public function load(FormFlowInterface $flow) { if ($flow->isHandleFileUploads()) { $tempDir = $flow->getHandleFileUploadsTempDir(); array_walk_recursive($data, function(&$value, $key) use ($flow, $tempDir) { - if(!$flow->isHandleFileUploadsWithGaufrette()){ - if ($value instanceof SerializableFile) { - $value = $value->getAsFile($tempDir); - } - }else{ - if ($value instanceof GaufretteFile) { - $downloadedFile = $this->gaufretteStorage->doDownload($flow->getGaufretteFilesystem(), $value); - $value = $value->getAsUploadedFile($downloadedFile); - } - } + if(!$flow->isHandleFileUploadsWithGaufrette()){ + if ($value instanceof SerializableFile) { + $value = $value->getAsFile($tempDir); + } + }else{ + if ($value instanceof GaufretteFile) { + $downloadedFile = $this->gaufretteStorage->doDownload($flow->getGaufretteFilesystem(), $value); + $value = $value->getAsUploadedFile($downloadedFile); + } + } }); } @@ -143,29 +143,29 @@ public function exists(FormFlowInterface $flow) { return isset($savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY]); } - /** - * {@inheritDoc} - */ - public function cleanup(FormFlowInterface $flow) { - $data = []; - - // try to find data for the given flow - $savedFlows = $this->storage->get(DataManagerInterface::STORAGE_ROOT, []); - if (isset($savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY])) { - $data = $savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY]; - } - - // handle file uploads - if ($flow->isHandleFileUploads()) { - array_walk_recursive($data, function(&$value, $key) use ($flow) { - if($flow->isHandleFileUploadsWithGaufrette()){ - if ($value instanceof GaufretteFile) { - $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $value); - } - } - }); - } - } + /** + * {@inheritDoc} + */ + public function cleanup(FormFlowInterface $flow) { + $data = []; + + // try to find data for the given flow + $savedFlows = $this->storage->get(DataManagerInterface::STORAGE_ROOT, []); + if (isset($savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY])) { + $data = $savedFlows[$flow->getName()][$flow->getInstanceId()][self::DATA_KEY]; + } + + // look for Gaufrette files to cleanup + if ($flow->isHandleFileUploads()) { + array_walk_recursive($data, function(&$value, $key) use ($flow) { + if($flow->isHandleFileUploadsWithGaufrette()){ + if ($value instanceof GaufretteFile) { + $this->gaufretteStorage->doRemove($flow->getGaufretteFilesystem(), $value); + } + } + }); + } + } /** * {@inheritDoc} diff --git a/Storage/DataManagerInterface.php b/Storage/DataManagerInterface.php index 283b55c8..e983b136 100644 --- a/Storage/DataManagerInterface.php +++ b/Storage/DataManagerInterface.php @@ -21,10 +21,10 @@ interface DataManagerInterface { */ function getStorage(); - /** - * @return GaufretteStorage - */ - function getGaufretteStorage(); + /** + * @return GaufretteStorage + */ + function getGaufretteStorage(); /** * Saves data of the given flow. @@ -47,12 +47,12 @@ function exists(FormFlowInterface $flow); */ function load(FormFlowInterface $flow); - /** - * Cleanups Gaufrette temp data of the given flow. - * @param FormFlowInterface $flow - * @return bool - */ - function cleanup(FormFlowInterface $flow); + /** + * Cleanups Gaufrette temp data of the given flow. + * @param FormFlowInterface $flow + * @return bool + */ + function cleanup(FormFlowInterface $flow); /** * Drops data of the given flow. diff --git a/Storage/GaufretteFile.php b/Storage/GaufretteFile.php index d104c9f7..88da3cdb 100644 --- a/Storage/GaufretteFile.php +++ b/Storage/GaufretteFile.php @@ -16,62 +16,64 @@ */ class GaufretteFile { - /** - * @var string Name of the file provided by Gaufrette on upload - */ - private $fileName; + /** + * @var string Name of the file provided by Gaufrette on upload + */ + private $fileName; - private $clientMimeType; + private $clientMimeType; - /** - * @param string $filename - * @param $originalFile - */ - public function __construct(string $filename, $originalFile) - { - if (!self::isSupported($originalFile)) { - throw new InvalidTypeException($originalFile, UploadedFile::class); - } + /** + * @param string $filename + * @param $originalFile + */ + public function __construct(string $filename, $originalFile) + { + if (!self::isSupported($originalFile)) { + throw new InvalidTypeException($originalFile, UploadedFile::class); + } - //Filename of uploaded file with Gaufrette - $this->fileName = $filename; + //Filename of uploaded file with Gaufrette + $this->fileName = $filename; - //Keep client original mime type - $this->clientMimeType = $originalFile->getClientMimeType(); - } + //Keep client original mime type + $this->clientMimeType = $originalFile->getClientMimeType(); + } - /** - * @param File $file - * @return mixed The file retrieved from Gaufrette converted to UploadedFile - */ - public function getAsUploadedFile(File $file) { - $tempDir = sys_get_temp_dir(); + /** + * @param File $file + * @return mixed The file retrieved from Gaufrette converted to UploadedFile + */ + public function getAsUploadedFile(File $file) + { + $tempDir = sys_get_temp_dir(); - // create a temporary file with its original content - $tempFile = tempnam($tempDir, 'craue_form_flow_serialized_file'); - file_put_contents($tempFile, $file->getContent()); + // create a temporary file with its original content + $tempFile = tempnam($tempDir, 'craue_form_flow_serialized_file'); + file_put_contents($tempFile, $file->getContent()); - TempFileUtil::addTempFile($tempFile); + TempFileUtil::addTempFile($tempFile); - // avoid a deprecation notice regarding "passing a size as 4th argument to the constructor" - // TODO remove as soon as Symfony >= 4.1 is required - if (property_exists(UploadedFile::class, 'size')) { - return new UploadedFile($tempFile, $this->fileName, $this->clientMimeType, null, null, true); - } + // avoid a deprecation notice regarding "passing a size as 4th argument to the constructor" + // TODO remove as soon as Symfony >= 4.1 is required + if (property_exists(UploadedFile::class, 'size')) { + return new UploadedFile($tempFile, $this->fileName, $this->clientMimeType, null, null, true); + } - return new UploadedFile($tempFile, $this->fileName, $this->clientMimeType, null, true); - } + return new UploadedFile($tempFile, $this->fileName, $this->clientMimeType, null, true); + } - public function getFileName() { - return $this->fileName; - } + public function getFileName() + { + return $this->fileName; + } - /** - * @param mixed $file - * @return bool - */ - public static function isSupported($file) - { - return $file instanceof UploadedFile; - } + /** + * @param mixed $file + * @return bool + */ + public static function isSupported($file) + { + return $file instanceof UploadedFile; + } } diff --git a/Storage/GaufretteStorage.php b/Storage/GaufretteStorage.php index 25864153..c86dea80 100644 --- a/Storage/GaufretteStorage.php +++ b/Storage/GaufretteStorage.php @@ -10,73 +10,79 @@ use Gaufrette\FilesystemMapInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; - +/** + * Stores data using Gaufrette. + * + * @author Kevin Cerro + * @copyright 2020 Kevin Cerro + * @license http://opensource.org/licenses/mit-license.php MIT License + */ class GaufretteStorage { - private $filesystemMap; - - /** - * Constructs a new instance of GaufretteStorage. - * - * @param FilesystemMapInterface $filesystemMap - */ - public function __construct(FilesystemMapInterface $filesystemMap) - { - $this->filesystemMap = $filesystemMap; - } - - public function doUpload(string $filesystem, UploadedFile $file) - { - $filesystem = $this->getFilesystem($filesystem); - $randomName = $this->generateRandomName(); - - if ($filesystem->getAdapter() instanceof MetadataSupporter) { - $filesystem->getAdapter()->setMetadata($randomName, ['contentType' => $file->getMimeType()]); - } - - $filesystem->write($randomName, file_get_contents($file->getPathname()), true); - return $randomName; - } - - public function doDownload(string $filesystem, GaufretteFile $gaufretteFile) - { - $filesystem = $this->getFilesystem($filesystem); - return $filesystem->get($gaufretteFile->getFileName()); - } - - public function doRemove(string $filesystem, GaufretteFile $gaufretteFile) - { - $filesystem = $this->getFilesystem($filesystem); - - try { - return $filesystem->delete($gaufretteFile->getFileName()); - } catch (FileNotFound $e) { - return false; - } - } - - public function hasFile(string $filesystem, string $fileName) - { - return $this->getFilesystem($filesystem)->has($fileName); - } - - /** - * Get filesystem adapter from the property mapping. - * @param string $filesystem - * @return FilesystemInterface - */ - private function getFilesystem(string $filesystem): FilesystemInterface - { - return $this->filesystemMap->get($filesystem); - } - - /** - * Generates random name - * TODO May we can improve this by setting the extension on the random name - * @return string|string[] - */ - private function generateRandomName() - { - return str_replace('.', '', \uniqid('', true)); - } + private $filesystemMap; + + /** + * Constructs a new instance of GaufretteStorage. + * + * @param FilesystemMapInterface $filesystemMap + */ + public function __construct(FilesystemMapInterface $filesystemMap) + { + $this->filesystemMap = $filesystemMap; + } + + public function doUpload(string $filesystem, UploadedFile $file) + { + $filesystem = $this->getFilesystem($filesystem); + $randomName = $this->generateRandomName(); + + if ($filesystem->getAdapter() instanceof MetadataSupporter) { + $filesystem->getAdapter()->setMetadata($randomName, ['contentType' => $file->getMimeType()]); + } + + $filesystem->write($randomName, file_get_contents($file->getPathname()), true); + return $randomName; + } + + public function doDownload(string $filesystem, GaufretteFile $gaufretteFile) + { + $filesystem = $this->getFilesystem($filesystem); + return $filesystem->get($gaufretteFile->getFileName()); + } + + public function doRemove(string $filesystem, GaufretteFile $gaufretteFile) + { + $filesystem = $this->getFilesystem($filesystem); + + try { + return $filesystem->delete($gaufretteFile->getFileName()); + } catch (FileNotFound $e) { + return false; + } + } + + public function hasFile(string $filesystem, string $fileName) + { + return $this->getFilesystem($filesystem)->has($fileName); + } + + /** + * Get filesystem adapter from the property mapping. + * @param string $filesystem + * @return FilesystemInterface + */ + private function getFilesystem(string $filesystem): FilesystemInterface + { + return $this->filesystemMap->get($filesystem); + } + + /** + * Generates random name + * TODO May we can improve this by setting the extension on the random name + * @return string|string[] + */ + private function generateRandomName() + { + return str_replace('.', '', \uniqid('', true)); + } } \ No newline at end of file