]> git.mxchange.org Git - friendica.git/blobdiff - doc/AddonStorageBackend.md
Merge pull request #13227 from BirdboyBolu/develop
[friendica.git] / doc / AddonStorageBackend.md
index e54960252be4777350d381531a5514bc00c0f42e..c3a6d1639cb76fb1c587b8c737294038531d990c 100644 (file)
@@ -4,24 +4,26 @@ Friendica Storage Backend Addon development
 * [Home](help)
 
 Storage backends can be added via addons.
-A storage backend is implemented as a class, and the plugin register the class to make it avaiable to the system.
+A storage backend is implemented as a class, and the plugin register the class to make it available to the system.
 
 ## The Storage Backend Class
 
 The class must live in `Friendica\Addon\youraddonname` namespace, where `youraddonname` the folder name of your addon.
 
-The class must implement `Friendica\Model\Storage\IWritableStorage` interface. All method in the interface must be implemented:
+There are two different interfaces you need to implement.
 
-namespace Friendica\Model\IWritableStorage;
+### `ICanWriteToStorage`
+
+The class must implement `Friendica\Core\Storage\Capability\ICanWriteToStorage` interface. All method in the interface must be implemented:
 
 ```php
-interface IWritableStorage
+namespace Friendica\Core\Storage\Capability\ICanWriteToStorage;
+
+interface ICanWriteToStorage
 {
        public function get(string $reference);
        public function put(string $data, string $reference = '');
        public function delete(string $reference);
-       public function getOptions();
-       public function saveOptions(array $data);
        public function __toString();
        public static function getName();
 }
@@ -31,7 +33,22 @@ interface IWritableStorage
 - `put(string $data, string $reference)` saves data in `$data` to position `$reference`, or a new position if `$reference` is empty.
 - `delete(string $reference)` delete data pointed by `$reference`
 
+### `ICanConfigureStorage`
+
 Each storage backend can have options the admin can set in admin page.
+To make the options possible, you need to implement the `Friendica\Core\Storage\Capability\ICanConfigureStorage` interface.
+
+All methods in the interface must be implemented:
+
+```php
+namespace Friendica\Core\Storage\Capability\ICanConfigureStorage;
+
+interface ICanConfigureStorage
+{
+       public function getOptions();
+       public function saveOptions(array $data);
+}
+```
 
 - `getOptions()` returns an array with details about each option to build the interface.
 - `saveOptions(array $data)` get `$data` from admin page, validate it and save it.
@@ -83,7 +100,7 @@ See doxygen documentation of `IWritableStorage` interface for details about each
 
 ## Register a storage backend class
 
-Each backend must be registered in the system when the plugin is installed, to be aviable.
+Each backend must be registered in the system when the plugin is installed, to be available.
 
 `DI::facStorage()->register(string $class)` is used to register the backend class.
 
@@ -91,7 +108,7 @@ When the plugin is uninstalled, registered backends must be unregistered using
 `DI::facStorage()->unregister(string $class)`.
 
 You have to register a new hook in your addon, listening on `storage_instance(App $a, array $data)`.
-In case `$data['name']` is your storage class name, you have to instance a new instance of your `Friendica\Model\Storage\IStorage` class.
+In case `$data['name']` is your storage class name, you have to instance a new instance of your `Friendica\Core\Storage\Capability\ICanReadFromStorage` class.
 Set the instance of your class as `$data['storage']` to pass it back to the backend.
 
 This is necessary because it isn't always clear, if you need further construction arguments.
@@ -107,7 +124,7 @@ Add a new test class which's naming convention is `StorageClassTest`, which exte
 Override the two necessary instances:
 
 ```php
-use Friendica\Model\Storage\IWritableStorage;
+use Friendica\Core\Storage\Capability\ICanWriteToStorage;
 
 abstract class StorageTest 
 {
@@ -115,7 +132,7 @@ abstract class StorageTest
        abstract protected function getInstance();
 
        // Assertion for the option array you return for your new StorageClass
-       abstract protected function assertOption(IWritableStorage $storage);
+       abstract protected function assertOption(ICanWriteToStorage $storage);
 } 
 ```
 
@@ -123,32 +140,32 @@ abstract class StorageTest
 
 There are two intended types of exceptions for storages
 
-### `ReferenceStorageExecption`
+### `ReferenceStorageException`
 
 This storage exception should be used in case the caller tries to use an invalid references.
 This could happen in case the caller tries to delete or update an unknown reference.
 The implementation of the storage backend must not ignore invalid references.
 
-Avoid throwing the common `StorageExecption` instead of the `ReferenceStorageException` at this particular situation!
+Avoid throwing the common `StorageException` instead of the `ReferenceStorageException` at this particular situation!
 
 ### `StorageException`
 
 This is the common exception in case unexpected errors happen using the storage backend.
-If there's a predecessor to this exception (e.g. you caught an exception and are throwing this execption), you should add the predecessor for transparency reasons.
+If there's a predecessor to this exception (e.g. you caught an exception and are throwing this exception), you should add the predecessor for transparency reasons.
 
 Example:
 
 ```php
-use Friendica\Model\Storage\IWritableStorage;
+use Friendica\Core\Storage\Capability\ICanWriteToStorage;
 
-class ExampleStorage implements IWritableStorage 
+class ExampleStorage implements ICanWriteToStorage 
 {
        public function get(string $reference) : string
        {
                try {
                        throw new Exception('a real bad exception');
                } catch (Exception $exception) {
-                       throw new \Friendica\Model\Storage\StorageException(sprintf('The Example Storage throws an exception for reference %s', $reference), 500, $exception);
+                       throw new \Friendica\Core\Storage\Exception\StorageException(sprintf('The Example Storage throws an exception for reference %s', $reference), 500, $exception);
                }
        }
 } 
@@ -156,7 +173,7 @@ class ExampleStorage implements IWritableStorage
 
 ## Example
 
-Here an hypotetical addon which register a useless storage backend.
+Here is a hypothetical addon which register a useless storage backend.
 Let's call it `samplestorage`.
 
 This backend will discard all data we try to save and will return always the same image when we ask for some data.
@@ -169,39 +186,34 @@ The file will be `addon/samplestorage/SampleStorageBackend.php`:
 <?php
 namespace Friendica\Addon\samplestorage;
 
-use Friendica\Model\Storage\IWritableStorage;
+use Friendica\Core\Storage\Capability\ICanWriteToStorage;
 
-use Friendica\Core\Config\IConfig;
+use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\Core\L10n;
 
-class SampleStorageBackend implements IWritableStorage
+class SampleStorageBackend implements ICanWriteToStorage
 {
        const NAME = 'Sample Storage';
 
-       /** @var IConfig */
-       private $config;
-       /** @var L10n */
-       private $l10n;
+       /** @var string */
+       private $filename;
 
        /**
          * SampleStorageBackend constructor.
-         * @param IConfig $config The configuration of Friendica
-         *                                                                       
+         * 
          * You can add here every dynamic class as dependency you like and add them to a private field
          * Friendica automatically creates these classes and passes them as argument to the constructor                                                                           
          */
-       public function __construct(IConfig $config, L10n $l10n
+       public function __construct(string $filename
        {
-               $this->config = $config;
-               $this->l10n   = $l10n;
+               $this->filename = $filename;
        }
 
        public function get(string $reference)
        {
                // we return always the same image data. Which file we load is defined by
                // a config key
-               $filename = $this->config->get('storage', 'samplestorage', 'sample.jpg');
-               return file_get_contents($filename);
+               return file_get_contents($this->filename);
        }
        
        public function put(string $data, string $reference = '')
@@ -219,6 +231,51 @@ class SampleStorageBackend implements IWritableStorage
                return true;
        }
        
+       public function __toString()
+       {
+               return self::NAME;
+       }
+
+       public static function getName()
+       {
+               return self::NAME;
+       }
+}
+```
+
+```php
+<?php
+namespace Friendica\Addon\samplestorage;
+
+use Friendica\Core\Storage\Capability\ICanConfigureStorage;
+
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Core\L10n;
+
+class SampleStorageBackendConfig implements ICanConfigureStorage
+{
+       /** @var \Friendica\Core\Config\Capability\IManageConfigValues */
+       private $config;
+       /** @var L10n */
+       private $l10n;
+
+       /**
+         * SampleStorageBackendConfig constructor.
+         * 
+         * You can add here every dynamic class as dependency you like and add them to a private field
+         * Friendica automatically creates these classes and passes them as argument to the constructor                                                                           
+         */
+       public function __construct(IManageConfigValues $config, L10n $l10n) 
+       {
+               $this->config = $config;
+               $this->l10n   = $l10n;
+       }
+
+       public function getFileName(): string
+       {
+               return $this->config->get('storage', 'samplestorage', 'sample.jpg');
+       }
+
        public function getOptions()
        {
                $filename = $this->config->get('storage', 'samplestorage', 'sample.jpg');
@@ -252,15 +309,6 @@ class SampleStorageBackend implements IWritableStorage
                return [];
        }
 
-       public function __toString()
-       {
-               return self::NAME;
-       }
-
-       public static function getName()
-       {
-               return self::NAME;
-       }
 }
 ```
 
@@ -272,42 +320,45 @@ The file is `addon/samplestorage/samplestorage.php`
 <?php
 /**
  * Name: Sample Storage Addon
- * Description: A sample addon which implements an unusefull storage backend
+ * Description: A sample addon which implements a very limited storage backend
  * Version: 1.0.0
  * Author: Alice <https://alice.social/~alice>
  */
 
 use Friendica\Addon\samplestorage\SampleStorageBackend;
+use Friendica\Addon\samplestorage\SampleStorageBackendConfig;
 use Friendica\DI;
 
 function samplestorage_install()
 {
-       // on addon install, we register our class with name "Sample Storage".
-       // note: we use `::class` property, which returns full class name as string
-       // this save us the problem of correctly escape backslashes in class name
+       Hook::register('storage_instance' , __FILE__, 'samplestorage_storage_instance');
+       Hook::register('storage_config' , __FILE__, 'samplestorage_storage_config');
        DI::storageManager()->register(SampleStorageBackend::class);
 }
 
-function samplestorage_unistall()
+function samplestorage_storage_uninstall()
 {
-       // when the plugin is uninstalled, we unregister the backend.
        DI::storageManager()->unregister(SampleStorageBackend::class);
 }
 
-function samplestorage_storage_instance(\Friendica\App $a, array $data)
+function samplestorage_storage_instance(App $a, array &$data)
 {
-    if ($data['name'] === SampleStorageBackend::getName()) {
-    // instance a new sample storage instance and pass it back to the core for usage
-        $data['storage'] = new SampleStorageBackend(DI::config(), DI::l10n(), DI::cache());
-    }
+       $config          = new SampleStorageBackendConfig(DI::l10n(), DI::config());
+       $data['storage'] = new SampleStorageBackendConfig($config->getFileName());
 }
+
+function samplestorage_storage_config(App $a, array &$data)
+{
+       $data['storage_config'] = new SampleStorageBackendConfig(DI::l10n(), DI::config());
+}
+
 ```
 
 **Theoretically - until tests for Addons are enabled too - create a test class with the name `addon/tests/SampleStorageTest.php`:
 
 ```php
-use Friendica\Model\Storage\IWritableStorage;
-use Friendica\Test\src\Model\Storage\StorageTest;
+use Friendica\Core\Storage\Capability\ICanWriteToStorage;
+use Friendica\Test\src\Core\Storage\StorageTest;
 
 class SampleStorageTest extends StorageTest 
 {
@@ -320,7 +371,7 @@ class SampleStorageTest extends StorageTest
        }
 
        // Assertion for the option array you return for your new StorageClass
-       protected function assertOption(IWritableStorage $storage)
+       protected function assertOption(ICanWriteToStorage $storage)
        {
                $this->assertEquals([
                        'filename' => [