From 14b76e48f085a48ea44812cdc9057c7404f0102a Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 2 Jul 2023 23:56:56 +0200 Subject: [PATCH] Introduce dynamic hook loading - Dynamically load addon files - Dynamically load hooks - Rewrite Logger-logic to use new hook logic (Monolog is working again) --- bin/auth_ejabberd.php | 6 +- bin/console.php | 6 +- bin/daemon.php | 6 +- bin/worker.php | 6 +- index.php | 3 + .../Addon/Capabilities/ICanLoadAddons.php | 37 ++++++ .../AddonInvalidConfigFileException.php} | 12 +- src/Core/Addon/Model/AddonLoader.php | 70 ++++++++++ src/Core/Hooks/Capabilities/HookType.php | 39 ++++++ .../Capabilities/ICanCreateInstances.php | 59 +++++++++ ...nstances.php => ICanRegisterInstances.php} | 40 ++---- .../Exceptions/HookConfigException.php} | 8 +- src/Core/Hooks/Model/DiceInstanceManager.php | 111 ++++++++++++++++ src/Core/Hooks/Model/InstanceManager.php | 104 --------------- src/Core/Hooks/Util/HookFileManager.php | 118 +++++++++++++++++ .../Capabilities/ICheckLoggerSettings.php | 42 ++++++ .../Capabilities/IHaveCallIntrospections.php | 2 +- src/Core/Logger/Capabilities/LogChannel.php | 43 +++++++ .../Logger/Exception/LogLevelException.php | 5 +- .../Exception/LoggerArgumentException.php | 5 +- src/Core/Logger/Exception/LoggerException.php | 5 +- .../Exception/LoggerUnusableException.php | 35 +++++ .../Factory/AbstractLoggerTypeFactory.php | 80 ++++++++++++ src/Core/Logger/Factory/Logger.php | 120 ++---------------- src/Core/Logger/Factory/ProfilerLogger.php | 53 ++++++++ src/Core/Logger/Factory/StreamLogger.php | 100 +++++++++++++++ src/Core/Logger/Factory/SyslogLogger.php | 60 +++++++++ src/Core/Logger/Type/README.md | 26 ---- src/Core/Logger/Type/StreamLogger.php | 81 ++---------- src/Core/Logger/Type/SyslogLogger.php | 29 ++--- src/{ => Core/Logger}/Util/FileSystem.php | 6 +- src/Core/Logger/Util/LoggerSettingsCheck.php | 91 +++++++++++++ src/DI.php | 23 ++-- src/Module/Admin/Summary.php | 36 +----- static/dependencies.config.php | 78 ++++++++---- static/hooks.config.php | 37 ++++++ .../Util/Hooks/InstanceMocks/FakeInstance.php | 4 +- .../Core/Hooks/Model/InstanceManagerTest.php | 38 +++--- tests/src/Core/Logger/StreamLoggerTest.php | 4 +- 39 files changed, 1161 insertions(+), 467 deletions(-) create mode 100644 src/Core/Addon/Capabilities/ICanLoadAddons.php rename src/Core/{Hooks/Capabilities/IAmAStrategy.php => Addon/Exception/AddonInvalidConfigFileException.php} (71%) create mode 100644 src/Core/Addon/Model/AddonLoader.php create mode 100644 src/Core/Hooks/Capabilities/HookType.php create mode 100644 src/Core/Hooks/Capabilities/ICanCreateInstances.php rename src/Core/Hooks/Capabilities/{ICanManageInstances.php => ICanRegisterInstances.php} (55%) rename src/Core/{Logger/Exception/LoggerInvalidException.php => Hooks/Exceptions/HookConfigException.php} (82%) create mode 100644 src/Core/Hooks/Model/DiceInstanceManager.php delete mode 100644 src/Core/Hooks/Model/InstanceManager.php create mode 100644 src/Core/Hooks/Util/HookFileManager.php create mode 100644 src/Core/Logger/Capabilities/ICheckLoggerSettings.php create mode 100644 src/Core/Logger/Capabilities/LogChannel.php create mode 100644 src/Core/Logger/Exception/LoggerUnusableException.php create mode 100644 src/Core/Logger/Factory/AbstractLoggerTypeFactory.php create mode 100644 src/Core/Logger/Factory/ProfilerLogger.php create mode 100644 src/Core/Logger/Factory/StreamLogger.php create mode 100644 src/Core/Logger/Factory/SyslogLogger.php delete mode 100644 src/Core/Logger/Type/README.md rename src/{ => Core/Logger}/Util/FileSystem.php (94%) create mode 100644 src/Core/Logger/Util/LoggerSettingsCheck.php create mode 100644 static/hooks.config.php diff --git a/bin/auth_ejabberd.php b/bin/auth_ejabberd.php index 40e7d3b97c..b923009e64 100755 --- a/bin/auth_ejabberd.php +++ b/bin/auth_ejabberd.php @@ -58,6 +58,7 @@ if (php_sapi_name() !== 'cli') { use Dice\Dice; use Friendica\App\Mode; +use Friendica\Core\Logger\Capabilities\LogChannel; use Friendica\Security\ExAuth; use Psr\Log\LoggerInterface; @@ -78,7 +79,10 @@ chdir($directory); require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]); +/** @var \Friendica\Core\Addon\Capabilities\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capabilities\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class,['constructParams' => [LogChannel::AUTH_JABBERED]]); \Friendica\DI::init($dice); \Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class)); diff --git a/bin/console.php b/bin/console.php index e1bc6b4985..b2cde10823 100755 --- a/bin/console.php +++ b/bin/console.php @@ -26,13 +26,17 @@ if (php_sapi_name() !== 'cli') { } use Dice\Dice; +use Friendica\Core\Logger\Capabilities\LogChannel; use Friendica\DI; use Psr\Log\LoggerInterface; require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]); +/** @var \Friendica\Core\Addon\Capabilities\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capabilities\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [LogChannel::CONSOLE]]); /// @fixme Necessary until Hooks inside the Logger can get loaded without the DI-class DI::init($dice); diff --git a/bin/daemon.php b/bin/daemon.php index e550aea891..1f0bb7079d 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -38,7 +38,6 @@ use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Util\DateTimeFormat; -use Psr\Log\LoggerInterface; // Get options $shortopts = 'f'; @@ -60,7 +59,10 @@ if (!file_exists('index.php') && (sizeof($_SERVER['argv']) != 0)) { require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]); +/** @var \Friendica\Core\Addon\Capabilities\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capabilities\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class,['constructParams' => [Logger\Capabilities\LogChannel::DAEMON]]); DI::init($dice); \Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class)); diff --git a/bin/worker.php b/bin/worker.php index a742132480..18a41e0643 100755 --- a/bin/worker.php +++ b/bin/worker.php @@ -29,6 +29,7 @@ if (php_sapi_name() !== 'cli') { use Dice\Dice; use Friendica\App; use Friendica\App\Mode; +use Friendica\Core\Logger\Capabilities\LogChannel; use Friendica\Core\Update; use Friendica\Core\Worker; use Friendica\DI; @@ -54,7 +55,10 @@ if (!file_exists("index.php") && (sizeof($_SERVER["argv"]) != 0)) { require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]); +/** @var \Friendica\Core\Addon\Capabilities\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capabilities\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class,['constructParams' => [LogChannel::WORKER]]); DI::init($dice); \Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class)); diff --git a/index.php b/index.php index 90df9c00e9..ce82470b64 100644 --- a/index.php +++ b/index.php @@ -30,6 +30,9 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) { require __DIR__ . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php'); +/** @var \Friendica\Core\Addon\Capabilities\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capabilities\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); $dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode', [false, $_SERVER], Dice::CHAIN_CALL]]]); \Friendica\DI::init($dice); diff --git a/src/Core/Addon/Capabilities/ICanLoadAddons.php b/src/Core/Addon/Capabilities/ICanLoadAddons.php new file mode 100644 index 0000000000..a28826ffb7 --- /dev/null +++ b/src/Core/Addon/Capabilities/ICanLoadAddons.php @@ -0,0 +1,37 @@ +. + * + */ + +namespace Friendica\Core\Addon\Capabilities; + +/** + * Interface for loading Addons specific content + */ +interface ICanLoadAddons +{ + /** + * Returns a merged config array of all active addons for a given config-name + * + * @param string $configName The config-name (config-file at the static directory, like 'hooks' => '{addon}/static/hooks.config.php) + * + * @return array the merged array + */ + public function getActiveAddonConfig(string $configName): array; +} diff --git a/src/Core/Hooks/Capabilities/IAmAStrategy.php b/src/Core/Addon/Exception/AddonInvalidConfigFileException.php similarity index 71% rename from src/Core/Hooks/Capabilities/IAmAStrategy.php rename to src/Core/Addon/Exception/AddonInvalidConfigFileException.php index 017cb56c4e..3bb41be53c 100644 --- a/src/Core/Hooks/Capabilities/IAmAStrategy.php +++ b/src/Core/Addon/Exception/AddonInvalidConfigFileException.php @@ -19,11 +19,17 @@ * */ -namespace Friendica\Core\Hooks\Capabilities; +namespace Friendica\Core\Addon\Exception; + +use Throwable; /** - * All classes, implementing this interface are valid Strategies for Hook calls + * Exception in case one or more config files of the addons are invalid */ -interface IAmAStrategy +class AddonInvalidConfigFileException extends \RuntimeException { + public function __construct($message = "", $code = 0, Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } } diff --git a/src/Core/Addon/Model/AddonLoader.php b/src/Core/Addon/Model/AddonLoader.php new file mode 100644 index 0000000000..707601aef8 --- /dev/null +++ b/src/Core/Addon/Model/AddonLoader.php @@ -0,0 +1,70 @@ +. + * + */ + +namespace Friendica\Core\Addon\Model; + +use Friendica\Core\Addon\Capabilities\ICanLoadAddons; +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Util\Strings; + +class AddonLoader implements ICanLoadAddons +{ + const STATIC_PATH = 'static'; + /** @var string */ + protected $basePath; + /** @var IManageConfigValues */ + protected $config; + + public function __construct(string $basePath, IManageConfigValues $config) + { + $this->basePath = $basePath; + $this->config = $config; + } + + /** {@inheritDoc} */ + public function getActiveAddonConfig(string $configName): array + { + $addons = array_keys(array_filter($this->config->get('addons') ?? [])); + $returnConfig = []; + + foreach ($addons as $addon) { + $addonName = Strings::sanitizeFilePathItem(trim($addon)); + + $configFile = $this->basePath . '/addon/' . $addonName . '/' . static::STATIC_PATH . '/' . $configName . '.config.php'; + + if (!file_exists($configFile)) { + // Addon unmodified, skipping + continue; + } + + $config = include $configFile; + + if (!is_array($config)) { + throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); + } + + $returnConfig = array_merge_recursive($returnConfig, $config); + } + + return $returnConfig; + } +} diff --git a/src/Core/Hooks/Capabilities/HookType.php b/src/Core/Hooks/Capabilities/HookType.php new file mode 100644 index 0000000000..6fea41e17a --- /dev/null +++ b/src/Core/Hooks/Capabilities/HookType.php @@ -0,0 +1,39 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capabilities; + +interface HookType +{ + /** + * Defines the key for the list of strategy-hooks. + * + * @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'; +} diff --git a/src/Core/Hooks/Capabilities/ICanCreateInstances.php b/src/Core/Hooks/Capabilities/ICanCreateInstances.php new file mode 100644 index 0000000000..6e5d8beb46 --- /dev/null +++ b/src/Core/Hooks/Capabilities/ICanCreateInstances.php @@ -0,0 +1,59 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capabilities; + +use Friendica\Core\Hooks\Exceptions\HookInstanceException; + +/** + * creates special instance and decorator treatments for given classes + */ +interface ICanCreateInstances +{ + /** + * Returns a new instance of a given class for the corresponding name + * + * 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; +} diff --git a/src/Core/Hooks/Capabilities/ICanManageInstances.php b/src/Core/Hooks/Capabilities/ICanRegisterInstances.php similarity index 55% rename from src/Core/Hooks/Capabilities/ICanManageInstances.php rename to src/Core/Hooks/Capabilities/ICanRegisterInstances.php index bdad1b9235..23a77ab35b 100644 --- a/src/Core/Hooks/Capabilities/ICanManageInstances.php +++ b/src/Core/Hooks/Capabilities/ICanRegisterInstances.php @@ -21,61 +21,43 @@ namespace Friendica\Core\Hooks\Capabilities; -use Friendica\Core\Hooks\Exceptions\HookInstanceException; use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; /** - * Managing special instance and decorator treatments for classes + * Register strategies and decorator/treatment handling for given classes */ -interface ICanManageInstances +interface ICanRegisterInstances { /** * Register a class(strategy) for a given interface with a unique name. * * @see https://refactoring.guru/design-patterns/strategy * - * @param string $interface The interface, which the given class implements - * @param string $name An arbitrary identifier for the given class, which will be used for factories, dependency injections etc. - * @param string $class The fully-qualified given class name - * @param ?array $arguments Additional arguments, which can be passed to the constructor + * @param string $interface The interface, which the given class implements + * @param string $class The fully-qualified given class name + * A placeholder for dependencies is possible as well + * @param ?string $name An arbitrary identifier for the given class, which will be used for factories, dependency injections etc. * * @return $this This interface for chain-calls * * @throws HookRegisterArgumentException in case the given class for the interface isn't valid or already set */ - public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): self; + 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 + * + * @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 - * @param array $arguments Additional arguments, which can be passed to the constructor of "decoratorClass" + * 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, array $arguments = []): self; - - /** - * Returns a new instance of a given class for the corresponding name - * - * 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" - * - * @throws HookInstanceException In case the class cannot get created - */ - public function getInstance(string $class, string $name, array $arguments = []): object; + public function registerDecorator(string $class, string $decoratorClass): self; } diff --git a/src/Core/Logger/Exception/LoggerInvalidException.php b/src/Core/Hooks/Exceptions/HookConfigException.php similarity index 82% rename from src/Core/Logger/Exception/LoggerInvalidException.php rename to src/Core/Hooks/Exceptions/HookConfigException.php index db6ecb78c5..ceca721b1d 100644 --- a/src/Core/Logger/Exception/LoggerInvalidException.php +++ b/src/Core/Hooks/Exceptions/HookConfigException.php @@ -19,13 +19,11 @@ * */ -namespace Friendica\Core\Logger\Exception; +namespace Friendica\Core\Hooks\Exceptions; -use Throwable; - -class LoggerInvalidException extends \RuntimeException +class HookConfigException extends \RuntimeException { - public function __construct($message = "", Throwable $previous = null) + public function __construct($message = "", \Throwable $previous = null) { parent::__construct($message, 500, $previous); } diff --git a/src/Core/Hooks/Model/DiceInstanceManager.php b/src/Core/Hooks/Model/DiceInstanceManager.php new file mode 100644 index 0000000000..381e0a7fe5 --- /dev/null +++ b/src/Core/Hooks/Model/DiceInstanceManager.php @@ -0,0 +1,111 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Model; + +use Dice\Dice; +use Friendica\Core\Hooks\Capabilities\ICanCreateInstances; +use Friendica\Core\Hooks\Capabilities\ICanRegisterInstances; +use Friendica\Core\Hooks\Exceptions\HookInstanceException; +use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; +use Friendica\Core\Hooks\Util\HookFileManager; + +/** + * This class represents an instance register, which uses Dice for creation + * + * @see Dice + */ +class DiceInstanceManager implements ICanCreateInstances, ICanRegisterInstances +{ + protected $instance = []; + protected $decorator = []; + + /** @var Dice */ + protected $dice; + + public function __construct(Dice $dice, HookFileManager $hookFileManager) + { + $this->dice = $dice; + $hookFileManager->setupHooks($this); + } + + /** {@inheritDoc} */ + public function registerStrategy(string $interface, string $class, ?string $name = null): ICanRegisterInstances + { + if (!empty($this->instance[$interface][$name])) { + throw new HookRegisterArgumentException(sprintf('A class with the name %s is already set for the interface %s', $name, $interface)); + } + + $this->instance[$interface][$name] = $class; + + return $this; + } + + /** {@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 + { + 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); + } +} diff --git a/src/Core/Hooks/Model/InstanceManager.php b/src/Core/Hooks/Model/InstanceManager.php deleted file mode 100644 index 7bfcfa420d..0000000000 --- a/src/Core/Hooks/Model/InstanceManager.php +++ /dev/null @@ -1,104 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Hooks\Model; - -use Dice\Dice; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; -use Friendica\Core\Hooks\Capabilities\ICanManageInstances; -use Friendica\Core\Hooks\Exceptions\HookInstanceException; -use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; - -/** {@inheritDoc} */ -class InstanceManager implements ICanManageInstances -{ - protected $instance = []; - protected $instanceArguments = []; - protected $decorator = []; - - /** @var Dice */ - protected $dice; - - public function __construct(Dice $dice) - { - $this->dice = $dice; - } - - /** {@inheritDoc} */ - public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): ICanManageInstances - { - if (!is_a($class, $interface, true)) { - throw new HookRegisterArgumentException(sprintf('%s is not a valid class for the interface %s', $class, $interface)); - } - - if (!is_a($class, IAmAStrategy::class, true)) { - throw new HookRegisterArgumentException(sprintf('%s does not inherit from the marker interface %s', $class, IAmAStrategy::class)); - } - - if (!empty($this->instance[$interface][$name])) { - throw new HookRegisterArgumentException(sprintf('A class with the name %s is already set for the interface %s', $name, $interface)); - } - - $this->instance[$interface][$name] = $class; - $this->instanceArguments[$interface][$name] = $arguments; - - return $this; - } - - /** {@inheritDoc} */ - public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): ICanManageInstances - { - if (!is_a($decoratorClass, $class, true)) { - throw new HookRegisterArgumentException(sprintf('%s is not a valid substitution for the given class or interface %s', $decoratorClass, $class)); - } - - $this->decorator[$class][] = [ - 'class' => $decoratorClass, - 'arguments' => $arguments, - ]; - - return $this; - } - - /** {@inheritDoc} */ - public function getInstance(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)); - } - - $instance = $this->dice->create($this->instance[$class][$name], array_merge($this->instanceArguments[$class][$name] ?? [], $arguments)); - - foreach ($this->decorator[$class] ?? [] as $decorator) { - $this->dice = $this->dice->addRule($class, [ - 'instanceOf' => $decorator['class'], - 'constructParams' => empty($decorator['arguments']) ? null : $decorator['arguments'], - /// @todo maybe support call structures for hooks as well in a later stage - could make factory calls easier - 'call' => null, - 'substitutions' => [$class => $instance], - ]); - - $instance = $this->dice->create($class); - } - - return $instance; - } -} diff --git a/src/Core/Hooks/Util/HookFileManager.php b/src/Core/Hooks/Util/HookFileManager.php new file mode 100644 index 0000000000..3575678577 --- /dev/null +++ b/src/Core/Hooks/Util/HookFileManager.php @@ -0,0 +1,118 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Util; + +use Friendica\Core\Addon\Capabilities\ICanLoadAddons; +use Friendica\Core\Hooks\Capabilities\HookType; +use Friendica\Core\Hooks\Capabilities\ICanRegisterInstances; +use Friendica\Core\Hooks\Exceptions\HookConfigException; + +/** + * Manage all hooks.config.php files + */ +class HookFileManager +{ + const STATIC_DIR = 'static'; + const CONFIG_NAME = 'hooks'; + + /** @var ICanLoadAddons */ + protected $addonLoader; + /** @var array */ + protected $hookConfig = []; + /** @var string */ + protected $basePath; + + public function __construct(string $basePath, ICanLoadAddons $addonLoader) + { + $this->basePath = $basePath; + $this->addonLoader = $addonLoader; + } + + /** + * Loads all kinds of hooks and registers the corresponding instances + * + * @param ICanRegisterInstances $instanceRegister The instance register + * + * @return void + */ + public function setupHooks(ICanRegisterInstances $instanceRegister) + { + // In case it wasn't used before, reload the whole hook config + if (empty($this->hookConfig)) { + $this->reloadHookConfig(); + } + + foreach ($this->hookConfig as $hookType => $classList) { + switch ($hookType) { + case HookType::STRATEGY: + foreach ($classList as $interface => $strategy) { + foreach ($strategy as $dependencyName => $names) { + if (is_array($names)) { + foreach ($names as $name) { + $instanceRegister->registerStrategy($interface, $dependencyName, $name); + } + } else { + $instanceRegister->registerStrategy($interface, $dependencyName, $names); + } + } + } + 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; + } + } + } + + /** + * Reloads all hook config files into the config cache for later usage + * + * Merges all hook configs from every addon - if present - as well + * + * @return void + */ + protected function reloadHookConfig() + { + // load core hook config + $configFile = $this->basePath . '/' . static::STATIC_DIR . '/' . static::CONFIG_NAME . '.config.php'; + + if (!file_exists($configFile)) { + throw new HookConfigException(sprintf('config file %s does not exit.', $configFile)); + } + + $config = include $configFile; + + if (!is_array($config)) { + throw new HookConfigException('Error loading config file ' . $configFile); + } + + $this->hookConfig = array_merge_recursive($config, $this->addonLoader->getActiveAddonConfig(static::CONFIG_NAME)); + } +} diff --git a/src/Core/Logger/Capabilities/ICheckLoggerSettings.php b/src/Core/Logger/Capabilities/ICheckLoggerSettings.php new file mode 100644 index 0000000000..532425ec06 --- /dev/null +++ b/src/Core/Logger/Capabilities/ICheckLoggerSettings.php @@ -0,0 +1,42 @@ +. + * + */ + +namespace Friendica\Core\Logger\Capabilities; + +/** + * Whenever a logging specific check is necessary, use this interface to encapsulate and centralize this logic + */ +interface ICheckLoggerSettings +{ + /** + * Checks if the logfile is set and usable + * + * @return string|null null in case everything is ok, otherwise returns the error + */ + public function checkLogfile(): ?string; + + /** + * Checks if the debugging logfile is usable in case it is set! + * + * @return string|null null in case everything is ok, otherwise returns the error + */ + public function checkDebugLogfile(): ?string; +} diff --git a/src/Core/Logger/Capabilities/IHaveCallIntrospections.php b/src/Core/Logger/Capabilities/IHaveCallIntrospections.php index 83d75f976f..7f884bf647 100644 --- a/src/Core/Logger/Capabilities/IHaveCallIntrospections.php +++ b/src/Core/Logger/Capabilities/IHaveCallIntrospections.php @@ -2,7 +2,7 @@ /** * @copyright Copyright (C) 2010-2023, the Friendica project * - * @license GNU AGPL version 3 or any later version + * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as diff --git a/src/Core/Logger/Capabilities/LogChannel.php b/src/Core/Logger/Capabilities/LogChannel.php new file mode 100644 index 0000000000..54ae032172 --- /dev/null +++ b/src/Core/Logger/Capabilities/LogChannel.php @@ -0,0 +1,43 @@ +. + * + */ + +namespace Friendica\Core\Logger\Capabilities; + +/** + * An enum class for the Log channels + */ +interface LogChannel +{ + /** @var string channel for the auth_ejabbered script */ + public const AUTH_JABBERED = 'auth_ejabberd'; + /** @var string Default channel in case it isn't set explicit */ + public const DEFAULT = self::APP; + /** @var string channel for console execution */ + public const CONSOLE = 'console'; + /** @var string channel for developer focused logging */ + public const DEV = 'dev'; + /** @var string channel for daemon executions */ + public const DAEMON = 'daemon'; + /** @var string channel for worker execution */ + public const WORKER = 'worker'; + /** @var string channel for frontend app executions */ + public const APP = 'app'; +} diff --git a/src/Core/Logger/Exception/LogLevelException.php b/src/Core/Logger/Exception/LogLevelException.php index 36b2c31cf3..39b2d17a94 100644 --- a/src/Core/Logger/Exception/LogLevelException.php +++ b/src/Core/Logger/Exception/LogLevelException.php @@ -2,7 +2,7 @@ /** * @copyright Copyright (C) 2010-2023, the Friendica project * - * @license GNU AGPL version 3 or any later version + * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -23,6 +23,9 @@ namespace Friendica\Core\Logger\Exception; use Throwable; +/** + * Exception in case the loglevel isn't set or isn't valid + */ class LogLevelException extends \InvalidArgumentException { public function __construct($message = "", Throwable $previous = null) diff --git a/src/Core/Logger/Exception/LoggerArgumentException.php b/src/Core/Logger/Exception/LoggerArgumentException.php index a0b9949b08..08eabe84a7 100644 --- a/src/Core/Logger/Exception/LoggerArgumentException.php +++ b/src/Core/Logger/Exception/LoggerArgumentException.php @@ -2,7 +2,7 @@ /** * @copyright Copyright (C) 2010-2023, the Friendica project * - * @license GNU AGPL version 3 or any later version + * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -23,6 +23,9 @@ namespace Friendica\Core\Logger\Exception; use Throwable; +/** + * Exception in case an argument of a logger class isn't valid + */ class LoggerArgumentException extends \InvalidArgumentException { public function __construct($message = "", Throwable $previous = null) diff --git a/src/Core/Logger/Exception/LoggerException.php b/src/Core/Logger/Exception/LoggerException.php index 7e3637327a..13bcff8f3c 100644 --- a/src/Core/Logger/Exception/LoggerException.php +++ b/src/Core/Logger/Exception/LoggerException.php @@ -2,7 +2,7 @@ /** * @copyright Copyright (C) 2010-2023, the Friendica project * - * @license GNU AGPL version 3 or any later version + * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -23,6 +23,9 @@ namespace Friendica\Core\Logger\Exception; use Throwable; +/** + * A generic exception of the logging namespace + */ class LoggerException extends \Exception { public function __construct($message = "", Throwable $previous = null) diff --git a/src/Core/Logger/Exception/LoggerUnusableException.php b/src/Core/Logger/Exception/LoggerUnusableException.php new file mode 100644 index 0000000000..29336e086b --- /dev/null +++ b/src/Core/Logger/Exception/LoggerUnusableException.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Core\Logger\Exception; + +use Throwable; + +/** + * Exception in case the used logging instance is unusable because of some circumstances + */ +class LoggerUnusableException extends \RuntimeException +{ + public function __construct($message = "", Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Core/Logger/Factory/AbstractLoggerTypeFactory.php b/src/Core/Logger/Factory/AbstractLoggerTypeFactory.php new file mode 100644 index 0000000000..a6ff5eebbc --- /dev/null +++ b/src/Core/Logger/Factory/AbstractLoggerTypeFactory.php @@ -0,0 +1,80 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; +use Psr\Log\LogLevel; + +/** + * Abstract class for creating logger types, which includes common necessary logic/content + */ +abstract class AbstractLoggerTypeFactory +{ + /** @var string */ + protected $channel; + /** @var IHaveCallIntrospections */ + protected $introspection; + + /** + * @param string $channel The channel for the logger + */ + public function __construct(IHaveCallIntrospections $introspection, string $channel) + { + $this->channel = $channel; + $this->introspection = $introspection; + } + + /** + * Mapping a legacy level to the PSR-3 compliant levels + * + * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel + * + * @param string $level the level to be mapped + * + * @return string the PSR-3 compliant level + */ + protected static function mapLegacyConfigDebugLevel(string $level): string + { + switch ($level) { + // legacy WARNING + case "0": + return LogLevel::ERROR; + // legacy INFO + case "1": + return LogLevel::WARNING; + // legacy TRACE + case "2": + return LogLevel::NOTICE; + // legacy DEBUG + case "3": + return LogLevel::INFO; + // legacy DATA + case "4": + // legacy ALL + case "5": + return LogLevel::DEBUG; + // default if nothing set + default: + return $level; + } + } +} diff --git a/src/Core/Logger/Factory/Logger.php b/src/Core/Logger/Factory/Logger.php index 2821a813c2..3fde878a34 100644 --- a/src/Core/Logger/Factory/Logger.php +++ b/src/Core/Logger/Factory/Logger.php @@ -22,134 +22,38 @@ namespace Friendica\Core\Logger\Factory; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hooks\Capabilities\ICanManageInstances; -use Friendica\Core\Logger\Exception\LogLevelException; -use Friendica\Core\Logger\Type\ProfilerLogger; -use Friendica\Core\Logger\Type\StreamLogger; -use Friendica\Core\Logger\Type\SyslogLogger; +use Friendica\Core\Hooks\Capabilities\ICanCreateInstances; +use Friendica\Core\Logger\Capabilities\LogChannel; use Psr\Log\LoggerInterface; -use Psr\Log\LogLevel; use Psr\Log\NullLogger; +use Throwable; /** - * A logger factory + * The logger factory for the core logging instances */ class Logger { - const DEV_CHANNEL = 'dev'; - - /** @var string The log-channel (app, worker, ...) */ + /** @var string The channel */ protected $channel; - /** @var ICanManageInstances */ - protected $instanceManager; - /** @var IManageConfigValues */ - protected $config; - public function __construct(string $channel, ICanManageInstances $instanceManager, IManageConfigValues $config, string $logfile = null) + public function __construct(string $channel = LogChannel::DEFAULT) { - $this->channel = $channel; - $this->instanceManager = $instanceManager; - $this->config = $config; - - $this->instanceManager - ->registerStrategy(LoggerInterface::class, 'syslog', SyslogLogger::class) - ->registerStrategy(LoggerInterface::class, 'stream', StreamLogger::class, isset($logfile) ? [$logfile] : null); - - if ($this->config->get('system', 'profiling') ?? false) { - $this->instanceManager->registerDecorator(LoggerInterface::class, ProfilerLogger::class); - } + $this->channel = $channel; } - /** - * Creates a new PSR-3 compliant logger instances - * - * @param string|null $loglevel (optional) A given loglevel in case the loglevel in the config isn't applicable - * - * @return LoggerInterface The PSR-3 compliant logger instance - */ - public function create(string $loglevel = null): LoggerInterface + public function create(ICanCreateInstances $createInstances, IManageConfigValues $config): LoggerInterface { - if (empty($this->config->get('system', 'debugging') ?? false)) { + if (empty($config->get('system', 'debugging') ?? false)) { return new NullLogger(); } - $loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($this->config->get('system', 'loglevel')); - $name = $this->config->get('system', 'logger_config') ?? 'stream'; + $name = $config->get('system', 'logger_config') ?? ''; try { - /** @var LoggerInterface */ - return $this->instanceManager->getInstance(LoggerInterface::class, $name, [$this->channel, $loglevel]); - } catch (LogLevelException $exception) { - // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create(LogLevel::NOTICE); - $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); - return $logger; - } catch (\Throwable $e) { + return $createInstances->createWithName(LoggerInterface::class, $name, [$this->channel]); + } catch (Throwable $e) { // No logger ... return new NullLogger(); } } - - /** - * Creates a new PSR-3 compliant develop logger - * - * If you want to debug only interactions from your IP or the IP of a remote server for federation debug, - * you'll use this logger instance for the duration of your work. - * - * It should never get filled during normal usage of Friendica - * - * @return LoggerInterface The PSR-3 compliant logger instance - * @throws \Exception - */ - public function createDev() - { - $debugging = $this->config->get('system', 'debugging'); - $stream = $this->config->get('system', 'dlogfile'); - $developerIp = $this->config->get('system', 'dlogip'); - - if ((!isset($developerIp) || !$debugging) && - (!is_file($stream) || is_writable($stream))) { - return new NullLogger(); - } - - $name = $this->config->get('system', 'logger_config') ?? 'stream'; - - /** @var LoggerInterface */ - return $this->instanceManager->getInstance(LoggerInterface::class, $name, [self::DEV_CHANNEL, LogLevel::DEBUG, $stream]); - } - - /** - * Mapping a legacy level to the PSR-3 compliant levels - * - * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel - * - * @param string $level the level to be mapped - * - * @return string the PSR-3 compliant level - */ - private static function mapLegacyConfigDebugLevel(string $level): string - { - switch ($level) { - // legacy WARNING - case "0": - return LogLevel::ERROR; - // legacy INFO - case "1": - return LogLevel::WARNING; - // legacy TRACE - case "2": - return LogLevel::NOTICE; - // legacy DEBUG - case "3": - return LogLevel::INFO; - // legacy DATA - case "4": - // legacy ALL - case "5": - return LogLevel::DEBUG; - // default if nothing set - default: - return $level; - } - } } diff --git a/src/Core/Logger/Factory/ProfilerLogger.php b/src/Core/Logger/Factory/ProfilerLogger.php new file mode 100644 index 0000000000..3d126921d6 --- /dev/null +++ b/src/Core/Logger/Factory/ProfilerLogger.php @@ -0,0 +1,53 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Type\ProfilerLogger as ProfilerLoggerClass; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +/** + * The logger factory for the ProfilerLogger + * + * @see ProfilerLoggerClass + */ +class ProfilerLogger extends AbstractLoggerTypeFactory +{ + /** + * Wraps a given Logger with profiling information in case profiling is enabled + * + * @param IManageConfigValues $config The system configuration + * @param LoggerInterface $logger The given logger class, which should get wrapped + * @param Profiler $profiler The profiler utility + * + * @return LoggerInterface The PSR-3 compliant logger instance + */ + public function create(IManageConfigValues $config, LoggerInterface $logger, Profiler $profiler): LoggerInterface + { + if ($config->get('system', 'profiling') ?? false) { + return $logger; + } else { + return new ProfilerLoggerClass($logger, $profiler); + } + } +} diff --git a/src/Core/Logger/Factory/StreamLogger.php b/src/Core/Logger/Factory/StreamLogger.php new file mode 100644 index 0000000000..85475b3af4 --- /dev/null +++ b/src/Core/Logger/Factory/StreamLogger.php @@ -0,0 +1,100 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Capabilities\LogChannel; +use Friendica\Core\Logger\Exception\LoggerArgumentException; +use Friendica\Core\Logger\Exception\LoggerException; +use Friendica\Core\Logger\Type\StreamLogger as StreamLoggerClass; +use Friendica\Core\Logger\Util\FileSystem; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; + +/** + * The logger factory for the StreamLogger instance + * + * @see StreamLoggerClass + */ +class StreamLogger extends AbstractLoggerTypeFactory +{ + /** + * Creates a new PSR-3 compliant stream logger instance + * + * @param IManageConfigValues $config The system configuration + * @param string|null $logfile (optional) A given logfile which should be used as stream (e.g. in case of + * developer logging) + * @param string|null $channel (optional) A given channel in case it is different from the default + * + * @return LoggerInterface The PSR-3 compliant logger instance + * + * @throws LoggerException in case the logger cannot get created + */ + public function create(IManageConfigValues $config, string $logfile = null, string $channel = null): LoggerInterface + { + $fileSystem = new FileSystem(); + + $logfile = $logfile ?? $config->get('system', 'logfile'); + if ((@file_exists($logfile) && !@is_writable($logfile)) && !@is_writable(basename($logfile))) { + throw new LoggerArgumentException(sprintf('%s is not a valid logfile', $logfile)); + } + + $loglevel = static::mapLegacyConfigDebugLevel($config->get('system', 'loglevel')); + + if (array_key_exists($loglevel, StreamLoggerClass::levelToInt)) { + $loglevel = StreamLoggerClass::levelToInt[$loglevel]; + } else { + $loglevel = StreamLoggerClass::levelToInt[LogLevel::NOTICE]; + } + + $stream = $fileSystem->createStream($logfile); + + return new StreamLoggerClass($channel ?? $this->channel, $this->introspection, $stream, $loglevel, getmypid()); + } + + /** + * Creates a new PSR-3 compliant develop logger + * + * If you want to debug only interactions from your IP or the IP of a remote server for federation debug, + * you'll use this logger instance for the duration of your work. + * + * It should never get filled during normal usage of Friendica + * + * @return LoggerInterface The PSR-3 compliant logger instance + * + * @throws LoggerException + */ + public function createDev(IManageConfigValues $config) + { + $debugging = $config->get('system', 'debugging'); + $logfile = $config->get('system', 'dlogfile'); + $developerIp = $config->get('system', 'dlogip'); + + if ((!isset($developerIp) || !$debugging) && + (!is_file($logfile) || is_writable($logfile))) { + return new NullLogger(); + } + + return $this->create($config, $logfile, LogChannel::DEV); + } +} diff --git a/src/Core/Logger/Factory/SyslogLogger.php b/src/Core/Logger/Factory/SyslogLogger.php new file mode 100644 index 0000000000..5a87895849 --- /dev/null +++ b/src/Core/Logger/Factory/SyslogLogger.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Exception\LoggerException; +use Friendica\Core\Logger\Type\SyslogLogger as SyslogLoggerClass; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; + +/** + * The logger factory for the SyslogLogger instance + * + * @see SyslogLoggerClass + */ +class SyslogLogger extends AbstractLoggerTypeFactory +{ + /** + * Creates a new PSR-3 compliant syslog logger instance + * + * @param IManageConfigValues $config The system configuration + * + * @return LoggerInterface The PSR-3 compliant logger instance + * + * @throws LoggerException in case the logger cannot get created + */ + public function create(IManageConfigValues $config): LoggerInterface + { + $logOpts = $config->get('system', 'syslog_flags') ?? SyslogLoggerClass::DEFAULT_FLAGS; + $logFacility = $config->get('system', 'syslog_facility') ?? SyslogLoggerClass::DEFAULT_FACILITY; + $loglevel = SyslogLogger::mapLegacyConfigDebugLevel($config->get('system', 'loglevel')); + + if (!array_key_exists($loglevel, SyslogLoggerClass::logLevels)) { + $loglevel = SyslogLoggerClass::logLevels[$loglevel]; + } else { + $loglevel = SyslogLoggerClass::logLevels[LogLevel::NOTICE]; + } + + return new SyslogLoggerClass($this->channel, $this->introspection, $loglevel, $logOpts, $logFacility); + } +} diff --git a/src/Core/Logger/Type/README.md b/src/Core/Logger/Type/README.md deleted file mode 100644 index b204353c04..0000000000 --- a/src/Core/Logger/Type/README.md +++ /dev/null @@ -1,26 +0,0 @@ -## Friendica\Util\Logger - -This namespace contains the different implementations of a Logger. - -### Configuration guideline - -The following settings are possible for `logger_config`: -- [`stream`](StreamLogger.php): A small logger for files or streams -- [`syslog`](SyslogLogger.php): Prints the logging output into the syslog - -[`VoidLogger`](VoidLogger.php) is a fallback logger without any function if no debugging is enabled. - -[`ProfilerLogger`](ProfilerLogger.php) is a wrapper around an existing logger in case profiling is enabled for Friendica. -Every log call will be saved to the `Profiler` with a timestamp. - -### Implementation guideline - -Each logging implementation should pe capable of printing at least the following information: -- An unique ID for each Request/Call -- The process ID (PID) -- A timestamp of the logging entry -- The critically of the log entry -- A log message -- A context of the log message (f.e which user) - -If possible, a Logger should extend [`AbstractLogger`](AbstractLogger.php), because it contains additional, Friendica specific business logic for each logging call. diff --git a/src/Core/Logger/Type/StreamLogger.php b/src/Core/Logger/Type/StreamLogger.php index d56f5b20ef..87f1a3937f 100644 --- a/src/Core/Logger/Type/StreamLogger.php +++ b/src/Core/Logger/Type/StreamLogger.php @@ -21,20 +21,16 @@ namespace Friendica\Core\Logger\Type; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; -use Friendica\Core\Logger\Exception\LoggerArgumentException; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Util\DateTimeFormat; -use Friendica\Util\FileSystem; use Psr\Log\LogLevel; /** * A Logger instance for logging into a stream (file, stdout, stderr) */ -class StreamLogger extends AbstractLogger implements IAmAStrategy +class StreamLogger extends AbstractLogger { /** * The minimum loglevel at which this logger will be triggered @@ -42,12 +38,6 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy */ private $logLevel; - /** - * The file URL of the stream (if needed) - * @var string - */ - private $url; - /** * The stream, where the current logger is writing into * @var resource @@ -60,16 +50,11 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy */ private $pid; - /** - * @var FileSystem - */ - private $fileSystem; - /** * Translates LogLevel log levels to integer values * @var array */ - private $levelToInt = [ + public const levelToInt = [ LogLevel::EMERGENCY => 0, LogLevel::ALERT => 1, LogLevel::CRITICAL => 2, @@ -84,41 +69,20 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy * {@inheritdoc} * @param string $level The minimum loglevel at which this logger will be triggered * - * @throws LoggerArgumentException - * @throws LogLevelException + * @throws LoggerException */ - public function __construct(string $channel, IManageConfigValues $config, IHaveCallIntrospections $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) + public function __construct(string $channel, IHaveCallIntrospections $introspection, $stream, int $logLevel, int $pid) { - $this->fileSystem = $fileSystem; - - $stream = $this->logfile ?? $config->get('system', 'logfile'); - if ((@file_exists($stream) && !@is_writable($stream)) && !@is_writable(basename($stream))) { - throw new LoggerArgumentException(sprintf('%s is not a valid logfile', $stream)); - } - parent::__construct($channel, $introspection); - if (is_resource($stream)) { - $this->stream = $stream; - } elseif (is_string($stream)) { - $this->url = $stream; - } else { - throw new LoggerArgumentException('A stream must either be a resource or a string.'); - } - - $this->pid = getmypid(); - if (array_key_exists($level, $this->levelToInt)) { - $this->logLevel = $this->levelToInt[$level]; - } else { - throw new LogLevelException(sprintf('The level "%s" is not valid.', $level)); - } - - $this->checkStream(); + $this->stream = $stream; + $this->pid = $pid; + $this->logLevel = $logLevel; } public function close() { - if ($this->url && is_resource($this->stream)) { + if (is_resource($this->stream)) { fclose($this->stream); } @@ -139,18 +103,16 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy */ protected function addEntry($level, string $message, array $context = []) { - if (!array_key_exists($level, $this->levelToInt)) { + if (!array_key_exists($level, static::levelToInt)) { throw new LogLevelException(sprintf('The level "%s" is not valid.', $level)); } - $logLevel = $this->levelToInt[$level]; + $logLevel = static::levelToInt[$level]; if ($logLevel > $this->logLevel) { return; } - $this->checkStream(); - $formattedLog = $this->formatLog($level, $message, $context); fwrite($this->stream, $formattedLog); } @@ -185,27 +147,4 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy return $logMessage; } - - /** - * Checks the current stream - * - * @throws LoggerException - * @throws LoggerArgumentException - */ - private function checkStream() - { - if (is_resource($this->stream)) { - return; - } - - if (empty($this->url)) { - throw new LoggerArgumentException('Missing stream URL.'); - } - - try { - $this->stream = $this->fileSystem->createStream($this->url); - } catch (\UnexpectedValueException $exception) { - throw new LoggerException('Cannot create stream.', $exception); - } - } } diff --git a/src/Core/Logger/Type/SyslogLogger.php b/src/Core/Logger/Type/SyslogLogger.php index 3c9ab581a0..88dc1964dd 100644 --- a/src/Core/Logger/Type/SyslogLogger.php +++ b/src/Core/Logger/Type/SyslogLogger.php @@ -21,8 +21,6 @@ namespace Friendica\Core\Logger\Type; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; @@ -32,7 +30,7 @@ use Psr\Log\LogLevel; * A Logger instance for syslogging (fast, but simple) * @see http://php.net/manual/en/function.syslog.php */ -class SyslogLogger extends AbstractLogger implements IAmAStrategy +class SyslogLogger extends AbstractLogger { const IDENT = 'Friendica'; @@ -45,7 +43,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy * Translates LogLevel log levels to syslog log priorities. * @var array */ - private $logLevels = [ + public const logLevels = [ LogLevel::DEBUG => LOG_DEBUG, LogLevel::INFO => LOG_INFO, LogLevel::NOTICE => LOG_NOTICE, @@ -60,7 +58,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy * Translates log priorities to string outputs * @var array */ - private $logToString = [ + protected const logToString = [ LOG_DEBUG => 'DEBUG', LOG_INFO => 'INFO', LOG_NOTICE => 'NOTICE', @@ -101,19 +99,18 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy /** * {@inheritdoc} - * @param string $level The minimum loglevel at which this logger will be triggered * - * @throws LogLevelException - * @throws LoggerException + * @param string $logLevel The minimum loglevel at which this logger will be triggered + * @param string $logOptions + * @param string $logFacility */ - public function __construct(string $channel, IManageConfigValues $config, IHaveCallIntrospections $introspection, string $level = LogLevel::NOTICE) + public function __construct(string $channel, IHaveCallIntrospections $introspection, string $logLevel, string $logOptions, string $logFacility) { parent::__construct($channel, $introspection); - $this->logOpts = $config->get('system', 'syslog_flags') ?? static::DEFAULT_FLAGS; - $this->logFacility = $config->get('system', 'syslog_facility') ?? static::DEFAULT_FACILITY; - $this->logLevel = $this->mapLevelToPriority($level); - $this->introspection->addClasses([self::class]); + $this->logOpts = $logOptions; + $this->logFacility = $logFacility; + $this->logLevel = $logLevel; } /** @@ -149,11 +146,11 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy */ public function mapLevelToPriority(string $level): int { - if (!array_key_exists($level, $this->logLevels)) { + if (!array_key_exists($level, static::logLevels)) { throw new LogLevelException(sprintf('The level "%s" is not valid.', $level)); } - return $this->logLevels[$level]; + return static::logLevels[$level]; } /** @@ -202,7 +199,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy $record = array_merge($record, ['uid' => $this->logUid]); $logMessage = $this->channel . ' '; - $logMessage .= '[' . $this->logToString[$level] . ']: '; + $logMessage .= '[' . static::logToString[$level] . ']: '; $logMessage .= $this->psrInterpolate($message, $context) . ' '; $logMessage .= $this->jsonEncodeArray($context) . ' - '; $logMessage .= $this->jsonEncodeArray($record); diff --git a/src/Util/FileSystem.php b/src/Core/Logger/Util/FileSystem.php similarity index 94% rename from src/Util/FileSystem.php rename to src/Core/Logger/Util/FileSystem.php index a21e7fb606..3793ac4a9d 100644 --- a/src/Util/FileSystem.php +++ b/src/Core/Logger/Util/FileSystem.php @@ -19,10 +19,10 @@ * */ -namespace Friendica\Util; +namespace Friendica\Core\Logger\Util; /** - * Util class for filesystem manipulation + * Util class for filesystem manipulation for Logger classes */ class FileSystem { @@ -38,7 +38,7 @@ class FileSystem * * @return string The directory name (empty if no directory is found, like urls) */ - public function createDir(string $file) + public function createDir(string $file): string { $dirname = null; $pos = strpos($file, '://'); diff --git a/src/Core/Logger/Util/LoggerSettingsCheck.php b/src/Core/Logger/Util/LoggerSettingsCheck.php new file mode 100644 index 0000000000..7782216dab --- /dev/null +++ b/src/Core/Logger/Util/LoggerSettingsCheck.php @@ -0,0 +1,91 @@ +. + * + */ + +namespace Friendica\Core\Logger\Util; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Logger\Capabilities\ICheckLoggerSettings; +use Friendica\Core\Logger\Exception\LoggerUnusableException; + +/** {@inheritDoc} */ +class LoggerSettingsCheck implements ICheckLoggerSettings +{ + /** @var IManageConfigValues */ + protected $config; + /** @var $fileSystem */ + protected $fileSystem; + /** @var L10n */ + protected $l10n; + + public function __construct(IManageConfigValues $config, FileSystem $fileSystem, L10n $l10n) + { + $this->config = $config; + $this->fileSystem = $fileSystem; + $this->l10n = $l10n; + } + + /** {@inheritDoc} */ + public function checkLogfile(): ?string + { + // Check logfile permission + if ($this->config->get('system', 'debugging')) { + $file = $this->config->get('system', 'logfile'); + + try { + $stream = $this->fileSystem->createStream($file); + + if (!isset($stream)) { + throw new LoggerUnusableException('Stream is null.'); + } + } catch (\Throwable $exception) { + return $this->l10n->t('The logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); + } + } + + return null; + } + + /** {@inheritDoc} */ + public function checkDebugLogfile(): ?string + { + // Check logfile permission + if ($this->config->get('system', 'debugging')) { + $file = $this->config->get('system', 'dlogfile'); + + if (empty($file)) { + return null; + } + + try { + $stream = $this->fileSystem->createStream($file); + + if (!isset($stream)) { + throw new LoggerUnusableException('Stream is null.'); + } + } catch (\Throwable $exception) { + return $this->l10n->t('The debug logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); + } + } + + return null; + } +} diff --git a/src/DI.php b/src/DI.php index 8d706ed374..ad8745622f 100644 --- a/src/DI.php +++ b/src/DI.php @@ -22,10 +22,12 @@ namespace Friendica; use Dice\Dice; -use Friendica\Core\Session\Capability\IHandleSessions; -use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Navigation\SystemMessages; -use Psr\Log\LoggerInterface; +use \Friendica\Core\Logger\Capabilities\ICheckLoggerSettings; +use \Friendica\Core\Logger\Util\LoggerSettingsCheck; +use \Friendica\Core\Session\Capability\IHandleSessions; +use \Friendica\Core\Session\Capability\IHandleUserSessions; +use \Friendica\Navigation\SystemMessages; +use \Psr\Log\LoggerInterface; /** * This class is capable of getting all dynamic created classes @@ -295,6 +297,11 @@ abstract class DI static::init($flushDice); } + public static function loggCheck(): ICheckLoggerSettings + { + return self::$dice->create(LoggerSettingsCheck::class); + } + /** * @return LoggerInterface */ @@ -692,14 +699,6 @@ abstract class DI return self::$dice->create(Util\DateTimeFormat::class); } - /** - * @return Util\FileSystem - */ - public static function fs() - { - return self::$dice->create(Util\FileSystem::class); - } - /** * @return Util\Profiler */ diff --git a/src/Module/Admin/Summary.php b/src/Module/Admin/Summary.php index d872f48259..80437305dc 100644 --- a/src/Module/Admin/Summary.php +++ b/src/Module/Admin/Summary.php @@ -79,7 +79,7 @@ class Summary extends BaseAdmin // Check if github.com/friendica/stable/VERSION is higher then // the local version of Friendica. Check is opt-in, source may be stable or develop branch if (DI::config()->get('system', 'check_new_version_url', 'none') != 'none') { - $gitversion = DI::keyValue()->get('git_friendica_version') ?? ''; + $gitversion = DI::keyValue()->get('git_friendica_version') ?? ''; if (version_compare(App::VERSION, $gitversion) < 0) { $warningtext[] = DI::l10n()->t('There is a new version of Friendica available for download. Your current version is %1$s, upstream version is %2$s', App::VERSION, $gitversion); @@ -126,35 +126,11 @@ class Summary extends BaseAdmin } // Check logfile permission - if (DI::config()->get('system', 'debugging')) { - $file = DI::config()->get('system', 'logfile'); - - $fileSystem = DI::fs(); - - try { - $stream = $fileSystem->createStream($file); - - if (!isset($stream)) { - throw new ServiceUnavailableException('Stream is null.'); - } - - } catch (\Throwable $exception) { - $warningtext[] = DI::l10n()->t('The logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); - } - - $file = DI::config()->get('system', 'dlogfile'); - - try { - if (!empty($file)) { - $stream = $fileSystem->createStream($file); - - if (!isset($stream)) { - throw new ServiceUnavailableException('Stream is null.'); - } - } - } catch (\Throwable $exception) { - $warningtext[] = DI::l10n()->t('The debug logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); - } + if (($return = DI::loggCheck()->checkLogfile()) !== null) { + $warningtext[] = $return; + } + if (($return = DI::loggCheck()->checkDebugLogfile()) !== null) { + $warningtext[] = $return; } // check legacy basepath settings diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 0891166424..2b246f8452 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -37,8 +37,9 @@ use Dice\Dice; use Friendica\App; use Friendica\Core\Cache; use Friendica\Core\Config; -use Friendica\Core\Hooks\Capabilities\ICanManageInstances; -use Friendica\Core\Hooks\Model\InstanceManager; +use Friendica\Core\Hooks\Capabilities\ICanCreateInstances; +use Friendica\Core\Hooks\Capabilities\ICanRegisterInstances; +use Friendica\Core\Hooks\Model\DiceInstanceManager; use Friendica\Core\PConfig; use Friendica\Core\L10n; use Friendica\Core\Lock; @@ -62,6 +63,13 @@ return [ // one instance for the whole execution 'shared' => true, ], + \Friendica\Core\Addon\Capabilities\ICanLoadAddons::class => [ + 'instanceOf' => \Friendica\Core\Addon\Model\AddonLoader::class, + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + [Dice::INSTANCE => Dice::SELF], + ], + ], '$basepath' => [ 'instanceOf' => Util\BasePath::class, 'call' => [ @@ -78,8 +86,24 @@ return [ $_SERVER ] ], - ICanManageInstances::class => [ - 'instanceOf' => InstanceManager::class, + DiceInstanceManager::class => [ + 'constructParams' => [ + [Dice::INSTANCE => Dice::SELF], + ] + ], + \Friendica\Core\Hooks\Util\HookFileManager::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + ], + ], + ICanRegisterInstances::class => [ + 'instanceOf' => DiceInstanceManager::class, + 'constructParams' => [ + [Dice::INSTANCE => Dice::SELF], + ], + ], + ICanCreateInstances::class => [ + 'instanceOf' => DiceInstanceManager::class, 'constructParams' => [ [Dice::INSTANCE => Dice::SELF], ], @@ -156,40 +180,40 @@ return [ [Dice::INSTANCE => '$basepath'], ], ], - /** - * Create a Logger, which implements the LoggerInterface - * - * Same as: - * $loggerFactory = new Factory\LoggerFactory(); - * $logger = $loggerFactory->create($channel, $configuration, $profiler); - * - * Attention1: We can use DICE for detecting dependencies inside "chained" calls too - * Attention2: The variable "$channel" is passed inside the creation of the dependencies per: - * $app = $dice->create(App::class, [], ['$channel' => 'index']); - * and is automatically passed as an argument with the same name - */ - LoggerInterface::class => [ + \Psr\Log\LoggerInterface::class => [ 'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class, - 'constructParams' => [ - 'index', + 'call' => [ + ['create', [], Dice::CHAIN_CALL], ], + ], + \Friendica\Core\Logger\Type\SyslogLogger::class => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\SyslogLogger::class, 'call' => [ ['create', [], Dice::CHAIN_CALL], ], ], - '$devLogger' => [ - 'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class, - 'constructParams' => [ - 'dev', + \Friendica\Core\Logger\Type\StreamLogger::class => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\StreamLogger::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], ], + ], + \Friendica\Core\Logger\Type\ProfilerLogger::class => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\ProfilerLogger::class, 'call' => [ - ['createDev', [], Dice::CHAIN_CALL], - ] + ['create', [], Dice::CHAIN_CALL], + ], ], \Friendica\Core\Logger\Capabilities\IHaveCallIntrospections::class => [ - 'instanceOf' => \Friendica\Core\Logger\Util\Introspection::class, + 'instanceOf' => \Friendica\Core\Logger\Util\Introspection::class, 'constructParams' => [ - \Friendica\Core\Logger\Util\Introspection::IGNORE_CLASS_LIST, + \Friendica\Core\Logger\Capabilities\IHaveCallIntrospections::IGNORE_CLASS_LIST, + ], + ], + '$devLogger' => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\StreamLogger::class, + 'call' => [ + ['createDev', [], Dice::CHAIN_CALL], ], ], Cache\Capability\ICanCache::class => [ diff --git a/static/hooks.config.php b/static/hooks.config.php new file mode 100644 index 0000000000..ca8863e0f2 --- /dev/null +++ b/static/hooks.config.php @@ -0,0 +1,37 @@ +. + * + */ + +use Friendica\Core\Hooks\Capabilities\HookType as H; + +return [ + H::STRATEGY => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + \Friendica\Core\Logger\Type\SyslogLogger::class => ['syslog'], + \Friendica\Core\Logger\Type\StreamLogger::class => ['stream'], + ], + ], + H::DECORATOR => [ + \Psr\Log\LoggerInterface::class => [ + \Friendica\Core\Logger\Type\ProfilerLogger::class, + ], + ], +]; diff --git a/tests/Util/Hooks/InstanceMocks/FakeInstance.php b/tests/Util/Hooks/InstanceMocks/FakeInstance.php index ff99002f7c..9a0e9dd6fa 100644 --- a/tests/Util/Hooks/InstanceMocks/FakeInstance.php +++ b/tests/Util/Hooks/InstanceMocks/FakeInstance.php @@ -21,9 +21,7 @@ namespace Friendica\Test\Util\Hooks\InstanceMocks; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; - -class FakeInstance implements IAmADecoratedInterface, IAmAStrategy +class FakeInstance { protected $aText = null; protected $cBool = null; diff --git a/tests/src/Core/Hooks/Model/InstanceManagerTest.php b/tests/src/Core/Hooks/Model/InstanceManagerTest.php index 4e4c0135cb..200500d63e 100644 --- a/tests/src/Core/Hooks/Model/InstanceManagerTest.php +++ b/tests/src/Core/Hooks/Model/InstanceManagerTest.php @@ -22,7 +22,7 @@ namespace Friendica\Test\src\Core\Hooks\Model; use Dice\Dice; -use Friendica\Core\Hooks\Model\InstanceManager; +use Friendica\Core\Hooks\Model\DiceInstanceManager; use Friendica\Test\MockedTest; use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstance; use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstanceDecorator; @@ -32,12 +32,12 @@ class InstanceManagerTest extends MockedTest { public function testEqualButNotSameInstance() { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice()); $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class); - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + $getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake'); + $getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake'); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); @@ -81,7 +81,7 @@ class InstanceManagerTest extends MockedTest */ public function testInstanceWithConstructorAnonymArgs(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice()); $args = []; @@ -98,9 +98,9 @@ class InstanceManagerTest extends MockedTest $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + $getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake'); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + $getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake'); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); @@ -117,7 +117,7 @@ class InstanceManagerTest extends MockedTest */ public function testInstanceConstructorAndGetInstanceWithNamedArgs(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice()); $args = []; @@ -131,9 +131,9 @@ class InstanceManagerTest extends MockedTest $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); @@ -150,7 +150,7 @@ class InstanceManagerTest extends MockedTest */ public function testInstanceWithTwoStrategies(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice()); $args = []; @@ -165,9 +165,9 @@ class InstanceManagerTest extends MockedTest $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + $getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake23', [$bString]); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); @@ -184,7 +184,7 @@ class InstanceManagerTest extends MockedTest */ public function testDecorator(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice()); $args = []; @@ -202,9 +202,9 @@ class InstanceManagerTest extends MockedTest $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + $getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake23', [$bString]); self::assertEquals(2, FakeInstanceDecorator::$countInstance); self::assertEquals($getInstanceA, $getInstanceB); @@ -222,7 +222,7 @@ class InstanceManagerTest extends MockedTest */ public function testTwoDecoratorWithPrefix(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice()); $args = []; @@ -241,9 +241,9 @@ class InstanceManagerTest extends MockedTest $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceA = $instance->createWithName(IAmADecoratedInterface::class, 'fake', [$bString]); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + $getInstanceB = $instance->createWithName(IAmADecoratedInterface::class, 'fake23', [$bString]); self::assertEquals(4, FakeInstanceDecorator::$countInstance); self::assertEquals($getInstanceA, $getInstanceB); diff --git a/tests/src/Core/Logger/StreamLoggerTest.php b/tests/src/Core/Logger/StreamLoggerTest.php index 1ddddf4c1b..c8fac4939d 100644 --- a/tests/src/Core/Logger/StreamLoggerTest.php +++ b/tests/src/Core/Logger/StreamLoggerTest.php @@ -24,7 +24,7 @@ namespace Friendica\Test\src\Core\Logger; use Friendica\Core\Logger\Exception\LoggerArgumentException; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; -use Friendica\Util\FileSystem; +use Friendica\Core\Logger\Util\FileSystem; use Friendica\Test\Util\VFSTrait; use Friendica\Core\Logger\Type\StreamLogger; use org\bovigo\vfs\vfsStream; @@ -41,7 +41,7 @@ class StreamLoggerTest extends AbstractLoggerTest private $logfile; /** - * @var Filesystem + * @var \Friendica\Core\Logger\Util\Filesystem */ private $fileSystem; -- 2.39.5