From 7bfc3c0ae01f4c6b7b3e51b5f84452469cb3f04f Mon Sep 17 00:00:00 2001
From: Philipp <admin@philipp.info>
Date: Sun, 16 Jul 2023 18:38:34 +0200
Subject: [PATCH] Add doc

---
 doc/AddonsStrategyDecorator.md | 151 ++++++++++++++++++++++++++++++++-
 1 file changed, 149 insertions(+), 2 deletions(-)

diff --git a/doc/AddonsStrategyDecorator.md b/doc/AddonsStrategyDecorator.md
index 7e0d53e32f..51456da6c7 100644
--- a/doc/AddonsStrategyDecorator.md
+++ b/doc/AddonsStrategyDecorator.md
@@ -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.
-- 
2.39.5