X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=doc%2FAddonStorageBackend.md;h=17c3f0414077ee1dfb4d8a800427aea46372e39c;hb=9827e933a2a1b8e93f293d4e6293384126e5784c;hp=d42c8bbbd7f7aadd87e1804c8ad0fcb1bdbb2919;hpb=1de3960e267a8d298348fbca18cf1be1f6a20f7a;p=friendica.git diff --git a/doc/AddonStorageBackend.md b/doc/AddonStorageBackend.md index d42c8bbbd7..17c3f04140 100644 --- a/doc/AddonStorageBackend.md +++ b/doc/AddonStorageBackend.md @@ -17,22 +17,24 @@ namespace Friendica\Model\Storage; ```php interface IStorage { - public static function get($ref); - public static function put($data, $ref = ""); - public static function delete($ref); - public static function getOptions(); - public static function saveOptions($data); + 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(); } ``` -- `get($ref)` returns data pointed by `$ref` -- `put($data, $ref)` saves data in `$data` to position `$ref`, or a new position if `$ref` is empty. -- `delete($ref)` delete data pointed by `$ref` +- `get(string $reference)` returns data pointed by `$reference` +- `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` Each storage backend can have options the admin can set in admin page. - `getOptions()` returns an array with details about each option to build the interface. -- `saveOptions($data)` get `$data` from admin page, validate it and save it. +- `saveOptions(array $data)` get `$data` from admin page, validate it and save it. The array returned by `getOptions()` is defined as: @@ -84,11 +86,38 @@ See doxygen documentation of `IStorage` interface for details about each method. Each backend must be registered in the system when the plugin is installed, to be aviable. -`Friendica\Core\StorageManager::register($name, $class)` is used to register the backend class. -The `$name` must be univocal and will be shown to admin. +`DI::facStorage()->register(string $class)` is used to register the backend class. When the plugin is uninstalled, registered backends must be unregistered using -`Friendica\Core\StorageManager::unregister($class)`. +`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. +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. + +## Adding tests + +**Currently testing is limited to core Friendica only, this shows theoretically how tests should work in the future** + +Each new Storage class should be added to the test-environment at [Storage Tests](https://github.com/friendica/friendica/tree/develop/tests/src/Model/Storage/). + +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\IStorage; + +abstract class StorageTest +{ + // returns an instance of your newly created storage class + abstract protected function getInstance(); + + // Assertion for the option array you return for your new StorageClass + abstract protected function assertOption(IStorage $storage); +} +``` ## Example @@ -107,65 +136,96 @@ namespace Friendica\Addon\samplestorage; use Friendica\Model\Storage\IStorage; -use Friendica\Core\Config; +use Friendica\Core\Config\IConfig; use Friendica\Core\L10n; class SampleStorageBackend implements IStorage { - public static function get($ref) + const NAME = 'Sample Storage'; + + /** @var IConfig */ + private $config; + /** @var L10n */ + private $l10n; + + /** + * 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) { - // we return alwais the same image data. Which file we load is defined by + $this->config = $config; + $this->l10n = $l10n; + } + + public function get(string $reference) + { + // we return always the same image data. Which file we load is defined by // a config key - $filename = Config::get("storage", "samplestorage", "sample.jpg"); + $filename = $this->config->get('storage', 'samplestorage', 'sample.jpg'); return file_get_contents($filename); } - public static function put($data, $ref = "") + public function put(string $data, string $reference = '') { - if ($ref === "") { - $ref = "sample"; + if ($reference === '') { + $reference = 'sample'; } // we don't save $data ! - return $ref; + return $reference; } - public static function delete($ref) + public function delete(string $reference) { // we pretend to delete the data return true; } - public static function getOptions() + public function getOptions() { - $filename = Config::get("storage", "samplestorage", "sample.jpg"); + $filename = $this->config->get('storage', 'samplestorage', 'sample.jpg'); return [ - "filename" => [ - "input", // will use a simple text input - L10n::t("The file to return"), // the label + 'filename' => [ + 'input', // will use a simple text input + $this->l10n->t('The file to return'), // the label $filename, // the current value - L10n::t("Enter the path to a file"), // the help text - // no extra data for "input" type.. + $this->l10n->t('Enter the path to a file'), // the help text + // no extra data for 'input' type.. + ], ]; } - public static function saveOptions($data) + public function saveOptions(array $data) { // the keys in $data are the same keys we defined in getOptions() - $newfilename = trim($data["filename"]); + $newfilename = trim($data['filename']); // this function should always validate the data. // in this example we check if file exists if (!file_exists($newfilename)) { // in case of error we return an array with - // ["optionname" => "error message"] - return ["filename" => "The file doesn't exists"]; + // ['optionname' => 'error message'] + return ['filename' => 'The file doesn\'t exists']; } - Config::set("storage", "samplestorage", $newfilename); + $this->config->set('storage', 'samplestorage', $newfilename); // no errors, return empty array return []; } + + public function __toString() + { + return self::NAME; + } + + public static function getName() + { + return self::NAME; + } } ``` @@ -182,23 +242,59 @@ The file is `addon/samplestorage/samplestorage.php` * Author: Alice */ -use Friendica\Core\StorageManager; use Friendica\Addon\samplestorage\SampleStorageBackend; +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 - StorageManager::register("Sample Storage", SampleStorageBackend::class); + DI::storageManager()->register(SampleStorageBackend::class); } function samplestorage_unistall() { // when the plugin is uninstalled, we unregister the backend. - StorageManager::unregister("Sample Storage"); + DI::storageManager()->unregister(SampleStorageBackend::class); +} + +function samplestorage_storage_instance(\Friendica\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()); + } } ``` +**Theoretically - until tests for Addons are enabled too - create a test class with the name `addon/tests/SampleStorageTest.php`: +```php +use Friendica\Model\Storage\IStorage; +use Friendica\Test\src\Model\Storage\StorageTest; + +class SampleStorageTest extends StorageTest +{ + // returns an instance of your newly created storage class + protected function getInstance() + { + // create a new SampleStorageBackend instance with all it's dependencies + // Have a look at DatabaseStorageTest or FilesystemStorageTest for further insights + return new SampleStorageBackend(); + } + // Assertion for the option array you return for your new StorageClass + protected function assertOption(IStorage $storage) + { + $this->assertEquals([ + 'filename' => [ + 'input', + 'The file to return', + 'sample.jpg', + 'Enter the path to a file' + ], + ], $storage->getOptions()); + } +} +```