diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index 7829b6f1f..21e227954 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -14,9 +14,9 @@ jobs: fail-fast: false matrix: operating-system: [ ubuntu-latest ] - php-version: [ '7.4', '8.0', '8.1' ] + php-version: [ '8.1', '8.2', '8.3' ] include: - - php-version: '8.1' + - php-version: '8.3' coverage: true steps: diff --git a/common/oatbox/filesystem/Directory.php b/common/oatbox/filesystem/Directory.php index be239d313..8af006963 100644 --- a/common/oatbox/filesystem/Directory.php +++ b/common/oatbox/filesystem/Directory.php @@ -21,8 +21,6 @@ namespace oat\oatbox\filesystem; -use League\Flysystem\FileExistsException; - class Directory extends FileSystemHandler implements \IteratorAggregate { public const ITERATOR_RECURSIVE = '1'; @@ -87,14 +85,13 @@ public function getFlyIterator($flags = null) $contents = $this->getFileSystem()->listContents($this->getPrefix(), $recursive); if (!empty($contents)) { - $dirPath = $this->getFileSystem()->get($this->getPrefix())->getPath(); foreach ($contents as $content) { if ($withDirectories && $content['type'] == 'dir') { - $iterator[] = $this->getDirectory(str_replace($dirPath, '', $content['path'])); + $iterator[] = $this->getDirectory($this->stripDirectoryPath($content['path'])); } if ($withFiles && $content['type'] == 'file') { - $iterator[] = $this->getFile(str_replace($dirPath, '', $content['path'])); + $iterator[] = $this->getFile($this->stripDirectoryPath($content['path'])); } } } @@ -127,7 +124,7 @@ public function getRelPath($content) */ public function exists() { - return $this->getFileSystem()->has($this->getPrefix()); + return $this->getFileSystem()->directoryExists($this->getPrefix()); } /** @@ -137,7 +134,14 @@ public function exists() */ public function deleteSelf() { - return $this->getFileSystem()->deleteDir($this->getPrefix()); + try { + $this->getFileSystem()->deleteDirectory($this->getPrefix()); + return true; + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); + } + + return false; } /** @@ -185,15 +189,10 @@ public function rename($path) foreach ($filePaths as $renaming) { try { - if ($this->getFileSystem()->rename($renaming['source'], $renaming['destination']) === false) { - throw new \common_exception_FileSystemError( - "Unable to rename '" . $renaming['source'] . "' into '" . $renaming['destination'] . "'." - ); - } - } catch (FileExistsException $e) { + $this->getFileSystem()->move($renaming['source'], $renaming['destination']); + } catch (FilesystemException $e) { throw new \common_exception_FileSystemError( - "Unable to rename '" . $renaming['source'] . "' into '" . $renaming['destination'] - . "'. File already exists." + "Unable to rename '" . $renaming['source'] . "' into '" . $renaming['destination'] . "'." ); } } @@ -206,4 +205,10 @@ public function rename($path) return true; } + + private function stripDirectoryPath(string $path): string + { + $strippedPath = str_replace($this->getPrefix(), '', $path); + return str_replace($this->getFileSystemId(), '', $strippedPath); + } } diff --git a/common/oatbox/filesystem/File.php b/common/oatbox/filesystem/File.php index 7ccdba8fc..25f6058c8 100644 --- a/common/oatbox/filesystem/File.php +++ b/common/oatbox/filesystem/File.php @@ -21,21 +21,15 @@ namespace oat\oatbox\filesystem; +use common_Logger; use GuzzleHttp\Psr7\Stream; use GuzzleHttp\Psr7\StreamWrapper; -use League\Flysystem\FileNotFoundException; use Psr\Http\Message\StreamInterface; -use League\Flysystem\FileExistsException; use tao_helpers_File; class File extends FileSystemHandler { - /** - * Get basename of $this file - * - * @return string - */ - public function getBasename() + public function getBasename(): string { return basename($this->getPrefix()); } @@ -48,7 +42,7 @@ public function getBasename() public function getMimeType() { try { - $mimeType = $this->getFileSystem()->getMimetype($this->getPrefix()); + $mimeType = $this->getFileSystem()->mimeType($this->getPrefix()); $suffix = substr($this->getPrefix(), -4); if ($mimeType === 'text/plain' && $suffix === '.css') { $mimeType = 'text/css'; @@ -59,7 +53,8 @@ public function getMimeType() } return $mimeType; - } catch (FileNotFoundException $e) { + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); } return false; } @@ -71,24 +66,7 @@ public function getMimeType() */ public function getSize() { - return $this->getFileSystem()->getSize($this->getPrefix()); - } - - /** - * Get metadata of $this file - * - * @return array|bool - */ - public function getMetadata() - { - try { - $path = $this->getPrefix(); - if ($this->getFileSystem()->has($path)) { - return $this->getFileSystem()->get($path)->getMetadata(); - } - } catch (FileNotFoundException $e) { - } - return false; + return $this->getFileSystem()->fileSize($this->getPrefix()); } /** @@ -100,36 +78,47 @@ public function getMetadata() * @param null $mimeType * @return bool * @throws \common_Exception - * @throws FileExistsException */ public function write($mixed, $mimeType = null) { $config = (is_null($mimeType)) ? [] : ['ContentType' => $mimeType]; - if (is_string($mixed)) { - return $this->getFileSystem()->write($this->getPrefix(), $mixed, $config); - } elseif (is_resource($mixed)) { - return $this->getFileSystem()->writeStream($this->getPrefix(), $mixed, $config); - } elseif ($mixed instanceof StreamInterface) { - if (!$mixed->isReadable()) { - throw new \common_Exception('Stream is not readable. Write to filesystem aborted.'); - } - if (!$mixed->isSeekable()) { - throw new \common_Exception('Stream is not seekable. Write to filesystem aborted.'); - } - $mixed->rewind(); - - $resource = StreamWrapper::getResource($mixed); - if (!is_resource($resource)) { - throw new \common_Exception( - 'Unable to create resource from the given stream. Write to filesystem aborted.' - ); + try { + if (is_string($mixed)) { + $this->getFileSystem()->write($this->getPrefix(), $mixed, $config); + } elseif (is_resource($mixed)) { + $this->getFileSystem()->writeStream($this->getPrefix(), $mixed, $config); + } elseif ($mixed instanceof StreamInterface) { + if (!$mixed->isReadable()) { + throw new \common_Exception('Stream is not readable. Write to filesystem aborted.'); + } + if ($mixed->isSeekable()) { + $mixed->rewind(); + } elseif ($mixed->eof()) { + throw new \common_Exception( + 'Stream is not seekable and is already processed. Write to filesystem aborted.' + ); + } + + $resource = StreamWrapper::getResource($mixed); + if (!is_resource($resource)) { + throw new \common_Exception( + 'Unable to create resource from the given stream. Write to filesystem aborted.' + ); + } + $this->getFileSystem()->writeStream($this->getPrefix(), $resource, $config); + } else { + throw new \InvalidArgumentException(sprintf( + 'Value to be written has to be: string, resource or StreamInterface, "%s" given.', + gettype($mixed) + )); } - return $this->getFileSystem()->writeStream($this->getPrefix(), $resource, $config); - } else { - throw new \InvalidArgumentException('Value to be written has to be: string, resource or StreamInterface, ' . - '"' . gettype($mixed) . '" given.'); + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); + return false; } + + return true; } /** @@ -140,45 +129,17 @@ public function write($mixed, $mimeType = null) * @param $mixed * @param null $mimeType * @return bool - * @throws \FileNotFoundException * @throws \common_Exception */ public function update($mixed, $mimeType = null) { if (!$this->exists()) { - throw new \FileNotFoundException('File "' . $this->getPrefix() . '" not found."'); - } - - \common_Logger::i('Writting in ' . $this->getPrefix()); - $config = (is_null($mimeType)) ? [] : ['ContentType' => $mimeType]; - - if (is_string($mixed)) { - return $this->getFileSystem()->update($this->getPrefix(), $mixed, $config); + throw new \RuntimeException('File "' . $this->getPrefix() . '" not found."'); } - if (is_resource($mixed)) { - return $this->getFileSystem()->updateStream($this->getPrefix(), $mixed, $config); - } + common_Logger::i('Writing in ' . $this->getPrefix()); - if ($mixed instanceof StreamInterface) { - if (!$mixed->isReadable()) { - throw new \common_Exception('Stream is not readable. Write to filesystem aborted.'); - } - if (!$mixed->isSeekable()) { - throw new \common_Exception('Stream is not seekable. Write to filesystem aborted.'); - } - $mixed->rewind(); - - $resource = StreamWrapper::getResource($mixed); - if (!is_resource($resource)) { - throw new \common_Exception( - 'Unable to create resource from the given stream. Write to filesystem aborted.' - ); - } - return $this->getFileSystem()->updateStream($this->getPrefix(), $resource, $config); - } - - throw new \InvalidArgumentException('Value to be written has to be: string, resource or StreamInterface'); + return $this->write($mixed, $mimeType); } /** @@ -193,36 +154,9 @@ public function update($mixed, $mimeType = null) */ public function put($mixed, $mimeType = null) { - \common_Logger::i('Writting in ' . $this->getPrefix()); - $config = (is_null($mimeType)) ? [] : ['ContentType' => $mimeType]; + common_Logger::i('Writting in ' . $this->getPrefix()); - if (is_string($mixed)) { - return $this->getFileSystem()->put($this->getPrefix(), $mixed, $config); - } - - if (is_resource($mixed)) { - return $this->getFileSystem()->putStream($this->getPrefix(), $mixed, $config); - } - - if ($mixed instanceof StreamInterface) { - if (!$mixed->isReadable()) { - throw new \common_Exception('Stream is not readable. Write to filesystem aborted.'); - } - if (!$mixed->isSeekable()) { - throw new \common_Exception('Stream is not seekable. Write to filesystem aborted.'); - } - $mixed->rewind(); - - $resource = StreamWrapper::getResource($mixed); - if (!is_resource($resource)) { - throw new \common_Exception( - 'Unable to create resource from the given stream. Write to filesystem aborted.' - ); - } - return $this->getFileSystem()->putStream($this->getPrefix(), $resource, $config); - } - - throw new \InvalidArgumentException('Value to be written has to be: string, resource or StreamInterface'); + return $this->write($mixed, $mimeType); } /** @@ -232,7 +166,13 @@ public function put($mixed, $mimeType = null) */ public function read() { - return $this->getFileSystem()->read($this->getPrefix()); + try { + return $this->getFileSystem()->read($this->getPrefix()); + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); + } + + return false; } /** @@ -242,7 +182,13 @@ public function read() */ public function readStream() { - return $this->getFileSystem()->readStream($this->getPrefix()); + try { + return $this->getFileSystem()->readStream($this->getPrefix()); + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); + } + + return false; } /** @@ -252,38 +198,33 @@ public function readStream() */ public function readPsrStream() { - return new Stream($this->getFileSystem()->readStream($this->getPrefix())); + $resource = null; + try { + $resource = $this->getFileSystem()->readStream($this->getPrefix()); + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); + } + + return new Stream($resource); } - /** - * Check if $this file exists && is file - * - * @return bool - */ - public function exists() + public function exists(): bool { try { - $path = $this->getPrefix(); - - if ($this->getFileSystem()->has($path)) { - $metadata = $this->getFileSystem()->getMetadata($this->getPrefix()); - return $metadata['type'] === 'file'; - } - } catch (FileNotFoundException $e) { + return $this->getFileSystem()->fileExists($this->getPrefix()); + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); } return false; } - /** - * Delete $this file - * - * @return bool - */ - public function delete() + public function delete(): bool { try { - return $this->getFileSystem()->delete($this->getPrefix()); - } catch (FileNotFoundException $e) { + $this->getFileSystem()->delete($this->getPrefix()); + return true; + } catch (FilesystemException $e) { + $this->logWarning($e->getMessage()); } return false; diff --git a/common/oatbox/filesystem/FileSystem.php b/common/oatbox/filesystem/FileSystem.php index 78c9a8b2f..de8eb19e5 100644 --- a/common/oatbox/filesystem/FileSystem.php +++ b/common/oatbox/filesystem/FileSystem.php @@ -21,9 +21,9 @@ namespace oat\oatbox\filesystem; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; use oat\oatbox\filesystem\utils\FileSystemWrapperTrait; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; /** * Class Filesystem @@ -38,7 +38,7 @@ class FileSystem implements FilesystemInterface protected $id; /** - * @var FilesystemInterface + * @var FilesystemOperator */ protected $filesystem; @@ -53,7 +53,7 @@ class FileSystem implements FilesystemInterface * @param $id * @param $adapter */ - public function __construct($id, FilesystemInterface $flySystem, $prefix) + public function __construct($id, FilesystemOperator $flySystem, $prefix) { $this->id = $id; $this->filesystem = $flySystem; @@ -69,10 +69,9 @@ public function getId() } /** - * @return FilesystemInterface - * @throws \common_Exception + * @return FilesystemOperator */ - protected function getFileSystem() + protected function getFileSystem(): FilesystemOperator { return $this->filesystem; } @@ -80,9 +79,9 @@ protected function getFileSystem() /** * Get the Adapter. * - * @return AdapterInterface adapter + * @return FilesystemAdapter adapter */ - private function getAdapter() + public function getAdapter() { return $this->getFileSystem()->getAdapter(); } diff --git a/common/oatbox/filesystem/FileSystemHandler.php b/common/oatbox/filesystem/FileSystemHandler.php index d9c63f6cd..efc6b310d 100644 --- a/common/oatbox/filesystem/FileSystemHandler.php +++ b/common/oatbox/filesystem/FileSystemHandler.php @@ -22,6 +22,7 @@ namespace oat\oatbox\filesystem; +use oat\oatbox\log\LoggerAwareTrait; use oat\oatbox\service\ServiceManager; use ReflectionClass; use ReflectionProperty; @@ -31,8 +32,9 @@ abstract class FileSystemHandler implements ServiceLocatorAwareInterface { use ServiceLocatorAwareTrait; + use LoggerAwareTrait; - private const NOT_SERIALIZABLE_PROPERTIES = ['fileSystem', 'serviceLocator']; + private const NOT_SERIALIZABLE_PROPERTIES = ['fileSystem', 'serviceLocator', 'logger']; /** * @var mixed diff --git a/common/oatbox/filesystem/FileSystemService.php b/common/oatbox/filesystem/FileSystemService.php index eb5542d1d..66dcebf24 100755 --- a/common/oatbox/filesystem/FileSystemService.php +++ b/common/oatbox/filesystem/FileSystemService.php @@ -21,12 +21,13 @@ namespace oat\oatbox\filesystem; +use League\Flysystem\Local\LocalFilesystemAdapter; use oat\oatbox\service\ConfigurableService; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FilesystemAdapter; use common_exception_Error; use Zend\ServiceManager\ServiceLocatorAwareInterface; use League\Flysystem\Filesystem as FlyFileSystem; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; /** * A service to reference and retrieve filesystems @@ -41,9 +42,7 @@ class FileSystemService extends ConfigurableService public const OPTION_DIRECTORIES = 'dirs'; - public const FLYSYSTEM_ADAPTER_NS = '\\League\\Flysystem\\Adapter\\'; - - public const FLYSYSTEM_LOCAL_ADAPTER = 'Local'; + private const FLYSYSTEM_NS = '\\League\\Flysystem\\'; private $filesystems = []; @@ -98,7 +97,7 @@ public function hasDirectory($id) * Retrieve an existing FileSystem by ID. * * @param string $id - * @return FilesystemInterface + * @return FileSystem * @throws \common_exception_Error * @throws \common_exception_NotFound */ @@ -118,7 +117,7 @@ public function getFileSystem($id) * * @param string $id * @param string $subPath - * @return FilesystemInterface + * @return FileSystem */ public function createFileSystem($id, $subPath = null) { @@ -131,7 +130,7 @@ public function createFileSystem($id, $subPath = null) * * @deprecated never rely on a directory being local, use addDir instead * @param string $id - * @return FilesystemInterface + * @return FilesystemOperator */ public function createLocalFileSystem($id) { @@ -152,8 +151,8 @@ public function registerLocalFileSystem($id, $path) { $adapters = $this->hasOption(self::OPTION_ADAPTERS) ? $this->getOption(self::OPTION_ADAPTERS) : []; $adapters[$id] = [ - 'class' => self::FLYSYSTEM_LOCAL_ADAPTER, - 'options' => ['root' => $path] + 'class' => LocalFilesystemAdapter::class, + 'options' => ['location' => $path] ]; $this->setOption(self::OPTION_ADAPTERS, $adapters); return true; @@ -189,7 +188,7 @@ public function unregisterFileSystem($id) * Get file adapter by file * * @param File $file - * @return AdapterInterface + * @return FilesystemAdapter * @throws \common_exception_NotFound * @throws common_exception_Error */ @@ -229,7 +228,7 @@ protected function getAdapterConfig($id) * @param string $id * @throws \common_exception_NotFound if adapter doesn't exist * @throws \common_exception_Error if adapter is not valid - * @return AdapterInterface + * @return FilesystemAdapter */ protected function getFlysystemAdapter($id) { @@ -246,16 +245,16 @@ protected function getFlysystemAdapter($id) $options = isset($adapterConfig['options']) ? $adapterConfig['options'] : []; if (!class_exists($class)) { - if (class_exists(self::FLYSYSTEM_ADAPTER_NS . $class)) { - $class = self::FLYSYSTEM_ADAPTER_NS . $class; - } elseif (class_exists(self::FLYSYSTEM_ADAPTER_NS . $class . '\\' . $class . 'Adapter')) { - $class = self::FLYSYSTEM_ADAPTER_NS . $class . '\\' . $class . 'Adapter'; + if (class_exists(self::FLYSYSTEM_NS . $class)) { + $class = self::FLYSYSTEM_NS . $class; + } elseif (class_exists(self::FLYSYSTEM_NS . $class . '\\' . $class . 'FilesystemAdapter')) { + $class = self::FLYSYSTEM_NS . $class . '\\' . $class . 'FilesystemAdapter'; } else { throw new common_exception_Error('Unknown Flysystem adapter "' . $class . '"'); } } - if (!is_subclass_of($class, 'League\Flysystem\AdapterInterface')) { + if (!is_subclass_of($class, 'League\Flysystem\FilesystemAdapter')) { throw new common_exception_Error('"' . $class . '" is not a flysystem adapter'); } $adapter = (new \ReflectionClass($class))->newInstanceArgs($options); diff --git a/common/oatbox/filesystem/FilesystemException.php b/common/oatbox/filesystem/FilesystemException.php new file mode 100644 index 000000000..886fb0439 --- /dev/null +++ b/common/oatbox/filesystem/FilesystemException.php @@ -0,0 +1,10 @@ +getFileSystem()->has($this->getFullPath($path)); + return $this->wrapFileSystemOperation(function () use ($location) { + return $this->getFileSystem()->has($this->getFullPath($location)); + }); } - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::read() - */ - public function read($path) - { - return $this->getFileSystem()->read($this->getFullPath($path)); - } - - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::readStream() - */ - public function readStream($path) - { - return $this->getFileSystem()->readStream($this->getFullPath($path)); - } - - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::listContents() - */ - public function listContents($directory = '', $recursive = false) - { - return $this->getFileSystem()->listContents($this->getFullPath($directory), $recursive); - } - - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::getMetadata() - */ - public function getMetadata($path) - { - return $this->getFileSystem()->getMetadata($this->getFullPath($path)); - } - - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::getSize() - */ - public function getSize($path) - { - return $this->getFileSystem()->getSize($this->getFullPath($path)); - } - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::getMimetype() + * @see FilesystemOperator::directoryExists + * @throws FilesystemException */ - public function getMimetype($path) + public function directoryExists(string $location): bool { - return $this->getFileSystem()->getMimetype($this->getFullPath($path)); + return $this->wrapFileSystemOperation(function () use ($location) { + return $this->getFileSystem()->directoryExists($this->getFullPath($location)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::getTimestamp() + * @see FilesystemOperator::read + * @throws FilesystemException */ - public function getTimestamp($path) + public function read(string $location): string { - return $this->getFileSystem()->getTimestamp($this->getFullPath($path)); + return $this->wrapFileSystemOperation(function () use ($location) { + return $this->getFileSystem()->read($this->getFullPath($location)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::getVisibility() + * @see FilesystemOperator::readStream + * @throws FilesystemException */ - public function getVisibility($path) + public function readStream($path) { - return $this->getFileSystem()->getVisibility($this->getFullPath($path)); + return $this->wrapFileSystemOperation(function () use ($path) { + return $this->getFileSystem()->readStream($this->getFullPath($path)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::write() + * @see FilesystemOperator::listContents + * @throws FilesystemException */ - public function write($path, $contents, array $config = []) + public function listContents(string $location = '', bool $deep = self::LIST_SHALLOW): DirectoryListing { - return $this->getFileSystem()->write($this->getFullPath($path), $contents, $config); + return $this->wrapFileSystemOperation(function () use ($location, $deep) { + return $this->getFileSystem()->listContents($this->getFullPath($location), $deep); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::writeStream() + * @see FilesystemOperator::write + * @throws FilesystemException */ - public function writeStream($path, $resource, array $config = []) + public function write(string $location, string $contents, array $config = []): void { - return $this->getFileSystem()->writeStream($this->getFullPath($path), $resource, $config); + $this->wrapFileSystemOperation(function () use ($location, $contents, $config) { + $this->getFileSystem()->write($this->getFullPath($location), $contents, $config); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::update() + * @see FilesystemOperator::writeStream + * @throws FilesystemException */ - public function update($path, $contents, array $config = []) + public function writeStream(string $location, $contents, array $config = []): void { - return $this->getFileSystem()->update($this->getFullPath($path), $contents, $config); + $this->wrapFileSystemOperation(function () use ($location, $contents, $config) { + $this->getFileSystem()->writeStream($this->getFullPath($location), $contents, $config); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::updateStream() + * @see FilesystemOperator::copy + * @throws FilesystemException */ - public function updateStream($path, $resource, array $config = []) + public function copy(string $source, string $destination, array $config = []): void { - return $this->getFileSystem()->updateStream($this->getFullPath($path), $resource, $config); + $this->wrapFileSystemOperation(function () use ($source, $destination, $config) { + $this->getFileSystem()->copy($this->getFullPath($source), $destination, $config); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::rename() + * @see FilesystemOperator::delete + * @throws FilesystemException */ - public function rename($path, $newpath) + public function delete(string $location): void { - return $this->getFileSystem()->rename($this->getFullPath($path), $newpath); + $this->wrapFileSystemOperation(function () use ($location) { + $this->getFileSystem()->delete($this->getFullPath($location)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::copy() + * @see FilesystemOperator::setVisibility + * @throws FilesystemException */ - public function copy($path, $newpath) + public function setVisibility(string $path, string $visibility): void { - return $this->getFileSystem()->copy($this->getFullPath($path), $newpath); + $this->wrapFileSystemOperation(function () use ($path, $visibility) { + $this->getFileSystem()->setVisibility($this->getFullPath($path), $visibility); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::delete() + * @see FilesystemOperator::fileExists + * @throws FilesystemException */ - public function delete($path) + public function fileExists(string $location): bool { - return $this->getFileSystem()->delete($this->getFullPath($path)); + return $this->wrapFileSystemOperation(function () use ($location) { + return $this->getFileSystem()->fileExists($this->getFullPath($location)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::deleteDir() + * @see FilesystemOperator::lastModified + * @throws FilesystemException */ - public function deleteDir($dirname) + public function lastModified(string $path): int { - return $this->getFileSystem()->deleteDir($this->getFullPath($dirname)); + return $this->wrapFileSystemOperation(function () use ($path) { + return $this->getFileSystem()->lastModified($this->getFullPath($path)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::createDir() + * @see FilesystemOperator::fileSize + * @throws FilesystemException */ - public function createDir($dirname, array $config = []) + public function fileSize(string $path): int { - return $this->getFileSystem()->createDir($this->getFullPath($dirname), $config); + return $this->wrapFileSystemOperation(function () use ($path) { + return $this->getFileSystem()->fileSize($this->getFullPath($path)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::setVisibility() + * @see FilesystemOperator::mimeType + * @throws FilesystemException */ - public function setVisibility($path, $visibility) + public function mimeType(string $path): string { - return $this->getFileSystem()->setVisibility($this->getFullPath($path), $visibility); + return $this->wrapFileSystemOperation(function () use ($path) { + return $this->getFileSystem()->mimeType($this->getFullPath($path)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::put() + * @see FilesystemOperator::visibility + * @throws FilesystemException */ - public function put($path, $contents, array $config = []) + public function visibility(string $path): string { - return $this->getFileSystem()->put($this->getFullPath($path), $contents, $config); + return $this->wrapFileSystemOperation(function () use ($path) { + return $this->getFileSystem()->visibility($this->getFullPath($path)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::putStream() + * @see FilesystemOperator::deleteDirectory + * @throws FilesystemException */ - public function putStream($path, $resource, array $config = []) + public function deleteDirectory(string $location): void { - return $this->getFileSystem()->putStream($this->getFullPath($path), $resource, $config); + $this->wrapFileSystemOperation(function () use ($location) { + $this->getFileSystem()->deleteDirectory($this->getFullPath($location)); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::readAndDelete() + * @see FilesystemOperator::createDirectory + * @throws FilesystemException */ - public function readAndDelete($path) + public function createDirectory(string $location, array $config = []): void { - return $this->getFileSystem()->readAndDelete($this->getFullPath($path)); + $this->wrapFileSystemOperation(function () use ($location, $config) { + $this->getFileSystem()->createDirectory($this->getFullPath($location), $config); + }); } - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::get() + * @see FilesystemOperator::move + * @throws FilesystemException */ - public function get($path, Handler $handler = null) + public function move(string $source, string $destination, array $config = []): void { - return $this->getFileSystem()->get($this->getFullPath($path), $handler); + $this->wrapFileSystemOperation(function () use ($source, $destination, $config) { + $this->getFileSystem()->move($this->getFullPath($source), $destination, $config); + }); } - - /** - * (non-PHPdoc) - * @see \League\Flysystem\FilesystemInterface::addPlugin() - */ - public function addPlugin(PluginInterface $plugin) + private function wrapFileSystemOperation(callable $operation) { - return $this->getFileSystem()->addPlugin($plugin); + try { + return $operation(); + } catch (FlyFilesystemException $e) { + throw new FilesystemException($e->getMessage(), $e->getCode(), $e); + } } - /** - * Return the underlying Filesystem - * - * @return Filesystem - */ - abstract protected function getFileSystem(); + abstract protected function getFileSystem(): FilesystemOperator; abstract protected function getFullPath($path); } diff --git a/common/oatbox/filesystem/utils/FlyWrapperTrait.php b/common/oatbox/filesystem/utils/FlyWrapperTrait.php index 5a727b3ac..9762620a3 100644 --- a/common/oatbox/filesystem/utils/FlyWrapperTrait.php +++ b/common/oatbox/filesystem/utils/FlyWrapperTrait.php @@ -2,7 +2,8 @@ namespace oat\oatbox\filesystem\utils; -use League\Flysystem\AdapterInterface; +use League\Flysystem\FileAttributes; +use League\Flysystem\FilesystemAdapter; use League\Flysystem\Config; /** @@ -13,116 +14,107 @@ trait FlyWrapperTrait { /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::write() + * @see FilesystemAdapter::write() + * @inheritDoc */ - public function write($path, $contents, Config $config) + public function write(string $path, string $contents, Config $config): void { - return $this->getAdapter()->write($path, $contents, $config); + $this->getAdapter()->write($path, $contents, $config); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::writeStream() + * @see FilesystemAdapter::writeStream() + * @inheritDoc */ - public function writeStream($path, $resource, Config $config) + public function writeStream(string $path, $contents, Config $config): void { - return $this->getAdapter()->writeStream($path, $resource, $config); + $this->getAdapter()->writeStream($path, $contents, $config); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::update() + * @see FilesystemAdapter::move() + * @inheritDoc */ - public function update($path, $contents, Config $config) + public function move(string $source, string $destination, Config $config): void { - return $this->getAdapter()->update($path, $contents, $config); + $this->getAdapter()->move($source, $destination, $config); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::updateStream() + * @see FilesystemAdapter::copy() + * @inheritDoc */ - public function updateStream($path, $resource, Config $config) + public function copy(string $source, string $destination, Config $config): void { - return $this->getAdapter()->updateStream($path, $resource, $config); + $this->getAdapter()->copy($source, $destination, $config); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::rename() + * @see FilesystemAdapter::delete() + * @inheritDoc */ - public function rename($path, $newpath) + public function delete(string $path): void { - return $this->getAdapter()->rename($path, $newpath); + $this->getAdapter()->delete($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::copy() + * @see FilesystemAdapter::deleteDirectory() + * @inheritDoc */ - public function copy($path, $newpath) + public function deleteDirectory(string $path): void { - $this->getAdapter()->copy($path, $newpath); + $this->getAdapter()->deleteDirectory($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::delete() + * @see FilesystemAdapter::createDirectory() + * @inheritDoc */ - public function delete($path) + public function createDirectory(string $path, Config $config): void { - return $this->getAdapter()->delete($path); + $this->getAdapter()->createDirectory($path, $config); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::deleteDir() + * @see FilesystemAdapter::setVisibility() + * @inheritDoc */ - public function deleteDir($dirname) + public function setVisibility(string $path, string $visibility): void { - return $this->getAdapter()->deleteDir($dirname); + $this->getAdapter()->setVisibility($path, $visibility); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::createDir() + * @see FilesystemAdapter::fileExists() + * @inheritDoc */ - public function createDir($dirname, Config $config) + public function fileExists(string $path): bool { - return $this->getAdapter()->createDir($dirname, $config); + return $this->getAdapter()->fileExists($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\AdapterInterface::setVisibility() + * @see FilesystemAdapter::directoryExists() + * @inheritDoc */ - public function setVisibility($path, $visibility) + public function directoryExists(string $path): bool { - return $this->getAdapter()->setVisibility($path, $visibility); + return $this->getAdapter()->directoryExists($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::has() + * @see FilesystemAdapter::read() + * @inheritDoc */ - public function has($path) - { - return $this->getAdapter()->has($path); - } - - /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::read() - */ - public function read($path) + public function read(string $path): string { return $this->getAdapter()->read($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::readStream() + * @see FilesystemAdapter::readStream() + * @inheritDoc */ public function readStream($path) { @@ -130,63 +122,54 @@ public function readStream($path) } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::listContents() - */ - public function listContents($directory = '', $recursive = false) - { - return $this->getAdapter()->listContents($directory, $recursive); - } - - /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::getMetadata() + * @see FilesystemAdapter::listContents() + * @inheritDoc */ - public function getMetadata($path) + public function listContents(string $path, bool $deep = false): iterable { - return $this->getAdapter()->getMetadata($path); + return $this->getAdapter()->listContents($path, $deep); } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::getSize() + * @see FilesystemAdapter::fileSize() + * @inheritDoc */ - public function getSize($path) + public function fileSize(string $path): FileAttributes { - return $this->getAdapter()->getSize($path); + return $this->getAdapter()->fileSize($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::getMimetype() + * @see FilesystemAdapter::mimeType() + * @inheritDoc */ - public function getMimetype($path) + public function mimeType(string $path): FileAttributes { - return $this->getAdapter()->getMimetype($path); + return $this->getAdapter()->mimeType($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::getTimestamp() + * @see FilesystemAdapter::lastModified() + * @inheritDoc */ - public function getTimestamp($path) + public function lastModified(string $path): FileAttributes { - return $this->getAdapter()->getTimestamp($path); + return $this->getAdapter()->lastModified($path); } /** - * (non-PHPdoc) - * @see \League\Flysystem\ReadInterface::getVisibility() + * @see FilesystemAdapter::visibility() + * @inheritDoc */ - public function getVisibility($path) + public function visibility(string $path): FileAttributes { - return $this->getAdapter()->getVisibility($path); + return $this->getAdapter()->visibility($path); } /** * Return the adapter implementation * - * @return AdapterInterface + * @return FilesystemAdapter */ abstract public function getAdapter(); } diff --git a/common/oatbox/filesystem/wrapper/GoogleStorageWrapper.php b/common/oatbox/filesystem/wrapper/GoogleStorageWrapper.php deleted file mode 100644 index c29847a9f..000000000 --- a/common/oatbox/filesystem/wrapper/GoogleStorageWrapper.php +++ /dev/null @@ -1,66 +0,0 @@ -getOption(self::OPTION_CLIENT_CONFIG)); - } - - /** - * @return AdapterInterface - */ - public function getAdapter() - { - if (is_null($this->adapter)) { - $client = $this->getClient(); - $bucket = $client->bucket($this->getOption('bucket')); - $adapter = new GoogleStorageAdapter($client, $bucket); - $this->adapter = $adapter; - } - return $this->adapter; - } -} diff --git a/common/oatbox/install/Installer.php b/common/oatbox/install/Installer.php index 82767f475..456ae0902 100755 --- a/common/oatbox/install/Installer.php +++ b/common/oatbox/install/Installer.php @@ -21,6 +21,7 @@ namespace oat\oatbox\install; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; use oat\oatbox\service\ConfigurableService; use oat\oatbox\service\exception\InvalidService; use oat\oatbox\service\exception\InvalidServiceManagerException; @@ -29,7 +30,6 @@ use oat\oatbox\filesystem\FileSystemService; use oat\oatbox\service\ServiceNotFoundException; use common_report_Report as Report; -use League\Flysystem\Memory\MemoryAdapter; /** * A service to install oatbox functionality @@ -101,11 +101,11 @@ protected function installFilesystem() 'default' => [ 'class' => 'Local', 'options' => [ - 'root' => $this->getOption('file_path') + 'location' => $this->getOption('file_path') ] ], 'memory' => [ - 'class' => MemoryAdapter::class + 'class' => InMemoryFilesystemAdapter::class ] ] ]); diff --git a/composer.json b/composer.json index 39f175a0f..3b6799f29 100755 --- a/composer.json +++ b/composer.json @@ -59,8 +59,9 @@ "doctrine/dbal": "^2.12", "doctrine/annotations": "^1.13", "laminas/laminas-servicemanager": "~2.5.0", - "league/flysystem": "~1.0", - "league/flysystem-memory": "~1.0", + "league/flysystem": "^3.0", + "league/flysystem-memory": "^3.0", + "league/flysystem-google-cloud-storage": "^3.0", "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "oat-sa/lib-generis-search": "^2.3.0", "monolog/monolog": "^1.23.0", @@ -86,7 +87,7 @@ "php-mock/php-mock": "^2.0" }, "suggest": { - "superbalist/flysystem-google-storage": "Supports google flystore" + "league/flysystem-google-cloud-storage": "Supports google flystore" }, "autoload": { "psr-4": { @@ -107,5 +108,11 @@ "psr-4": { "oat\\generis\\test\\": "generis/test/" } + }, + "config": { + "allow-plugins": { + "oat-sa/oatbox-extension-installer": true, + "php-http/discovery": true + } } } diff --git a/scripts/update/Updater.php b/scripts/update/Updater.php index 772af36d2..c8820c800 100644 --- a/scripts/update/Updater.php +++ b/scripts/update/Updater.php @@ -28,8 +28,8 @@ use common_ext_ExtensionUpdater; use core_kernel_impl_ApiModelOO; use core_kernel_persistence_smoothsql_SmoothModel; -use League\Flysystem\Adapter\Local; -use League\Flysystem\Memory\MemoryAdapter; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; +use League\Flysystem\Local\LocalFilesystemAdapter; use oat\generis\model\data\ModelManager; use oat\generis\model\data\Ontology; use oat\generis\model\fileReference\FileReferenceSerializer; @@ -464,8 +464,8 @@ public function update($initialVersion) if (get_class($fs) == FileSystemService::class) { // override default behavior to ensure an adapter and not a directory is created $adapters['default'] = [ - 'class' => Local::class, - 'options' => ['root' => $fs->getOption(FileSystemService::OPTION_FILE_PATH)] + 'class' => LocalFilesystemAdapter::class, + 'options' => ['location' => $fs->getOption(FileSystemService::OPTION_FILE_PATH)] ]; $fs->setOption(FileSystemService::OPTION_ADAPTERS, $adapters); } else { @@ -526,7 +526,7 @@ public function update($initialVersion) /** @var FileSystemService $fs */ $fs = $this->getServiceManager()->get(FileSystemService::SERVICE_ID); $adapters = $fs->getOption(FileSystemService::OPTION_ADAPTERS); - $adapters['memory'] = [ 'class' => MemoryAdapter::class, ]; + $adapters['memory'] = [ 'class' => InMemoryFilesystemAdapter::class, ]; $fs->setOption(FileSystemService::OPTION_ADAPTERS, $adapters); $this->getServiceManager()->register(FileSystemService::SERVICE_ID, $fs); diff --git a/test/FileSystemMockTrait.php b/test/FileSystemMockTrait.php index b5c95c58b..53d7814da 100644 --- a/test/FileSystemMockTrait.php +++ b/test/FileSystemMockTrait.php @@ -21,7 +21,7 @@ namespace oat\generis\test; -use League\Flysystem\Memory\MemoryAdapter; +use League\Flysystem\InMemory\InMemoryFilesystemAdapter; use oat\oatbox\filesystem\FileSystemService; trait FileSystemMockTrait @@ -30,7 +30,7 @@ protected function getFileSystemMock($dirs = []): FileSystemService { $adapterparam = [ 'testfs' => [ - 'class' => MemoryAdapter::class + 'class' => InMemoryFilesystemAdapter::class ] ]; $dirparam = []; diff --git a/test/integration/common/filesystem/DirectoryFilesystemTest.php b/test/integration/common/filesystem/DirectoryFilesystemTest.php index 5e04b8ddd..f79d7aff0 100644 --- a/test/integration/common/filesystem/DirectoryFilesystemTest.php +++ b/test/integration/common/filesystem/DirectoryFilesystemTest.php @@ -101,7 +101,6 @@ public function testGetFullPathFile() /** * @return bool - * @throws \League\Flysystem\FileExistsException * @throws \common_Exception */ private function generateFile($path)