tao-test/app/generis/common/oatbox/filesystem/FileSystemService.php

268 lines
8.1 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2015 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*
*/
namespace oat\oatbox\filesystem;
use oat\oatbox\service\ConfigurableService;
use League\Flysystem\AdapterInterface;
use common_exception_Error;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use \League\Flysystem\Filesystem as FlyFileSystem;
use League\Flysystem\FilesystemInterface;
/**
* A service to reference and retrieve filesystems
*/
class FileSystemService extends ConfigurableService
{
const SERVICE_ID = 'generis/filesystem';
const OPTION_FILE_PATH = 'filesPath';
const OPTION_ADAPTERS = 'adapters';
const OPTION_DIRECTORIES = 'dirs';
const FLYSYSTEM_ADAPTER_NS = '\\League\\Flysystem\\Adapter\\';
const FLYSYSTEM_LOCAL_ADAPTER = 'Local';
private $filesystems = [];
/**
*
* @param $id
* @return \oat\oatbox\filesystem\Directory
*/
public function getDirectory($id)
{
return $this->propagate(new Directory($id, ''));
}
/**
* Returns the directory config
* @return array
*/
protected function getDirectories()
{
return $this->hasOption(self::OPTION_DIRECTORIES)
? $this->getOption(self::OPTION_DIRECTORIES)
: [];
}
/**
* Add a directory reference
* @param string $id
* @param string $adapterId
*/
protected function addDir($id, $adapterId)
{
$dirs = $this->getDirectories();
$dirs[$id] = $adapterId;
$this->setOption(self::OPTION_DIRECTORIES, $dirs);
}
/**
* Returns whenever or not a FS exists
* @param string $id
* @return boolean
*/
public function hasDirectory($id)
{
$adapterConfig = $this->getOption(self::OPTION_ADAPTERS);
$dirConfig = $this->getOption(self::OPTION_DIRECTORIES);
return isset($adapterConfig[$id]) || isset($dirConfig[$id]);
}
/**
* Get FileSystem by ID
*
* Retrieve an existing FileSystem by ID.
*
* @param string $id
* @return FilesystemInterface
* @throws \common_exception_Error
* @throws \common_exception_NotFound
*/
public function getFileSystem($id)
{
if (!isset($this->filesystems[$id])) {
$config = $this->getAdapterConfig($id);
$adapter = $this->getFlysystemAdapter($config['adapter']);
$this->filesystems[$id] = new FileSystem($id, new FlyFileSystem($adapter), $config['path']);
}
return $this->filesystems[$id];
}
/**
* Creates a filesystem using the default implementation (Local)
* Override this function to create your files elsewhere by default
*
* @param string $id
* @param string $subPath
* @return FilesystemInterface
*/
public function createFileSystem($id, $subPath = null)
{
$this->addDir($id, 'default');
return $this->getFileSystem($id);
}
/**
* Create a new local file system
*
* @deprecated never rely on a directory being local, use addDir instead
* @param string $id
* @return FilesystemInterface
*/
public function createLocalFileSystem($id)
{
$path = $this->getOption(self::OPTION_FILE_PATH) . \helpers_File::sanitizeInjectively($id);
$this->registerLocalFileSystem($id, $path);
return $this->getFileSystem($id);
}
/**
* Registers a local file system, used for transition
*
* @deprecated never rely on a directory being local, use addDir instead
* @param string $id
* @param string $path
* @return boolean
*/
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]
];
$this->setOption(self::OPTION_ADAPTERS, $adapters);
return true;
}
/**
* Remove a filesystem adapter
*
* @param string $id
* @return boolean
*/
public function unregisterFileSystem($id)
{
if (isset($this->filesystems[$id])) {
unset($this->filesystems[$id]);
}
$adapters = $this->getOption(self::OPTION_ADAPTERS);
if (isset($adapters[$id])) {
unset($adapters[$id]);
$this->setOption(self::OPTION_ADAPTERS, $adapters);
return true;
} elseif ($this->hasDirectory($id)) {
$directories = $this->getOption(self::OPTION_DIRECTORIES);
unset($directories[$id]);
$this->setOption(self::OPTION_DIRECTORIES, $directories);
return true;
} else {
return false;
}
}
/**
* Get file adapter by file
*
* @param File $file
* @return AdapterInterface
* @throws \common_exception_NotFound
* @throws common_exception_Error
*/
public function getFileAdapterByFile(File $file)
{
$config = $this->getAdapterConfig($file->getFileSystemId());
return $this->getFlysystemAdapter($config['adapter']);
}
/**
* Returns the configuration for an adapter
* @param string $id
* @return string[]
*/
protected function getAdapterConfig($id)
{
$dirs = $this->getDirectories();
if (!isset($dirs[$id])) {
$config = [
'adapter' => $id,
'path' => ''
];
} elseif (is_array($dirs[$id])) {
$config = $dirs[$id];
} else {
$config = [
'adapter' => $dirs[$id],
'path' => $id
];
}
return $config;
}
/**
* inspired by burzum/storage-factory
*
* @param string $id
* @throws \common_exception_NotFound if adapter doesn't exist
* @throws \common_exception_Error if adapter is not valid
* @return AdapterInterface
*/
protected function getFlysystemAdapter($id)
{
$fsConfig = $this->getOption(self::OPTION_ADAPTERS);
if (!isset($fsConfig[$id])) {
throw new \common_exception_NotFound('Undefined filesystem "' . $id . '"');
}
$adapterConfig = $fsConfig[$id];
// alias?
while (is_string($adapterConfig)) {
$adapterConfig = $fsConfig[$adapterConfig];
}
$class = $adapterConfig['class'];
$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';
} else {
throw new common_exception_Error('Unknown Flysystem adapter "' . $class . '"');
}
}
if (!is_subclass_of($class, 'League\Flysystem\AdapterInterface')) {
throw new common_exception_Error('"' . $class . '" is not a flysystem adapter');
}
$adapter = (new \ReflectionClass($class))->newInstanceArgs($options);
if ($adapter instanceof ServiceLocatorAwareInterface) {
$adapter->setServiceLocator($this->getServiceLocator());
}
return $adapter;
}
}