Add tests for InstanceManager and remove Decorator hook logic (avoid complex Dice logic)
This commit is contained in:
parent
527622df4a
commit
93af6f0564
14 changed files with 218 additions and 390 deletions
|
@ -1,159 +0,0 @@
|
|||
Friendica strategy and decorator Hooks
|
||||
===========================================
|
||||
|
||||
* [Home](help)
|
||||
|
||||
## 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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
89
doc/StrategyHooks.md
Normal file
89
doc/StrategyHooks.md
Normal file
|
@ -0,0 +1,89 @@
|
|||
Friendica strategy Hooks
|
||||
===========================================
|
||||
|
||||
* [Home](help)
|
||||
|
||||
## 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->create(ExampleInterface::class, 'A');
|
||||
|
||||
$concreteClass->testMethod();
|
||||
// output:
|
||||
// "concrete class A";
|
||||
```
|
||||
|
||||
## hooks.config.php
|
||||
|
||||
To avoid registering all strategies manually inside the code, Friendica introduced the [`hooks.config.php`](../static/hooks.config.php) file.
|
||||
|
||||
There, you can register all kind of strategies 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.
|
||||
|
||||
### Example
|
||||
|
||||
```php
|
||||
use Friendica\Core\Hooks\Capabilities\BehavioralHookType as H;
|
||||
|
||||
return [
|
||||
H::STRATEGY => [
|
||||
ExampleInterface::class => [
|
||||
ConcreteClassA::class => ['A'],
|
||||
ConcreteClassB::class => ['B'],
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
## Addons
|
||||
|
||||
The hook logic is useful for decoupling the Friendica core logic, but its primary goal is to modularize Friendica in creating addons.
|
||||
|
||||
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.
|
|
@ -21,7 +21,11 @@
|
|||
|
||||
namespace Friendica\Core\Hooks\Capabilities;
|
||||
|
||||
interface HookType
|
||||
/**
|
||||
* An enum of hook types, based on behavioral design patterns
|
||||
* @see https://refactoring.guru/design-patterns/behavioral-patterns
|
||||
*/
|
||||
interface BehavioralHookType
|
||||
{
|
||||
/**
|
||||
* Defines the key for the list of strategy-hooks.
|
||||
|
@ -29,11 +33,5 @@ interface HookType
|
|||
* @see https://refactoring.guru/design-patterns/strategy
|
||||
*/
|
||||
const STRATEGY = 'strategy';
|
||||
/**
|
||||
* Defines the key for the list of decorator-hooks.
|
||||
*
|
||||
* @see https://refactoring.guru/design-patterns/decorator
|
||||
*/
|
||||
const DECORATOR = 'decorator';
|
||||
const EVENT = 'event';
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
namespace Friendica\Core\Hooks\Capabilities;
|
||||
|
||||
/**
|
||||
* creates special instance and decorator treatments for given classes
|
||||
* creates special instances for given classes
|
||||
*/
|
||||
interface ICanCreateInstances
|
||||
{
|
||||
|
@ -31,27 +31,11 @@ interface ICanCreateInstances
|
|||
*
|
||||
* The instance will be build based on the registered strategy and the (unique) name
|
||||
*
|
||||
* In case, there are registered decorators for this class as well, all decorators of the list will be wrapped
|
||||
* around the instance before returning it
|
||||
*
|
||||
* @param string $class The fully-qualified name of the given class or interface which will get returned
|
||||
* @param string $name An arbitrary identifier to find a concrete instance strategy.
|
||||
* @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime
|
||||
*
|
||||
* @return object The concrete instance of the type "$class"
|
||||
*/
|
||||
public function createWithName(string $class, string $name, array $arguments = []): object;
|
||||
|
||||
/**
|
||||
* Returns a new instance of a given class
|
||||
*
|
||||
* In case, there are registered decorators for this class as well, all decorators of the list will be wrapped
|
||||
* around the instance before returning it
|
||||
*
|
||||
* @param string $class The fully-qualified name of the given class or interface which will get returned
|
||||
* @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime
|
||||
*
|
||||
* @return object The concrete instance of the type "$class"
|
||||
*/
|
||||
public function create(string $class, array $arguments = []): object;
|
||||
public function create(string $class, string $name, array $arguments = []): object;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Friendica\Core\Hooks\Capabilities;
|
|||
use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException;
|
||||
|
||||
/**
|
||||
* Register strategies and decorator/treatment handling for given classes
|
||||
* Register strategies for given classes
|
||||
*/
|
||||
interface ICanRegisterInstances
|
||||
{
|
||||
|
@ -43,21 +43,4 @@ interface ICanRegisterInstances
|
|||
* @throws HookRegisterArgumentException in case the given class for the interface isn't valid or already set
|
||||
*/
|
||||
public function registerStrategy(string $interface, string $class, ?string $name = null): self;
|
||||
|
||||
/**
|
||||
* Register a new decorator for a given class or interface
|
||||
*
|
||||
* @see https://refactoring.guru/design-patterns/decorator
|
||||
*
|
||||
* @note Decorator attach new behaviors to classes without changing them or without letting them know about it.
|
||||
*
|
||||
* @param string $class The fully-qualified class or interface name, which gets decorated by a class
|
||||
* @param string $decoratorClass The fully-qualified name of the class which mimics the given class or interface and adds new functionality
|
||||
* A placeholder for dependencies is possible as well
|
||||
*
|
||||
* @return $this This interface for chain-calls
|
||||
*
|
||||
* @throws HookRegisterArgumentException in case the given class for the class or interface isn't valid
|
||||
*/
|
||||
public function registerDecorator(string $class, string $decoratorClass): self;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ use Friendica\Core\Hooks\Util\HookFileManager;
|
|||
class DiceInstanceManager implements ICanCreateInstances, ICanRegisterInstances
|
||||
{
|
||||
protected $instance = [];
|
||||
protected $decorator = [];
|
||||
|
||||
/** @var Dice */
|
||||
protected $dice;
|
||||
|
@ -60,52 +59,12 @@ class DiceInstanceManager implements ICanCreateInstances, ICanRegisterInstances
|
|||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function registerDecorator(string $class, string $decoratorClass): ICanRegisterInstances
|
||||
{
|
||||
$this->decorator[$class][] = $decoratorClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function create(string $class, array $arguments = []): object
|
||||
{
|
||||
$instanceClassName = $class;
|
||||
$instanceRule = $this->dice->getRule($instanceClassName) ?? [];
|
||||
|
||||
$instanceRule = array_replace_recursive($instanceRule, [
|
||||
'constructParams' => $arguments,
|
||||
]);
|
||||
|
||||
$this->dice = $this->dice->addRule($instanceClassName, $instanceRule);
|
||||
|
||||
foreach ($this->decorator[$class] ?? [] as $decorator) {
|
||||
$dependencyRule = $this->dice->getRule($decorator);
|
||||
for ($i = 0; $i < count($dependencyRule['call'] ?? []); $i++) {
|
||||
$dependencyRule['call'][$i][1] = [[Dice::INSTANCE => $instanceClassName]];
|
||||
}
|
||||
$dependencyRule['constructParams'] = $arguments;
|
||||
$dependencyRule['substitutions'] = [
|
||||
$class => $instanceClassName,
|
||||
];
|
||||
|
||||
$this->dice = $this->dice->addRule($decorator, $dependencyRule);
|
||||
|
||||
$instanceClassName = $decorator;
|
||||
}
|
||||
|
||||
return $this->dice->create($instanceClassName);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function createWithName(string $class, string $name, array $arguments = []): object
|
||||
public function create(string $class, string $name, array $arguments = []): object
|
||||
{
|
||||
if (empty($this->instance[$class][$name])) {
|
||||
throw new HookInstanceException(sprintf('The class with the name %s isn\'t registered for the class or interface %s', $name, $class));
|
||||
}
|
||||
|
||||
$instanceClassName = $this->instance[$class][$name];
|
||||
|
||||
return $this->create($instanceClassName, $arguments);
|
||||
return $this->dice->create($this->instance[$class][$name], $arguments);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
namespace Friendica\Core\Hooks\Util;
|
||||
|
||||
use Friendica\Core\Addon\Capabilities\ICanLoadAddons;
|
||||
use Friendica\Core\Hooks\Capabilities\HookType;
|
||||
use Friendica\Core\Hooks\Capabilities\BehavioralHookType;
|
||||
use Friendica\Core\Hooks\Capabilities\ICanRegisterInstances;
|
||||
use Friendica\Core\Hooks\Exceptions\HookConfigException;
|
||||
|
||||
|
@ -63,7 +63,7 @@ class HookFileManager
|
|||
|
||||
foreach ($this->hookConfig as $hookType => $classList) {
|
||||
switch ($hookType) {
|
||||
case HookType::STRATEGY:
|
||||
case BehavioralHookType::STRATEGY:
|
||||
foreach ($classList as $interface => $strategy) {
|
||||
foreach ($strategy as $dependencyName => $names) {
|
||||
if (is_array($names)) {
|
||||
|
@ -76,17 +76,6 @@ class HookFileManager
|
|||
}
|
||||
}
|
||||
break;
|
||||
case HookType::DECORATOR:
|
||||
foreach ($classList as $interface => $decorators) {
|
||||
if (is_array($decorators)) {
|
||||
foreach ($decorators as $decorator) {
|
||||
$instanceRegister->registerDecorator($interface, $decorator);
|
||||
}
|
||||
} else {
|
||||
$instanceRegister->registerDecorator($interface, $decorators);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace Friendica\Core\Logger\Factory;
|
|||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Hooks\Capabilities\ICanCreateInstances;
|
||||
use Friendica\Core\Logger\Capabilities\LogChannel;
|
||||
use Friendica\Core\Logger\Type\ProfilerLogger as ProfilerLoggerClass;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use Throwable;
|
||||
|
@ -41,7 +43,7 @@ class Logger
|
|||
$this->channel = $channel;
|
||||
}
|
||||
|
||||
public function create(ICanCreateInstances $createInstances, IManageConfigValues $config): LoggerInterface
|
||||
public function create(ICanCreateInstances $createInstances, IManageConfigValues $config, Profiler $profiler): LoggerInterface
|
||||
{
|
||||
if (empty($config->get('system', 'debugging') ?? false)) {
|
||||
return new NullLogger();
|
||||
|
@ -50,7 +52,13 @@ class Logger
|
|||
$name = $config->get('system', 'logger_config') ?? '';
|
||||
|
||||
try {
|
||||
return $createInstances->createWithName(LoggerInterface::class, $name, [$this->channel]);
|
||||
/** @var LoggerInterface $logger */
|
||||
$logger = $createInstances->create(LoggerInterface::class, $name, [$this->channel]);
|
||||
if ($config->get('system', 'profiling') ?? false) {
|
||||
return new ProfilerLoggerClass($logger, $profiler);
|
||||
} else {
|
||||
return $logger;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// No logger ...
|
||||
return new NullLogger();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\Core\Hooks\Capabilities\HookType as H;
|
||||
use Friendica\Core\Hooks\Capabilities\BehavioralHookType as H;
|
||||
use Friendica\Core\Logger\Type;
|
||||
use Psr\Log;
|
||||
|
||||
|
@ -31,9 +31,4 @@ return [
|
|||
Type\StreamLogger::class => ['stream'],
|
||||
],
|
||||
],
|
||||
H::DECORATOR => [
|
||||
Log\LoggerInterface::class => [
|
||||
Type\ProfilerLogger::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
namespace Friendica\Test\Util\Hooks\InstanceMocks;
|
||||
|
||||
class FakeInstance
|
||||
class FakeInstance implements IAmADecoratedInterface
|
||||
{
|
||||
protected $aText = null;
|
||||
protected $cBool = null;
|
||||
|
@ -39,6 +39,8 @@ class FakeInstance
|
|||
$this->aText = $aText;
|
||||
$this->cBool = $cBool;
|
||||
$this->bText = $bText;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getAText(): ?string
|
||||
|
|
|
@ -25,14 +25,14 @@ class FakeInstanceDecorator implements IAmADecoratedInterface
|
|||
{
|
||||
public static $countInstance = 0;
|
||||
|
||||
const PREFIX = 'prefix1';
|
||||
|
||||
/** @var IAmADecoratedInterface */
|
||||
protected $orig;
|
||||
protected $prefix = '';
|
||||
|
||||
public function __construct(IAmADecoratedInterface $orig, string $prefix = '')
|
||||
public function __construct(IAmADecoratedInterface $orig)
|
||||
{
|
||||
$this->orig = $orig;
|
||||
$this->prefix = $prefix;
|
||||
|
||||
self::$countInstance++;
|
||||
}
|
||||
|
@ -44,16 +44,16 @@ class FakeInstanceDecorator implements IAmADecoratedInterface
|
|||
|
||||
public function getAText(): ?string
|
||||
{
|
||||
return $this->prefix . $this->orig->getAText();
|
||||
return static::PREFIX . $this->orig->getAText();
|
||||
}
|
||||
|
||||
public function getBText(): ?string
|
||||
{
|
||||
return $this->prefix . $this->orig->getBText();
|
||||
return static::PREFIX . $this->orig->getBText();
|
||||
}
|
||||
|
||||
public function getCBool(): ?bool
|
||||
{
|
||||
return $this->prefix . $this->orig->getCBool();
|
||||
return static::PREFIX . $this->orig->getCBool();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ class AddonLoaderTest extends MockedTest
|
|||
<?php
|
||||
|
||||
return [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
@ -79,7 +79,7 @@ EOF;
|
|||
'addon/testaddon1/static/hooks.config.php' => $this->content,
|
||||
],
|
||||
'assertion' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
@ -94,7 +94,7 @@ EOF;
|
|||
'addon/testaddon2/static/hooks.config.php' => $this->content,
|
||||
],
|
||||
'assertion' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => ['', ''],
|
||||
],
|
||||
|
@ -118,7 +118,7 @@ EOF;
|
|||
'addon/testaddon2/static/hooks.config.php' => $this->content,
|
||||
],
|
||||
'assertion' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
|
|
@ -22,25 +22,27 @@
|
|||
namespace Friendica\Test\src\Core\Hooks\Model;
|
||||
|
||||
use Dice\Dice;
|
||||
use Friendica\Core\Hooks\Exceptions\HookInstanceException;
|
||||
use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException;
|
||||
use Friendica\Core\Hooks\Model\DiceInstanceManager;
|
||||
use Friendica\Core\Hooks\Util\HookFileManager;
|
||||
use Friendica\Test\MockedTest;
|
||||
use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstance;
|
||||
use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstanceDecorator;
|
||||
use Friendica\Test\Util\Hooks\InstanceMocks\IAmADecoratedInterface;
|
||||
use Mockery\MockInterface;
|
||||
|
||||
class InstanceManagerTest extends MockedTest
|
||||
{
|
||||
public function testEqualButNotSameInstance()
|
||||
/** @var HookFileManager|MockInterface */
|
||||
protected $hookFileManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice());
|
||||
parent::setUp();
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class);
|
||||
|
||||
$getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake');
|
||||
$getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake');
|
||||
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
$this->hookFileManager = \Mockery::mock(HookFileManager::class);
|
||||
$this->hookFileManager->shouldReceive('setupHooks')->withAnyArgs();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
|
@ -50,6 +52,19 @@ class InstanceManagerTest extends MockedTest
|
|||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testEqualButNotSameInstance()
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice(), $this->hookFileManager);
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake');
|
||||
|
||||
$getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake');
|
||||
$getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake');
|
||||
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
}
|
||||
|
||||
public function dataTests(): array
|
||||
{
|
||||
return [
|
||||
|
@ -79,9 +94,9 @@ class InstanceManagerTest extends MockedTest
|
|||
/**
|
||||
* @dataProvider dataTests
|
||||
*/
|
||||
public function testInstanceWithConstructorAnonymArgs(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
public function testInstanceWithArgs(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice());
|
||||
$instance = new DiceInstanceManager(new Dice(), $this->hookFileManager);
|
||||
|
||||
$args = [];
|
||||
|
||||
|
@ -95,45 +110,12 @@ class InstanceManagerTest extends MockedTest
|
|||
$args[] = $cBool;
|
||||
}
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake');
|
||||
|
||||
/** @var IAmADecoratedInterface $getInstanceA */
|
||||
$getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake');
|
||||
$getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake', $args);
|
||||
/** @var IAmADecoratedInterface $getInstanceB */
|
||||
$getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake');
|
||||
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
self::assertEquals($aString, $getInstanceA->getAText());
|
||||
self::assertEquals($aString, $getInstanceB->getAText());
|
||||
self::assertEquals($bString, $getInstanceA->getBText());
|
||||
self::assertEquals($bString, $getInstanceB->getBText());
|
||||
self::assertEquals($cBool, $getInstanceA->getCBool());
|
||||
self::assertEquals($cBool, $getInstanceB->getCBool());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTests
|
||||
*/
|
||||
public function testInstanceConstructorAndGetInstanceWithNamedArgs(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice());
|
||||
|
||||
$args = [];
|
||||
|
||||
if (isset($aString)) {
|
||||
$args[] = $aString;
|
||||
}
|
||||
if (isset($cBool)) {
|
||||
$args[] = $cBool;
|
||||
}
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args);
|
||||
|
||||
/** @var IAmADecoratedInterface $getInstanceA */
|
||||
$getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]);
|
||||
/** @var IAmADecoratedInterface $getInstanceB */
|
||||
$getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]);
|
||||
$getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake', $args);
|
||||
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
|
@ -150,24 +132,27 @@ class InstanceManagerTest extends MockedTest
|
|||
*/
|
||||
public function testInstanceWithTwoStrategies(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice());
|
||||
$instance = new DiceInstanceManager(new Dice(), $this->hookFileManager);
|
||||
|
||||
$args = [];
|
||||
|
||||
if (isset($aString)) {
|
||||
$args[] = $aString;
|
||||
}
|
||||
if (isset($bString)) {
|
||||
$args[] = $bString;
|
||||
}
|
||||
if (isset($cBool)) {
|
||||
$args[] = $cBool;
|
||||
}
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake');
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake23');
|
||||
|
||||
/** @var IAmADecoratedInterface $getInstanceA */
|
||||
$getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]);
|
||||
$getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake', $args);
|
||||
/** @var IAmADecoratedInterface $getInstanceB */
|
||||
$getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake23', [$bString]);
|
||||
$getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake23', $args);
|
||||
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
|
@ -180,79 +165,74 @@ class InstanceManagerTest extends MockedTest
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTests
|
||||
* Test the exception in case the interface was already registered
|
||||
*/
|
||||
public function testDecorator(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
public function testDoubleRegister()
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice());
|
||||
self::expectException(HookRegisterArgumentException::class);
|
||||
self::expectExceptionMessage(sprintf('A class with the name %s is already set for the interface %s', 'fake', IAmADecoratedInterface::class));
|
||||
|
||||
$args = [];
|
||||
|
||||
if (isset($aString)) {
|
||||
$args[] = $aString;
|
||||
}
|
||||
if (isset($cBool)) {
|
||||
$args[] = $cBool;
|
||||
}
|
||||
|
||||
$prefix = 'prefix1';
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args);
|
||||
$instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]);
|
||||
|
||||
/** @var IAmADecoratedInterface $getInstanceA */
|
||||
$getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]);
|
||||
/** @var IAmADecoratedInterface $getInstanceB */
|
||||
$getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake23', [$bString]);
|
||||
|
||||
self::assertEquals(2, FakeInstanceDecorator::$countInstance);
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
self::assertEquals($prefix . $aString, $getInstanceA->getAText());
|
||||
self::assertEquals($prefix . $aString, $getInstanceB->getAText());
|
||||
self::assertEquals($prefix . $bString, $getInstanceA->getBText());
|
||||
self::assertEquals($prefix . $bString, $getInstanceB->getBText());
|
||||
self::assertEquals($prefix . $cBool, $getInstanceA->getCBool());
|
||||
self::assertEquals($prefix . $cBool, $getInstanceB->getCBool());
|
||||
$instance = new DiceInstanceManager(new Dice(), $this->hookFileManager);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake');
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the exception in case the name of the instance isn't registered
|
||||
*/
|
||||
public function testWrongInstanceName()
|
||||
{
|
||||
self::expectException(HookInstanceException::class );
|
||||
self::expectExceptionMessage(sprintf('The class with the name %s isn\'t registered for the class or interface %s', 'fake', IAmADecoratedInterface::class));
|
||||
|
||||
$instance = new DiceInstanceManager(new Dice(), $this->hookFileManager);
|
||||
$instance->create(IAmADecoratedInterface::class, 'fake');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test in case there are already some rules
|
||||
*
|
||||
* @dataProvider dataTests
|
||||
*/
|
||||
public function testTwoDecoratorWithPrefix(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
public function testWithGivenRules(string $aString = null, bool $cBool = null, string $bString = null)
|
||||
{
|
||||
$instance = new DiceInstanceManager(new Dice());
|
||||
|
||||
$args = [];
|
||||
|
||||
if (isset($aString)) {
|
||||
$args[] = $aString;
|
||||
}
|
||||
if (isset($bString)) {
|
||||
$args[] = $bString;
|
||||
}
|
||||
|
||||
$dice = (new Dice())->addRules([
|
||||
FakeInstance::class => [
|
||||
'constructParams' => $args,
|
||||
],
|
||||
]);
|
||||
|
||||
$args = [];
|
||||
|
||||
if (isset($cBool)) {
|
||||
$args[] = $cBool;
|
||||
}
|
||||
|
||||
$prefix = 'prefix1';
|
||||
$instance = new DiceInstanceManager($dice, $this->hookFileManager);
|
||||
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args);
|
||||
$instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]);
|
||||
$instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class);
|
||||
$instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake');
|
||||
|
||||
/** @var IAmADecoratedInterface $getInstanceA */
|
||||
$getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]);
|
||||
$getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake', $args);
|
||||
/** @var IAmADecoratedInterface $getInstanceB */
|
||||
$getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake23', [$bString]);
|
||||
$getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake', $args);
|
||||
|
||||
self::assertEquals(4, FakeInstanceDecorator::$countInstance);
|
||||
self::assertEquals($getInstanceA, $getInstanceB);
|
||||
self::assertNotSame($getInstanceA, $getInstanceB);
|
||||
self::assertEquals($prefix . $aString, $getInstanceA->getAText());
|
||||
self::assertEquals($prefix . $aString, $getInstanceB->getAText());
|
||||
self::assertEquals($prefix . $bString, $getInstanceA->getBText());
|
||||
self::assertEquals($prefix . $bString, $getInstanceB->getBText());
|
||||
self::assertEquals($prefix . $cBool, $getInstanceA->getCBool());
|
||||
self::assertEquals($prefix . $cBool, $getInstanceB->getCBool());
|
||||
self::assertEquals($aString, $getInstanceA->getAText());
|
||||
self::assertEquals($aString, $getInstanceB->getAText());
|
||||
self::assertEquals($bString, $getInstanceA->getBText());
|
||||
self::assertEquals($bString, $getInstanceB->getBText());
|
||||
self::assertEquals($cBool, $getInstanceA->getCBool());
|
||||
self::assertEquals($cBool, $getInstanceB->getCBool());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,12 +31,12 @@ class HookFileManagerTest extends MockedTest
|
|||
<?php
|
||||
|
||||
return [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
],
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::DECORATOR => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::DECORATOR => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class,
|
||||
],
|
||||
|
@ -56,12 +56,12 @@ EOF,
|
|||
<?php
|
||||
|
||||
return [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => '',
|
||||
],
|
||||
],
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::DECORATOR => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::DECORATOR => [
|
||||
\Psr\Log\LoggerInterface::class => \Psr\Log\NullLogger::class,
|
||||
],
|
||||
];
|
||||
|
@ -79,7 +79,7 @@ EOF,
|
|||
<?php
|
||||
|
||||
return [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
@ -87,7 +87,7 @@ return [
|
|||
];
|
||||
EOF,
|
||||
'addonsArray' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => ['null'],
|
||||
],
|
||||
|
@ -104,7 +104,7 @@ EOF,
|
|||
<?php
|
||||
|
||||
return [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
@ -112,7 +112,7 @@ return [
|
|||
];
|
||||
EOF,
|
||||
'addonsArray' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => 'null',
|
||||
],
|
||||
|
@ -130,7 +130,7 @@ EOF,
|
|||
<?php
|
||||
|
||||
return [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
@ -138,7 +138,7 @@ return [
|
|||
];
|
||||
EOF,
|
||||
'addonsArray' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
@ -163,7 +163,7 @@ return [
|
|||
];
|
||||
EOF,
|
||||
'addonsArray' => [
|
||||
\Friendica\Core\Hooks\Capabilities\HookType::STRATEGY => [
|
||||
\Friendica\Core\Hooks\Capabilities\BehavioralHookType::STRATEGY => [
|
||||
\Psr\Log\LoggerInterface::class => [
|
||||
\Psr\Log\NullLogger::class => [''],
|
||||
],
|
||||
|
|
Loading…
Reference in a new issue