]> git.mxchange.org Git - friendica.git/commitdiff
Add doc
authorPhilipp <admin@philipp.info>
Sun, 16 Jul 2023 16:38:34 +0000 (18:38 +0200)
committerPhilipp <admin@philipp.info>
Sun, 16 Jul 2023 16:43:36 +0000 (18:43 +0200)
doc/AddonsStrategyDecorator.md

index 7e0d53e32f0fc5c606b630777390b9cc4b40d71e..51456da6c71d92b07db32c880be301eaec3d1825 100644 (file)
@@ -5,8 +5,155 @@ Friendica strategy and decorator Hooks
 
 ## Strategy hooks
 
+This type of hook is based on the [Strategy Design Pattern](https://refactoring.guru/design-patterns/strategy).
+
+A strategy class defines a possible implementation of a given interface based on a unique name.
+Every name is possible as long as it's unique and not `null`.
+Using an empty name (`''`) is possible as well and should be used as the "default" implementation.
+To register a strategy, use the [`ICanRegisterInstance`](../src/Core/Hooks/Capabilities/ICanRegisterInstances.php) interface.
+
+After registration, a caller can automatically create this instance with the [`ICanCreateInstances`](../src/Core/Hooks/Capabilities/ICanCreateInstances.php) interface and the chosen name.
+
+This is useful in case there are different, possible implementations for the same purpose, like for logging, locking, caching, ...
+
+Normally, a config entry is used to choose the right implementation at runtime.
+And if no config entry is set, the "default" implementation should be used.
+
+### Example
+
+```php
+interface ExampleInterface
+{
+       public function testMethod();
+}
+
+public class ConcreteClassA implements ExampleInterface
+{
+       public function testMethod()
+       {
+               echo "concrete class A";
+       }
+}
+
+public class ConcreteClassB implements ExampleInterface
+{
+       public function testMethod()
+       {
+               echo "concrete class B";
+       }
+}
+
+/** @var \Friendica\Core\Hooks\Capabilities\ICanRegisterInstances $instanceRegister */
+$instanceRegister->registerStrategy(ExampleInterface::class, ConcreteClassA::class, 'A');
+$instanceRegister->registerStrategy(ExampleInterface::class, ConcreteClassB::class, 'B');
+
+/** @var \Friendica\Core\Hooks\Capabilities\ICanCreateInstances $instanceManager */
+/** @var ConcreteClassA $concreteClass */
+$concreteClass = $instanceManager->createWithName(ExampleInterface::class, 'A');
+
+$concreteClass->testMethod();
+// output:
+// "concrete class A";
+```
+
 ## Decorator hooks
 
-## hook.config.php
+This type of hook is based on the [Decorator Design Pattern](https://refactoring.guru/design-patterns/decorator).
+
+A decorator class extends a given strategy instance (see  [Strategy hooks](#strategy-hooks)]).
+To register a decorator, use the [`ICanRegisterInstance`](../src/Core/Hooks/Capabilities/ICanRegisterInstances.php) interface.
+
+After registration, a caller can automatically create an instance with the [`ICanCreateInstances`](../src/Core/Hooks/Capabilities/ICanCreateInstances.php) interface and the decorator will wrap its logic around the call.
+
+This is useful in case you want to extend a given class but the given class isn't responsible for these business logic. Or you want to extend an interface without knowing the concrete implementation.
+For example profiling logger calls, Friendica is using a [`ProfilerLogger`](../src/Core/Logger/Type/ProfilerLogger.php), which wraps all other logging implementations and traces each log call.
+
+Normally, a config entry is used to enable/disable decorator.
+
+### Example
+
+```php
+interface ExampleInterface
+{
+       public function testMethod();
+}
+
+public class ConcreteClassA implements ExampleInterface
+{
+       public function testMethod()
+       {
+               echo "concrete class A";
+       }
+}
+
+public class DecoratorClassA implements ExampleInterface
+{
+       /** @var ExampleInterface */
+       protected $example;
+
+       public function __construct(ExampleInterface $example)
+       {
+               $this->example = $example;
+       }
+
+       public function testMethod()
+       {
+               echo "decorated!\n";
+               $this->example->testMethod();
+       }
+}
+
+/** @var \Friendica\Core\Hooks\Capabilities\ICanRegisterInstances $instanceRegister */
+$instanceRegister->registerStrategy(ExampleInterface::class, ConcreteClassA::class, 'A');
+$instanceRegister->registerDecorator(ExampleInterface::class, DecoratorClassA::class);
+
+/** @var \Friendica\Core\Hooks\Capabilities\ICanCreateInstances $instanceManager */
+/** @var ConcreteClassA $concreteClass */
+$concreteClass = $instanceManager->createWithName(ExampleInterface::class, 'A');
+
+$concreteClass->testMethod();
+// output:
+// "decorated!"
+// "concrete class A";
+```
+
+## hooks.config.php
+
+To avoid registering all strategies and decorators manually inside the code, Friendica introduced the [`hooks.config.php`](../static/hooks.config.php) file.
+
+There, you can register all kind of strategies and decorators in one file.
+
+### [`HookType::STRATEGY`](../src/Core/Hooks/Capabilities/HookType.php)
+
+For each given interface, a list of key-value pairs can be set, where the key is the concrete implementation class and the value is an array of unique names.
+
+### [`HookType::DECORATOR`](../src/Core/Hooks/Capabilities/HookType.php)
+
+For each given interface, a list of concrete decorator classes can be set.
+
+### Example
+
+```php
+use Friendica\Core\Hooks\Capabilities\HookType as H;
+
+return [
+       H::STRATEGY  => [
+               ExampleInterface::class => [
+                       ConcreteClassA::class => ['A'],
+                       ConcreteClassB::class => ['B'],
+               ],
+       ],
+       H::DECORATOR => [
+               ExampleInterface::class => [
+                       DecoratorClassA::class,
+               ],
+       ],
+];
+```
+
+## Addons
+
+The hook logic is useful for decoupling the Friendica core logic, but its primary goal is to modularize Friendica in creating addons.
 
-## Create new hooks
+Therefor you can either use the interfaces directly as shown above, or you can place your own `hooks.config.php` file inside a `static` directory directly under your addon core directory.
+Friendica will automatically search these config files for each **activated** addon and register the given hooks.