use Dice\Dice;
use Friendica\App\Mode;
+use Friendica\Core\Logger\Capabilities\LogChannel;
use Friendica\Security\ExAuth;
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' => ['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));
}
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);
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Util\DateTimeFormat;
-use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'f';
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));
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;
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));
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);
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Addon\Exception;
+
+use Throwable;
+
+/**
+ * Exception in case one or more config files of the addons are invalid
+ */
+class AddonInvalidConfigFileException extends \RuntimeException
+{
+ public function __construct($message = "", $code = 0, Throwable $previous = null)
+ {
+ parent::__construct($message, 500, $previous);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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';
+}
+++ /dev/null
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Hooks\Capabilities;
-
-/**
- * All classes, implementing this interface are valid Strategies for Hook calls
- */
-interface IAmAStrategy
-{
-}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+}
+++ /dev/null
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-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
- */
-interface ICanManageInstances
-{
- /**
- * 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
- *
- * @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;
-
- /**
- * 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
- * @param array $arguments Additional arguments, which can be passed to the constructor of "decoratorClass"
- *
- * @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;
-}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Hooks\Capabilities;
+
+use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException;
+
+/**
+ * Register strategies and decorator/treatment handling for given classes
+ */
+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 $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 $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;
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Hooks\Exceptions;
+
+class HookConfigException extends \RuntimeException
+{
+ public function __construct($message = "", \Throwable $previous = null)
+ {
+ parent::__construct($message, 500, $previous);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+}
+++ /dev/null
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-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;
- }
-}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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));
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+}
/**
* @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
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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';
+}
/**
* @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
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)
/**
* @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
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)
/**
* @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
use Throwable;
+/**
+ * A generic exception of the logging namespace
+ */
class LoggerException extends \Exception
{
public function __construct($message = "", Throwable $previous = null)
+++ /dev/null
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Core\Logger\Exception;
-
-use Throwable;
-
-class LoggerInvalidException extends \RuntimeException
-{
- public function __construct($message = "", Throwable $previous = null)
- {
- parent::__construct($message, 500, $previous);
- }
-}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+ }
+ }
+}
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;
- }
- }
}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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);
+ }
+}
+++ /dev/null
-## 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.
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
*/
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
*/
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,
* {@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);
}
*/
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);
}
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);
- }
- }
}
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;
* 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';
* 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,
* Translates log priorities to string outputs
* @var array
*/
- private $logToString = [
+ protected const logToString = [
LOG_DEBUG => 'DEBUG',
LOG_INFO => 'INFO',
LOG_NOTICE => 'NOTICE',
/**
* {@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;
}
/**
*/
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];
}
/**
$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);
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Core\Logger\Util;
+
+/**
+ * Util class for filesystem manipulation for Logger classes
+ */
+class FileSystem
+{
+ /**
+ * @var string a error message
+ */
+ private $errorMessage;
+
+ /**
+ * Creates a directory based on a file, which gets accessed
+ *
+ * @param string $file The file
+ *
+ * @return string The directory name (empty if no directory is found, like urls)
+ */
+ public function createDir(string $file): string
+ {
+ $dirname = null;
+ $pos = strpos($file, '://');
+
+ if (!$pos) {
+ $dirname = realpath(dirname($file));
+ }
+
+ if (substr($file, 0, 7) === 'file://') {
+ $dirname = realpath(dirname(substr($file, 7)));
+ }
+
+ if (isset($dirname) && !is_dir($dirname)) {
+ set_error_handler([$this, 'customErrorHandler']);
+ $status = mkdir($dirname, 0777, true);
+ restore_error_handler();
+
+ if (!$status && !is_dir($dirname)) {
+ throw new \UnexpectedValueException(sprintf('Directory "%s" cannot get created: ' . $this->errorMessage, $dirname));
+ }
+
+ return $dirname;
+ } elseif (isset($dirname) && is_dir($dirname)) {
+ return $dirname;
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Creates a stream based on a URL (could be a local file or a real URL)
+ *
+ * @param string $url The file/url
+ *
+ * @return resource the open stream resource
+ *
+ * @throws \UnexpectedValueException
+ */
+ public function createStream(string $url)
+ {
+ $directory = $this->createDir($url);
+ set_error_handler([$this, 'customErrorHandler']);
+ if (!empty($directory)) {
+ $url = $directory . DIRECTORY_SEPARATOR . pathinfo($url, PATHINFO_BASENAME);
+ }
+
+ $stream = fopen($url, 'ab');
+ restore_error_handler();
+
+ if (!is_resource($stream)) {
+ throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: ' . $this->errorMessage, $url));
+ }
+
+ return $stream;
+ }
+
+ private function customErrorHandler($code, $msg)
+ {
+ $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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;
+ }
+}
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
static::init($flushDice);
}
+ public static function loggCheck(): ICheckLoggerSettings
+ {
+ return self::$dice->create(LoggerSettingsCheck::class);
+ }
+
/**
* @return LoggerInterface
*/
return self::$dice->create(Util\DateTimeFormat::class);
}
- /**
- * @return Util\FileSystem
- */
- public static function fs()
- {
- return self::$dice->create(Util\FileSystem::class);
- }
-
/**
* @return Util\Profiler
*/
// 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);
}
// 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
+++ /dev/null
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Util;
-
-/**
- * Util class for filesystem manipulation
- */
-class FileSystem
-{
- /**
- * @var string a error message
- */
- private $errorMessage;
-
- /**
- * Creates a directory based on a file, which gets accessed
- *
- * @param string $file The file
- *
- * @return string The directory name (empty if no directory is found, like urls)
- */
- public function createDir(string $file)
- {
- $dirname = null;
- $pos = strpos($file, '://');
-
- if (!$pos) {
- $dirname = realpath(dirname($file));
- }
-
- if (substr($file, 0, 7) === 'file://') {
- $dirname = realpath(dirname(substr($file, 7)));
- }
-
- if (isset($dirname) && !is_dir($dirname)) {
- set_error_handler([$this, 'customErrorHandler']);
- $status = mkdir($dirname, 0777, true);
- restore_error_handler();
-
- if (!$status && !is_dir($dirname)) {
- throw new \UnexpectedValueException(sprintf('Directory "%s" cannot get created: ' . $this->errorMessage, $dirname));
- }
-
- return $dirname;
- } elseif (isset($dirname) && is_dir($dirname)) {
- return $dirname;
- } else {
- return '';
- }
- }
-
- /**
- * Creates a stream based on a URL (could be a local file or a real URL)
- *
- * @param string $url The file/url
- *
- * @return resource the open stream resource
- *
- * @throws \UnexpectedValueException
- */
- public function createStream(string $url)
- {
- $directory = $this->createDir($url);
- set_error_handler([$this, 'customErrorHandler']);
- if (!empty($directory)) {
- $url = $directory . DIRECTORY_SEPARATOR . pathinfo($url, PATHINFO_BASENAME);
- }
-
- $stream = fopen($url, 'ab');
- restore_error_handler();
-
- if (!is_resource($stream)) {
- throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: ' . $this->errorMessage, $url));
- }
-
- return $stream;
- }
-
- private function customErrorHandler($code, $msg)
- {
- $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
- }
-}
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;
// 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' => [
$_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],
],
[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 => [
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+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,
+ ],
+ ],
+];
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;
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;
{
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);
*/
public function testInstanceWithConstructorAnonymArgs(string $aString = null, bool $cBool = null, string $bString = null)
{
- $instance = new InstanceManager(new Dice());
+ $instance = new DiceInstanceManager(new Dice());
$args = [];
$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);
*/
public function testInstanceConstructorAndGetInstanceWithNamedArgs(string $aString = null, bool $cBool = null, string $bString = null)
{
- $instance = new InstanceManager(new Dice());
+ $instance = new DiceInstanceManager(new Dice());
$args = [];
$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);
*/
public function testInstanceWithTwoStrategies(string $aString = null, bool $cBool = null, string $bString = null)
{
- $instance = new InstanceManager(new Dice());
+ $instance = new DiceInstanceManager(new Dice());
$args = [];
$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);
*/
public function testDecorator(string $aString = null, bool $cBool = null, string $bString = null)
{
- $instance = new InstanceManager(new Dice());
+ $instance = new DiceInstanceManager(new Dice());
$args = [];
$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);
*/
public function testTwoDecoratorWithPrefix(string $aString = null, bool $cBool = null, string $bString = null)
{
- $instance = new InstanceManager(new Dice());
+ $instance = new DiceInstanceManager(new Dice());
$args = [];
$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);
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;
private $logfile;
/**
- * @var Filesystem
+ * @var \Friendica\Core\Logger\Util\Filesystem
*/
private $fileSystem;