use Asika\SimpleConsole\CommandArgsException;
use Friendica\Core\StorageManager;
+use Friendica\Model\Storage\ReferenceStorageException;
use Friendica\Model\Storage\StorageException;
/**
protected function doSet()
{
- if (count($this->args) !== 2) {
+ if (count($this->args) !== 2 || empty($this->args[1])) {
throw new CommandArgsException('Invalid arguments');
}
- $name = $this->args[1];
- $class = $this->storageManager->getWritableStorageByName($name);
+ $name = $this->args[1];
+ try {
+ $class = $this->storageManager->getWritableStorageByName($name);
- if (is_null($class)) {
+ if (!$this->storageManager->setBackend($class)) {
+ $this->out($class . ' is not a valid backend storage class.');
+ return -1;
+ }
+ } catch (ReferenceStorageException $exception) {
$this->out($name . ' is not a registered backend.');
return -1;
}
- if (!$this->storageManager->setBackend($class)) {
- $this->out($class . ' is not a valid backend storage class.');
- return -1;
- }
-
return 0;
}
use Friendica\Network\HTTPException\InternalServerErrorException;
use Psr\Log\LoggerInterface;
-
/**
* Manage storage backends
*
Storage\Database::NAME => Storage\Database::class,
];
- private $backends = [];
+ private $backends;
/**
* @var Storage\IStorage[] A local cache for storage instances
/** @var L10n */
private $l10n;
- /** @var Storage\IStorage */
+ /** @var Storage\IWritableStorage */
private $currentBackend;
/**
* @param IConfig $config
* @param LoggerInterface $logger
* @param L10n $l10n
+ *
+ * @throws Storage\InvalidClassStorageException in case the active backend class is invalid
+ * @throws Storage\StorageException in case of unexpected errors during the active backend class loading
*/
public function __construct(Database $dba, IConfig $config, LoggerInterface $logger, L10n $l10n)
{
- $this->dba = $dba;
- $this->config = $config;
- $this->logger = $logger;
- $this->l10n = $l10n;
+ $this->dba = $dba;
+ $this->config = $config;
+ $this->logger = $logger;
+ $this->l10n = $l10n;
$this->backends = $config->get('storage', 'backends', self::DEFAULT_BACKENDS);
- $currentName = $this->config->get('storage', 'name', '');
+ $currentName = $this->config->get('storage', 'name');
// you can only use user backends as a "default" backend, so the second parameter is true
$this->currentBackend = $this->getWritableStorageByName($currentName);
/**
* Return current storage backend class
*
- * @return Storage\IWritableStorage|null
+ * @return Storage\IWritableStorage
*/
public function getBackend()
{
*
* @return Storage\IWritableStorage
*
- * @throws Storage\ReferenceStorageException in case there's no backend class for the name
+ * @throws Storage\InvalidClassStorageException in case there's no backend class for the name
* @throws Storage\StorageException in case of an unexpected failure during the hook call
*/
- public function getWritableStorageByName(string $name = null)
+ public function getWritableStorageByName(string $name): Storage\IWritableStorage
{
- // @todo 2020.09 Remove this call after 2 releases
- $name = $this->checkLegacyBackend($name);
-
- // If there's no cached instance create a new instance
- if (!isset($this->backendInstances[$name])) {
- // If the current name isn't a valid backend (or the SystemResource instance) create it
- if ($this->isValidBackend($name, true)) {
- switch ($name) {
- // Try the filesystem backend
- case Storage\Filesystem::getName():
- $this->backendInstances[$name] = new Storage\Filesystem($this->config, $this->l10n);
- break;
- // try the database backend
- case Storage\Database::getName():
- $this->backendInstances[$name] = new Storage\Database($this->dba);
- break;
- default:
- $data = [
- 'name' => $name,
- 'storage' => null,
- ];
- try {
- Hook::callAll('storage_instance', $data);
- if (($data['storage'] ?? null) instanceof Storage\IWritableStorage) {
- $this->backendInstances[$data['name'] ?? $name] = $data['storage'];
- } else {
- throw new Storage\ReferenceStorageException(sprintf('Backend %s was not found', $name));
- }
- } catch (InternalServerErrorException $exception) {
- throw new Storage\StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception);
- }
- break;
- }
- } else {
- throw new Storage\ReferenceStorageException(sprintf('Backend %s is not valid', $name));
- }
+ $storage = $this->getByName($name, $this->backends);
+ if ($storage instanceof Storage\IWritableStorage) {
+ return $storage;
+ } else {
+ throw new Storage\InvalidClassStorageException(sprintf('Backend %s is not writable', $name));
}
-
- return $this->backendInstances[$name];
}
/**
* Return storage backend class by registered name
*
- * @param string $name Backend name
+ * @param string $name Backend name
+ * @param array|null $validBackends possible, manual override of the valid backends
*
* @return Storage\IStorage
*
- * @throws Storage\ReferenceStorageException in case there's no backend class for the name
+ * @throws Storage\InvalidClassStorageException in case there's no backend class for the name
* @throws Storage\StorageException in case of an unexpected failure during the hook call
*/
- public function getByName(string $name)
+ public function getByName(string $name, array $validBackends = null): Storage\IStorage
{
- // @todo 2020.09 Remove this call after 2 releases
- $name = $this->checkLegacyBackend($name);
-
// If there's no cached instance create a new instance
if (!isset($this->backendInstances[$name])) {
// If the current name isn't a valid backend (or the SystemResource instance) create it
- if ($this->isValidBackend($name, false)) {
+ if ($this->isValidBackend($name, $validBackends)) {
switch ($name) {
// Try the filesystem backend
case Storage\Filesystem::getName():
if (($data['storage'] ?? null) instanceof Storage\IStorage) {
$this->backendInstances[$data['name'] ?? $name] = $data['storage'];
} else {
- throw new Storage\ReferenceStorageException(sprintf('Backend %s was not found', $name));
+ throw new Storage\InvalidClassStorageException(sprintf('Backend %s was not found', $name));
}
} catch (InternalServerErrorException $exception) {
throw new Storage\StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception);
break;
}
} else {
- throw new Storage\ReferenceStorageException(sprintf('Backend %s is not valid', $name));
+ throw new Storage\InvalidClassStorageException(sprintf('Backend %s is not valid', $name));
}
}
/**
* Checks, if the storage is a valid backend
*
- * @param string|null $name The name or class of the backend
- * @param boolean $onlyUserBackend True, if just user backend should get returned (e.g. not SystemResource)
+ * @param string|null $name The name or class of the backend
+ * @param array|null $validBackends Possible, valid backends to check
*
* @return boolean True, if the backend is a valid backend
*/
- public function isValidBackend(string $name = null, bool $onlyUserBackend = false)
- {
- return array_key_exists($name, $this->backends) ||
- (!$onlyUserBackend && in_array($name, [Storage\SystemResource::getName(), Storage\ExternalResource::getName()]));
- }
-
- /**
- * Check for legacy backend storage class names (= full model class name)
- *
- * @todo 2020.09 Remove this function after 2 releases, because there shouldn't be any legacy backend classes left
- *
- * @param string|null $name a potential, legacy storage name ("Friendica\Model\Storage\...")
- *
- * @return string|null The current storage name
- */
- private function checkLegacyBackend(string $name = null)
+ public function isValidBackend(string $name = null, array $validBackends = null): bool
{
- if (stristr($name, 'Friendica\Model\Storage\\')) {
- $this->logger->notice('Using deprecated storage class value', ['name' => $name]);
- return substr($name, 24);
- }
-
- return $name;
+ $validBackends = $validBackends ?? array_merge($this->backends,
+ [
+ Storage\SystemResource::getName() => '',
+ Storage\ExternalResource::getName() => ''
+ ]);
+ return array_key_exists($name, $validBackends);
}
/**
*
* @return boolean True, if the set was successful
*/
- public function setBackend(Storage\IWritableStorage $storage)
+ public function setBackend(Storage\IWritableStorage $storage): bool
{
if ($this->config->set('storage', 'name', $storage::getName())) {
$this->currentBackend = $storage;
*
* @return array
*/
- public function listBackends()
+ public function listBackends(): array
{
return $this->backends;
}
*
* @return boolean True, if the registration was successful
*/
- public function register(string $class)
+ public function register(string $class): bool
{
if (is_subclass_of($class, Storage\IStorage::class)) {
/** @var Storage\IStorage $class */
*
* @return boolean True, if unregistering was successful
*/
- public function unregister(string $class)
+ public function unregister(string $class): bool
{
if (is_subclass_of($class, Storage\IStorage::class)) {
/** @var Storage\IStorage $class */
* @throws Storage\StorageException
* @throws Exception
*/
- public function move(Storage\IWritableStorage $destination, array $tables = self::TABLES, int $limit = 5000)
+ public function move(Storage\IWritableStorage $destination, array $tables = self::TABLES, int $limit = 5000): int
{
- if (!$this->isValidBackend($destination, true)) {
+ if (!$this->isValidBackend($destination, $this->backends)) {
throw new Storage\StorageException(sprintf("Can't move to storage backend '%s'", $destination::getName()));
}
while ($resource = $this->dba->fetch($resources)) {
$id = $resource['id'];
- $data = $resource['data'];
- $source = $this->getWritableStorageByName($resource['backend-class']);
$sourceRef = $resource['backend-ref'];
+ $source = null;
- if (!empty($source)) {
+ try {
+ $source = $this->getWritableStorageByName($resource['backend-class'] ?? '');
$this->logger->info('Get data from old backend.', ['oldBackend' => $source, 'oldReference' => $sourceRef]);
$data = $source->get($sourceRef);
+ } catch (Storage\InvalidClassStorageException $exception) {
+ $this->logger->info('Get data from DB resource field.', ['oldReference' => $sourceRef]);
+ $data = $resource['data'];
+ } catch (Storage\ReferenceStorageException $exception) {
+ $this->logger->info('Invalid source reference.', ['oldBackend' => $source, 'oldReference' => $sourceRef]);
+ continue;
}
$this->logger->info('Save data to new backend.', ['newBackend' => $destination::getName()]);
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
+use Friendica\Model\Storage\InvalidClassStorageException;
use Friendica\Model\Storage\ReferenceStorageException;
use Friendica\Object\Image;
use Friendica\Util\DateTimeFormat;
return $item['data'];
}
- $backendClass = DI::storageManager()->getByName($item['backend-class'] ?? '');
- if (empty($backendClass)) {
+ try {
+ $backendClass = DI::storageManager()->getByName($item['backend-class'] ?? '');
+ $backendRef = $item['backend-ref'];
+ return $backendClass->get($backendRef);
+ } catch (InvalidClassStorageException $storageException) {
// legacy data storage in 'data' column
$i = self::selectFirst(['data'], ['id' => $item['id']]);
if ($i === false) {
return null;
}
return $i['data'];
- } else {
- $backendRef = $item['backend-ref'];
- try {
- return $backendClass->get($backendRef);
- } catch (ReferenceStorageException $referenceStorageException) {
- DI::logger()->debug('No data found for item', ['item' => $item, 'exception' => $referenceStorageException]);
- return '';
- }
+ } catch (ReferenceStorageException $referenceStorageException) {
+ DI::logger()->debug('No data found for item', ['item' => $item, 'exception' => $referenceStorageException]);
+ return '';
}
}
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
foreach($items as $item) {
- $backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
- if (!empty($backend_class)) {
+ try {
+ $backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
$fields['backend-ref'] = $backend_class->put($img->asString(), $item['backend-ref'] ?? '');
- } else {
- $fields['data'] = $img->asString();
+ } catch (InvalidClassStorageException $storageException) {
+ DI::logger()->debug('Storage class not found.', ['conditions' => $conditions, 'exception' => $storageException]);
+ } catch (ReferenceStorageException $referenceStorageException) {
+ DI::logger()->debug('Item doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]);
}
}
}
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
foreach($items as $item) {
- $backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
- if (!empty($backend_class)) {
- try {
- $backend_class->delete($item['backend-ref'] ?? '');
- } catch (ReferenceStorageException $referenceStorageException) {
- DI::logger()->debug('Item doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]);
- }
+ try {
+ $backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
+ $backend_class->delete($item['backend-ref'] ?? '');
+ } catch (InvalidClassStorageException $storageException) {
+ DI::logger()->debug('Storage class not found.', ['conditions' => $conditions, 'exception' => $storageException]);
+ } catch (ReferenceStorageException $referenceStorageException) {
+ DI::logger()->debug('Item doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]);
}
}
use Friendica\Database\DBStructure;
use Friendica\DI;
use Friendica\Model\Storage\ExternalResource;
+use Friendica\Model\Storage\InvalidClassStorageException;
use Friendica\Model\Storage\ReferenceStorageException;
use Friendica\Model\Storage\StorageException;
use Friendica\Model\Storage\SystemResource;
* @param array $photo Photo data. Needs at least 'id', 'type', 'backend-class', 'backend-ref'
*
* @return \Friendica\Object\Image
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
- * @throws \ImagickException
- * @throws StorageException
*/
public static function getImageDataForPhoto(array $photo)
{
return $photo['data'];
}
- $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? '');
- if (empty($backendClass)) {
- // legacy data storage in "data" column
- $i = self::selectFirst(['data'], ['id' => $photo['id']]);
- if ($i === false) {
- return null;
+ try {
+ $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? '');
+ $image = $backendClass->get($photo['backend-ref'] ?? '');
+
+ if ($image instanceof Image) {
+ return $image;
+ } else {
+ DI::logger()->info('Stored data is not an image', ['photo' => $photo]);
}
- $data = $i['data'];
- } else {
- $backendRef = $photo['backend-ref'] ?? '';
+ } catch (InvalidClassStorageException $storageException) {
try {
- $data = $backendClass->get($backendRef);
- } catch (ReferenceStorageException $referenceStorageException) {
- DI::logger()->debug('No data found for photo', ['photo' => $photo, 'exception' => $referenceStorageException]);
- return null;
+ // legacy data storage in "data" column
+ $i = self::selectFirst(['data'], ['id' => $photo['id']]);
+ if ($i !== false) {
+ return $i['data'];
+ } else {
+ DI::logger()->info('Stored legacy data is empty', ['photo' => $photo]);
+ }
+ } catch (\Exception $exception) {
+ DI::logger()->info('Unexpected database exception', ['photo' => $photo, 'exception' => $exception]);
}
+ } catch (ReferenceStorageException $referenceStorageException) {
+ DI::logger()->debug('Invalid reference for photo', ['photo' => $photo, 'exception' => $referenceStorageException]);
+ } catch (StorageException $storageException) {
+ DI::logger()->info('Unexpected storage exception', ['photo' => $photo, 'exception' => $storageException]);
+ } catch (\ImagickException $imagickException) {
+ DI::logger()->info('Unexpected imagick exception', ['photo' => $photo, 'exception' => $imagickException]);
}
- return $data;
+
+ return null;
}
/**
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
- public static function getImageForPhoto(array $photo)
+ public static function getImageForPhoto(array $photo): Image
{
- $data = self::getImageDataForPhoto($photo);
- if (empty($data)) {
- return null;
- }
-
- return new Image($data, $photo['type']);
+ return new Image(self::getImageDataForPhoto($photo), $photo['type']);
}
/**
// Get defined storage backend.
// if no storage backend, we use old "data" column in photo table.
// if is an existing photo, reuse same backend
- $data = "";
+ $data = "";
$backend_ref = "";
+ $storage = "";
- if (DBA::isResult($existing_photo)) {
- $backend_ref = (string)$existing_photo["backend-ref"];
- $storage = DI::storageManager()->getWritableStorageByName($existing_photo["backend-class"] ?? '');
- } else {
- $storage = DI::storage();
- }
-
- if (empty($storage)) {
- $data = $Image->asString();
- } else {
+ try {
+ if (DBA::isResult($existing_photo)) {
+ $backend_ref = (string)$existing_photo["backend-ref"];
+ $storage = DI::storageManager()->getWritableStorageByName($existing_photo["backend-class"] ?? '');
+ } else {
+ $storage = DI::storage();
+ }
$backend_ref = $storage->put($Image->asString(), $backend_ref);
+ } catch (InvalidClassStorageException $storageException) {
+ $data = $Image->asString();
}
$fields = [
$photos = DBA::select('photo', ['id', 'backend-class', 'backend-ref'], $conditions);
while ($photo = DBA::fetch($photos)) {
- $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
- if (!empty($backend_class)) {
- try {
- $backend_class->delete($item['backend-ref'] ?? '');
- // Delete the photos after they had been deleted successfully
- DBA::delete("photo", ['id' => $photo['id']]);
- } catch (ReferenceStorageException $referenceStorageException) {
- DI::logger()->debug('phot doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]);
- }
+ try {
+ $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
+ $backend_class->delete($item['backend-ref'] ?? '');
+ // Delete the photos after they had been deleted successfully
+ DBA::delete("photo", ['id' => $photo['id']]);
+ } catch (InvalidClassStorageException $storageException) {
+ DI::logger()->debug('Storage class not found.', ['conditions' => $conditions, 'exception' => $storageException]);
+ } catch (ReferenceStorageException $referenceStorageException) {
+ DI::logger()->debug('Photo doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]);
}
}
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
foreach($photos as $photo) {
- $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
- if (!empty($backend_class)) {
+ try {
+ $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
$fields["backend-ref"] = $backend_class->put($img->asString(), $photo['backend-ref']);
- } else {
+ } catch (InvalidClassStorageException $storageException) {
$fields["data"] = $img->asString();
}
}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Model\Storage;
+
+/**
+ * Storage Exception in case of invalid storage class
+ */
+class InvalidClassStorageException extends StorageException
+{
+}
use Friendica\Core\Renderer;
use Friendica\DI;
+use Friendica\Model\Storage\InvalidClassStorageException;
use Friendica\Model\Storage\IWritableStorage;
use Friendica\Module\BaseAdmin;
use Friendica\Util\Strings;
$storagebackend = Strings::escapeTags(trim($parameters['name'] ?? ''));
- /** @var IWritableStorage $newstorage */
- $newstorage = DI::storageManager()->getWritableStorageByName($storagebackend);
+ try {
+ /** @var IWritableStorage $newstorage */
+ $newstorage = DI::storageManager()->getWritableStorageByName($storagebackend);
+ } catch (InvalidClassStorageException $storageException) {
+ notice(DI::l10n()->t('Storage backend, %s is invalid.', $storagebackend));
+ DI::baseUrl()->redirect('admin/storage');
+ }
// save storage backend form
$storage_opts = $newstorage->getOptions();
$storage_form_errors = $newstorage->saveOptions($storage_opts_data);
if (count($storage_form_errors)) {
foreach ($storage_form_errors as $name => $err) {
- notice('Storage backend, ' . $storage_opts[$name][1] . ': ' . $err);
+ notice(DI::l10n()->t('Storage backend %s error: %s', $storage_opts[$name][1], $err));
}
DI::baseUrl()->redirect('admin/storage');
}
if (!empty($_POST['submit_save_set'])) {
- /** @var IWritableStorage $newstorage */
- $newstorage = DI::storageManager()->getWritableStorageByName($storagebackend);
+ try {
+ /** @var IWritableStorage $newstorage */
+ $newstorage = DI::storageManager()->getWritableStorageByName($storagebackend);
- if (!DI::storageManager()->setBackend($newstorage)) {
+ if (!DI::storageManager()->setBackend($newstorage)) {
+ notice(DI::l10n()->t('Invalid storage backend setting value.'));
+ }
+ } catch (InvalidClassStorageException $storageException) {
notice(DI::l10n()->t('Invalid storage backend setting value.'));
}
}
use Friendica\Model\Post;
use Friendica\Model\Profile;
use Friendica\Model\Storage\ExternalResource;
+use Friendica\Model\Storage\ReferenceStorageException;
+use Friendica\Model\Storage\StorageException;
use Friendica\Model\Storage\SystemResource;
+use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Util\Proxy;
use Friendica\Object\Image;
use Friendica\Util\Images;
$cacheable = ($photo["allow_cid"] . $photo["allow_gid"] . $photo["deny_cid"] . $photo["deny_gid"] === "") && (isset($photo["cacheable"]) ? $photo["cacheable"] : true);
$stamp = microtime(true);
+
$imgdata = MPhoto::getImageDataForPhoto($photo);
+ if (empty($imgdata)) {
+ throw new NotFoundException();
+ }
// The mimetype for an external or system resource can only be known reliably after it had been fetched
if (in_array($photo['backend-class'], [ExternalResource::NAME, SystemResource::NAME])) {
$base_image = Photo::selectFirst([], ['resource-id' => $resource_id, 'uid' => local_user(), 'scale' => $scale]);
if (DBA::isResult($base_image)) {
$Image = Photo::getImageForPhoto($base_image);
+ if (empty($Image)) {
+ throw new HTTPException\InternalServerErrorException();
+ }
+
if ($Image->isValid()) {
// If setting for the default profile, unset the profile photo flag from any other photos I own
DBA::update('photo', ['profile' => 0], ['uid' => local_user()]);
}
$Image = Photo::getImageForPhoto($photos[0]);
+ if (empty($Image)) {
+ throw new HTTPException\InternalServerErrorException();
+ }
$imagecrop = [
'resource-id' => $resource_id,
use Friendica\Model\Config\Config;
use Friendica\Model\Storage;
use Friendica\Core\Session;
-use Friendica\Model\Storage\StorageException;
use Friendica\Network\HTTPRequest;
use Friendica\Test\DatabaseTest;
use Friendica\Test\Util\Database\StaticDatabase;
class StorageManagerTest extends DatabaseTest
{
+ use VFSTrait;
/** @var Database */
private $dba;
/** @var IConfig */
/** @var HTTPRequest */
private $httpRequest;
- use VFSTrait;
-
protected function setUp(): void
{
parent::setUp();
$configModel = new Config($this->dba);
$this->config = new PreloadConfig($configCache, $configModel);
+ $this->config->set('storage', 'name', 'Database');
$this->l10n = \Mockery::mock(L10n::class);
public function dataStorages()
{
return [
- 'empty' => [
- 'name' => '',
- 'assert' => null,
- 'assertName' => '',
- 'userBackend' => false,
+ 'empty' => [
+ 'name' => '',
+ 'valid' => false,
+ 'interface' => Storage\IStorage::class,
+ 'assert' => null,
+ 'assertName' => '',
],
- 'database' => [
- 'name' => Storage\Database::NAME,
- 'assert' => Storage\Database::class,
- 'assertName' => Storage\Database::NAME,
- 'userBackend' => true,
+ 'database' => [
+ 'name' => Storage\Database::NAME,
+ 'valid' => true,
+ 'interface' => Storage\IWritableStorage::class,
+ 'assert' => Storage\Database::class,
+ 'assertName' => Storage\Database::NAME,
],
- 'filesystem' => [
- 'name' => Storage\Filesystem::NAME,
- 'assert' => Storage\Filesystem::class,
- 'assertName' => Storage\Filesystem::NAME,
- 'userBackend' => true,
+ 'filesystem' => [
+ 'name' => Storage\Filesystem::NAME,
+ 'valid' => true,
+ 'interface' => Storage\IWritableStorage::class,
+ 'assert' => Storage\Filesystem::class,
+ 'assertName' => Storage\Filesystem::NAME,
],
'systemresource' => [
- 'name' => Storage\SystemResource::NAME,
- 'assert' => Storage\SystemResource::class,
- 'assertName' => Storage\SystemResource::NAME,
- // false here, because SystemResource isn't meant to be a user backend,
- // it's for system resources only
- 'userBackend' => false,
+ 'name' => Storage\SystemResource::NAME,
+ 'valid' => true,
+ 'interface' => Storage\IStorage::class,
+ 'assert' => Storage\SystemResource::class,
+ 'assertName' => Storage\SystemResource::NAME,
],
- 'invalid' => [
+ 'invalid' => [
'name' => 'invalid',
+ 'valid' => false,
+ 'interface' => null,
'assert' => null,
'assertName' => '',
'userBackend' => false,
];
}
- /**
- * Data array for legacy backends
- *
- * @todo 2020.09 After 2 releases, remove the legacy functionality and these data array with it
- *
- * @return array
- */
- public function dataLegacyBackends()
- {
- return [
- 'legacyDatabase' => [
- 'name' => 'Friendica\Model\Storage\Database',
- 'assert' => Storage\Database::class,
- 'assertName' => Storage\Database::NAME,
- 'userBackend' => true,
- ],
- 'legacyFilesystem' => [
- 'name' => 'Friendica\Model\Storage\Filesystem',
- 'assert' => Storage\Filesystem::class,
- 'assertName' => Storage\Filesystem::NAME,
- 'userBackend' => true,
- ],
- 'legacySystemResource' => [
- 'name' => 'Friendica\Model\Storage\SystemResource',
- 'assert' => Storage\SystemResource::class,
- 'assertName' => Storage\SystemResource::NAME,
- 'userBackend' => false,
- ],
- ];
- }
-
/**
* Test the getByName() method
*
* @dataProvider dataStorages
- * @dataProvider dataLegacyBackends
*/
- public function testGetByName($name, $assert, $assertName, $userBackend)
+ public function testGetByName($name, $valid, $interface, $assert, $assertName)
{
- $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
+ if (!$valid) {
+ $this->expectException(Storage\InvalidClassStorageException::class);
+ }
+
+ if ($interface === Storage\IWritableStorage::class) {
+ $this->config->set('storage', 'name', $name);
+ }
- if ($userBackend) {
+ $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
+
+ if ($interface === Storage\IWritableStorage::class) {
$storage = $storageManager->getWritableStorageByName($name);
} else {
$storage = $storageManager->getByName($name);
}
- if (!empty($assert)) {
- self::assertInstanceOf(Storage\IStorage::class, $storage);
- self::assertInstanceOf($assert, $storage);
- } else {
- self::assertNull($storage);
- }
+ self::assertInstanceOf($interface, $storage);
+ self::assertInstanceOf($assert, $storage);
self::assertEquals($assertName, $storage);
}
*
* @dataProvider dataStorages
*/
- public function testIsValidBackend($name, $assert, $assertName, $userBackend)
+ public function testIsValidBackend($name, $valid, $interface, $assert, $assertName)
{
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
// true in every of the backends
self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
- // if userBackend is set to true, filter out e.g. SystemRessource
- self::assertEquals($userBackend, $storageManager->isValidBackend($name, true));
+ // if it's a IWritableStorage, the valid backend should return true, otherwise false
+ self::assertEquals($interface === Storage\IWritableStorage::class, $storageManager->isValidBackend($name, StorageManager::DEFAULT_BACKENDS));
}
/**
*
* @dataProvider dataStorages
*/
- public function testGetBackend($name, $assert, $assertName, $userBackend)
+ public function testGetBackend($name, $valid, $interface, $assert, $assertName)
{
- $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
+ if ($interface !== Storage\IWritableStorage::class) {
+ static::markTestSkipped('only works for IWritableStorage');
+ }
- self::assertNull($storageManager->getBackend());
+ $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
- if ($userBackend) {
- $selBackend = $storageManager->getWritableStorageByName($name);
- $storageManager->setBackend($selBackend);
+ $selBackend = $storageManager->getWritableStorageByName($name);
+ $storageManager->setBackend($selBackend);
- self::assertInstanceOf($assert, $storageManager->getBackend());
- }
+ self::assertInstanceOf($assert, $storageManager->getBackend());
}
/**
* Test the method getBackend() with a pre-configured backend
*
* @dataProvider dataStorages
- * @dataProvider dataLegacyBackends
*/
- public function testPresetBackend($name, $assert, $assertName, $userBackend)
+ public function testPresetBackend($name, $valid, $interface, $assert, $assertName)
{
$this->config->set('storage', 'name', $name);
+ if ($interface !== Storage\IWritableStorage::class) {
+ $this->expectException(Storage\InvalidClassStorageException::class);
+ }
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
- if ($userBackend) {
- self::assertInstanceOf($assert, $storageManager->getBackend());
- } else {
- self::assertNull($storageManager->getBackend());
- }
+ self::assertInstanceOf($assert, $storageManager->getBackend());
}
/**
public function testRegisterUnregisterBackends()
{
/// @todo Remove dice once "Hook" is dynamic and mockable
- $dice = (new Dice())
+ $dice = (new Dice())
->addRules(include __DIR__ . '/../../../static/dependencies.config.php')
->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
->addRule(ISession::class, ['instanceOf' => Session\Memory::class, 'shared' => true, 'call' => null]);
SampleStorageBackend::registerHook();
Hook::loadHooks();
- self::assertTrue($storageManager->setBackend( $storageManager->getWritableStorageByName(SampleStorageBackend::NAME)));
+ self::assertTrue($storageManager->setBackend($storageManager->getWritableStorageByName(SampleStorageBackend::NAME)));
self::assertEquals(SampleStorageBackend::NAME, $this->config->get('storage', 'name'));
self::assertInstanceOf(SampleStorageBackend::class, $storageManager->getBackend());
*
* @dataProvider dataStorages
*/
- public function testMoveStorage($name, $assert, $assertName, $userBackend)
+ public function testMoveStorage($name, $valid, $interface, $assert, $assertName)
{
- if (!$userBackend) {
+ if ($interface !== Storage\IWritableStorage::class) {
self::markTestSkipped("No user backend");
}
$this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
- $storage = $storageManager->getWritableStorageByName($name);
+ $storage = $storageManager->getWritableStorageByName($name);
$storageManager->move($storage);
$photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
while ($photo = $this->dba->fetch($photos)) {
-
self::assertEmpty($photo['data']);
$storage = $storageManager->getByName($photo['backend-class']);
- $data = $storage->get($photo['backend-ref']);
+ $data = $storage->get($photo['backend-ref']);
self::assertNotEmpty($data);
}
*/
public function testWrongWritableStorage()
{
- $this->expectException(\TypeError::class);
+ $this->expectException(Storage\InvalidClassStorageException::class);
+ $this->expectExceptionMessage('Backend SystemResource is not valid');
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
- $storage = $storageManager->getWritableStorageByName(Storage\SystemResource::getName());
+ $storage = $storageManager->getWritableStorageByName(Storage\SystemResource::getName());
$storageManager->move($storage);
}
}