The class must live in `Friendica\Addon\youraddonname` namespace, where `youraddonname` the folder name of your addon.
-The class must implement `Friendica\Model\Storage\ISelectableStorage` interface. All method in the interface must be implemented:
+The class must implement `Friendica\Model\Storage\IWritableStorage` interface. All method in the interface must be implemented:
-namespace Friendica\Model\ISelectableStorage;
+namespace Friendica\Model\IWritableStorage;
```php
-interface ISelectableStorage
+interface IWritableStorage
{
public function get(string $reference);
public function put(string $data, string $reference = '');
];
-See doxygen documentation of `ISelectableStorage` interface for details about each method.
+See doxygen documentation of `IWritableStorage` interface for details about each method.
## Register a storage backend class
Add a new test class which's naming convention is `StorageClassTest`, which extend the `StorageTest` in the same directory.
Override the two necessary instances:
+
```php
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
abstract class StorageTest
{
abstract protected function getInstance();
// Assertion for the option array you return for your new StorageClass
- abstract protected function assertOption(ISelectableStorage $storage);
+ abstract protected function assertOption(IWritableStorage $storage);
}
```
Example:
```php
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
-class ExampleStorage implements ISelectableStorage
+class ExampleStorage implements IWritableStorage
{
public function get(string $reference) : string
{
<?php
namespace Friendica\Addon\samplestorage;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Core\Config\IConfig;
use Friendica\Core\L10n;
-class SampleStorageBackend implements ISelectableStorage
+class SampleStorageBackend implements IWritableStorage
{
const NAME = 'Sample Storage';
**Theoretically - until tests for Addons are enabled too - create a test class with the name `addon/tests/SampleStorageTest.php`:
```php
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Test\src\Model\Storage\StorageTest;
class SampleStorageTest extends StorageTest
}
// Assertion for the option array you return for your new StorageClass
- protected function assertOption(ISelectableStorage $storage)
+ protected function assertOption(IWritableStorage $storage)
{
$this->assertEquals([
'filename' => [
}
$name = $this->args[1];
- $class = $this->storageManager->getSelectableStorageByName($name);
+ $class = $this->storageManager->getWritableStorageByName($name);
if (is_null($class)) {
$this->out($name . ' is not a registered backend.');
$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->getSelectableStorageByName($currentName);
+ $this->currentBackend = $this->getWritableStorageByName($currentName);
}
/**
* Return current storage backend class
*
- * @return Storage\ISelectableStorage|null
+ * @return Storage\IWritableStorage|null
*/
public function getBackend()
{
}
/**
- * Returns a selectable storage backend class by registered name
+ * Returns a writable storage backend class by registered name
*
* @param string $name Backend name
*
- * @return Storage\ISelectableStorage
+ * @return Storage\IWritableStorage
*
* @throws Storage\ReferenceStorageException 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 getSelectableStorageByName(string $name = null)
+ public function getWritableStorageByName(string $name = null)
{
// @todo 2020.09 Remove this call after 2 releases
$name = $this->checkLegacyBackend($name);
];
try {
Hook::callAll('storage_instance', $data);
- if (($data['storage'] ?? null) instanceof Storage\ISelectableStorage) {
+ 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));
/**
* Set current storage backend class
*
- * @param Storage\ISelectableStorage $storage The storage class
+ * @param Storage\IWritableStorage $storage The storage class
*
* @return boolean True, if the set was successful
*/
- public function setBackend(Storage\ISelectableStorage $storage)
+ public function setBackend(Storage\IWritableStorage $storage)
{
if ($this->config->set('storage', 'name', $storage::getName())) {
$this->currentBackend = $storage;
* Copy existing data to destination storage and delete from source.
* This method cannot move to legacy in-table `data` field.
*
- * @param Storage\ISelectableStorage $destination Destination storage class name
- * @param array $tables Tables to look in for resources. Optional, defaults to ['photo', 'attach']
- * @param int $limit Limit of the process batch size, defaults to 5000
+ * @param Storage\IWritableStorage $destination Destination storage class name
+ * @param array $tables Tables to look in for resources. Optional, defaults to ['photo', 'attach']
+ * @param int $limit Limit of the process batch size, defaults to 5000
*
* @return int Number of moved resources
* @throws Storage\StorageException
* @throws Exception
*/
- public function move(Storage\ISelectableStorage $destination, array $tables = self::TABLES, int $limit = 5000)
+ public function move(Storage\IWritableStorage $destination, array $tables = self::TABLES, int $limit = 5000)
{
if (!$this->isValidBackend($destination, true)) {
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->getSelectableStorageByName($resource['backend-class']);
+ $source = $this->getWritableStorageByName($resource['backend-class']);
$sourceRef = $resource['backend-ref'];
if (!empty($source)) {
}
/**
- * @return Model\Storage\ISelectableStorage
+ * @return Model\Storage\IWritableStorage
*/
public static function storage()
{
- return self::$dice->create(Model\Storage\ISelectableStorage::class);
+ return self::$dice->create(Model\Storage\IWritableStorage::class);
}
//
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
foreach($items as $item) {
- $backend_class = DI::storageManager()->getSelectableStorageByName($item['backend-class'] ?? '');
+ $backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
if (!empty($backend_class)) {
$fields['backend-ref'] = $backend_class->put($img->asString(), $item['backend-ref'] ?? '');
} else {
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
foreach($items as $item) {
- $backend_class = DI::storageManager()->getSelectableStorageByName($item['backend-class'] ?? '');
+ $backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
if (!empty($backend_class)) {
try {
$backend_class->delete($item['backend-ref'] ?? '');
if (DBA::isResult($existing_photo)) {
$backend_ref = (string)$existing_photo["backend-ref"];
- $storage = DI::storageManager()->getSelectableStorageByName($existing_photo["backend-class"] ?? '');
+ $storage = DI::storageManager()->getWritableStorageByName($existing_photo["backend-class"] ?? '');
} else {
$storage = DI::storage();
}
$photos = DBA::select('photo', ['id', 'backend-class', 'backend-ref'], $conditions);
while ($photo = DBA::fetch($photos)) {
- $backend_class = DI::storageManager()->getSelectableStorageByName($photo['backend-class'] ?? '');
+ $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
if (!empty($backend_class)) {
try {
$backend_class->delete($item['backend-ref'] ?? '');
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
foreach($photos as $photo) {
- $backend_class = DI::storageManager()->getSelectableStorageByName($photo['backend-class'] ?? '');
+ $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
if (!empty($backend_class)) {
$fields["backend-ref"] = $backend_class->put($img->asString(), $photo['backend-ref']);
} else {
*
* This class manage data stored in database table.
*/
-class Database implements ISelectableStorage
+class Database implements IWritableStorage
{
const NAME = 'Database';
* Each new resource gets a value as reference and is saved in a
* folder tree stucture created from that value.
*/
-class Filesystem implements ISelectableStorage
+class Filesystem implements IWritableStorage
{
const NAME = 'Filesystem';
+++ /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;
-
-/**
- * Interface for selectable storage backends
- *
- * Used for storages with CRUD functionality, mainly used for user data (e.g. photos, attachements).
- * There's only one active, selectable storage possible and can be selected by the current administrator
- */
-interface ISelectableStorage extends IStorage
-{
- /**
- * Put data in backend as $ref. If $ref is not defined a new reference is created.
- *
- * @param string $data Data to save
- * @param string $reference Data reference. Optional.
- *
- * @return string Saved data reference
- *
- * @throws StorageException in case there's an unexpected error
- */
- public function put(string $data, string $reference = ""): string;
-
- /**
- * Remove data from backend
- *
- * @param string $reference Data reference
- *
- * @throws StorageException in case there's an unexpected error
- * @throws ReferenceStorageException in case the reference doesn't exist
- */
- public function delete(string $reference);
-
- /**
- * Get info about storage options
- *
- * @return array
- *
- * This method return an array with informations about storage options
- * from which the form presented to the user is build.
- *
- * The returned array is:
- *
- * [
- * 'option1name' => [ ..info.. ],
- * 'option2name' => [ ..info.. ],
- * ...
- * ]
- *
- * An empty array can be returned if backend doesn't have any options
- *
- * The info array for each option MUST be as follows:
- *
- * [
- * 'type', // define the field used in form, and the type of data.
- * // one of 'checkbox', 'combobox', 'custom', 'datetime',
- * // 'input', 'intcheckbox', 'password', 'radio', 'richtext'
- * // 'select', 'select_raw', 'textarea'
- *
- * 'label', // Translatable label of the field
- * 'value', // Current value
- * 'help text', // Translatable description for the field
- * extra data // Optional. Depends on 'type':
- * // select: array [ value => label ] of choices
- * // intcheckbox: value of input element
- * // select_raw: prebuild html string of < option > tags
- * ]
- *
- * See https://github.com/friendica/friendica/wiki/Quick-Template-Guide
- */
- public function getOptions(): array;
-
- /**
- * Validate and save options
- *
- * @param array $data Array [optionname => value] to be saved
- *
- * @return array Validation errors: [optionname => error message]
- *
- * Return array must be empty if no error.
- */
- public function saveOptions(array $data): array;
-}
--- /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;
+
+/**
+ * Interface for writable storage backends
+ *
+ * Used for storages with CRUD functionality, mainly used for user data (e.g. photos, attachements).
+ * There's only one active, writable storage possible. This type of storages are selectable by the current administrator
+ */
+interface IWritableStorage extends IStorage
+{
+ /**
+ * Put data in backend as $ref. If $ref is not defined a new reference is created.
+ *
+ * @param string $data Data to save
+ * @param string $reference Data reference. Optional.
+ *
+ * @return string Saved data reference
+ *
+ * @throws StorageException in case there's an unexpected error
+ */
+ public function put(string $data, string $reference = ""): string;
+
+ /**
+ * Remove data from backend
+ *
+ * @param string $reference Data reference
+ *
+ * @throws StorageException in case there's an unexpected error
+ * @throws ReferenceStorageException in case the reference doesn't exist
+ */
+ public function delete(string $reference);
+
+ /**
+ * Get info about storage options
+ *
+ * @return array
+ *
+ * This method return an array with informations about storage options
+ * from which the form presented to the user is build.
+ *
+ * The returned array is:
+ *
+ * [
+ * 'option1name' => [ ..info.. ],
+ * 'option2name' => [ ..info.. ],
+ * ...
+ * ]
+ *
+ * An empty array can be returned if backend doesn't have any options
+ *
+ * The info array for each option MUST be as follows:
+ *
+ * [
+ * 'type', // define the field used in form, and the type of data.
+ * // one of 'checkbox', 'combobox', 'custom', 'datetime',
+ * // 'input', 'intcheckbox', 'password', 'radio', 'richtext'
+ * // 'select', 'select_raw', 'textarea'
+ *
+ * 'label', // Translatable label of the field
+ * 'value', // Current value
+ * 'help text', // Translatable description for the field
+ * extra data // Optional. Depends on 'type':
+ * // select: array [ value => label ] of choices
+ * // intcheckbox: value of input element
+ * // select_raw: prebuild html string of < option > tags
+ * ]
+ *
+ * See https://github.com/friendica/friendica/wiki/Quick-Template-Guide
+ */
+ public function getOptions(): array;
+
+ /**
+ * Validate and save options
+ *
+ * @param array $data Array [optionname => value] to be saved
+ *
+ * @return array Validation errors: [optionname => error message]
+ *
+ * Return array must be empty if no error.
+ */
+ public function saveOptions(array $data): array;
+}
use Friendica\Core\Renderer;
use Friendica\DI;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Module\BaseAdmin;
use Friendica\Util\Strings;
$storagebackend = Strings::escapeTags(trim($parameters['name'] ?? ''));
- /** @var ISelectableStorage $newstorage */
- $newstorage = DI::storageManager()->getSelectableStorageByName($storagebackend);
+ /** @var IWritableStorage $newstorage */
+ $newstorage = DI::storageManager()->getWritableStorageByName($storagebackend);
// save storage backend form
$storage_opts = $newstorage->getOptions();
}
if (!empty($_POST['submit_save_set'])) {
- /** @var ISelectableStorage $newstorage */
- $newstorage = DI::storageManager()->getSelectableStorageByName($storagebackend);
+ /** @var IWritableStorage $newstorage */
+ $newstorage = DI::storageManager()->getWritableStorageByName($storagebackend);
if (!DI::storageManager()->setBackend($newstorage)) {
notice(DI::l10n()->t('Invalid storage backend setting value.'));
$storage_form_prefix = preg_replace('|[^a-zA-Z0-9]|', '', $name);
$storage_form = [];
- foreach (DI::storageManager()->getSelectableStorageByName($name)->getOptions() as $option => $info) {
+ foreach (DI::storageManager()->getWritableStorageByName($name)->getOptions() as $option => $info) {
$type = $info[0];
// Backward compatibilty with yesno field description
if ($type == 'yesno') {
'name' => $name,
'prefix' => $storage_form_prefix,
'form' => $storage_form,
- 'active' => $current_storage_backend instanceof ISelectableStorage && $name === $current_storage_backend::getName(),
+ 'active' => $current_storage_backend instanceof IWritableStorage && $name === $current_storage_backend::getName(),
];
}
'$noconfig' => DI::l10n()->t('This backend doesn\'t have custom settings'),
'$baseurl' => DI::baseUrl()->get(true),
'$form_security_token' => self::getFormSecurityToken("admin_storage"),
- '$storagebackend' => $current_storage_backend instanceof ISelectableStorage ? $current_storage_backend::getName() : DI::l10n()->t('Database (legacy)'),
+ '$storagebackend' => $current_storage_backend instanceof IWritableStorage ? $current_storage_backend::getName() : DI::l10n()->t('Database (legacy)'),
'$availablestorageforms' => $available_storage_forms,
]);
}
use Friendica\Core\StorageManager;
use Friendica\Database\Database;
use Friendica\Factory;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Model\User\Cookie;
use Friendica\Network;
use Friendica\Util;
$_SERVER, $_COOKIE
],
],
- ISelectableStorage::class => [
+ IWritableStorage::class => [
'instanceOf' => StorageManager::class,
'call' => [
['getBackend', [], Dice::CHAIN_CALL],
namespace Friendica\Test\Util;
use Friendica\Core\Hook;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Core\L10n;
/**
* A backend storage example class
*/
-class SampleStorageBackend implements ISelectableStorage
+class SampleStorageBackend implements IWritableStorage
{
const NAME = 'Sample Storage';
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, $this->httpRequest);
if ($userBackend) {
- $storage = $storageManager->getSelectableStorageByName($name);
+ $storage = $storageManager->getWritableStorageByName($name);
} else {
$storage = $storageManager->getByName($name);
}
self::assertNull($storageManager->getBackend());
if ($userBackend) {
- $selBackend = $storageManager->getSelectableStorageByName($name);
+ $selBackend = $storageManager->getWritableStorageByName($name);
$storageManager->setBackend($selBackend);
self::assertInstanceOf($assert, $storageManager->getBackend());
SampleStorageBackend::registerHook();
Hook::loadHooks();
- self::assertTrue($storageManager->setBackend( $storageManager->getSelectableStorageByName(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());
$this->loadFixture(__DIR__ . '/../../datasets/storage/database.fixture.php', $this->dba);
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
- $storage = $storageManager->getSelectableStorageByName($name);
+ $storage = $storageManager->getWritableStorageByName($name);
$storageManager->move($storage);
$photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
/**
* Test moving data to a WRONG storage
*/
- public function testWrongSelectableStorage()
+ public function testWrongWritableStorage()
{
$this->expectException(\TypeError::class);
$storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n);
- $storage = $storageManager->getSelectableStorageByName(Storage\SystemResource::getName());
+ $storage = $storageManager->getWritableStorageByName(Storage\SystemResource::getName());
$storageManager->move($storage);
}
}
use Friendica\Factory\ConfigFactory;
use Friendica\Model\Storage\Database;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Test\DatabaseTestTrait;
use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Test\Util\VFSTrait;
return new Database($dba);
}
- protected function assertOption(ISelectableStorage $storage)
+ protected function assertOption(IWritableStorage $storage)
{
self::assertEmpty($storage->getOptions());
}
use Friendica\Core\Config\IConfig;
use Friendica\Core\L10n;
use Friendica\Model\Storage\Filesystem;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Model\Storage\StorageException;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\Profiler;
return new Filesystem($this->config, $l10n);
}
- protected function assertOption(ISelectableStorage $storage)
+ protected function assertOption(IWritableStorage $storage)
{
self::assertEquals([
'storagepath' => [
namespace Friendica\Test\src\Model\Storage;
-use Friendica\Model\Storage\ISelectableStorage;
+use Friendica\Model\Storage\IWritableStorage;
use Friendica\Model\Storage\IStorage;
use Friendica\Model\Storage\ReferenceStorageException;
use Friendica\Test\MockedTest;
abstract class StorageTest extends MockedTest
{
- /** @return ISelectableStorage */
+ /** @return IWritableStorage */
abstract protected function getInstance();
- abstract protected function assertOption(ISelectableStorage $storage);
+ abstract protected function assertOption(IWritableStorage $storage);
/**
* Test if the instance is "really" implementing the interface