Introduce new Hook logic
- InstanceManager for computing strategies and to allow decorators - Adapting Core\Logger to use it
This commit is contained in:
		
					parent
					
						
							
								d17a21601c
							
						
					
				
			
			
				commit
				
					
						f609e38600
					
				
			
		
					 22 changed files with 844 additions and 236 deletions
				
			
		
							
								
								
									
										29
									
								
								src/Core/Hooks/Capabilities/IAmAStrategy.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/Core/Hooks/Capabilities/IAmAStrategy.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | <?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 interfaces, marking this interface are valid Strategies for Hook calls | ||||||
|  |  */ | ||||||
|  | interface IAmAStrategy | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								src/Core/Hooks/Capabilities/ICanManageInstances.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/Core/Hooks/Capabilities/ICanManageInstances.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | ||||||
|  | <?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      The name of the given class, which will be used for factories, dependency injections etc. | ||||||
|  | 	 * @param string $class     The class of the given class | ||||||
|  | 	 * @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 class or interface, which gets decorated by a class | ||||||
|  | 	 * @param string $decoratorClass 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     A given class or interface, which will get returned | ||||||
|  | 	 * @param string $name      The name of the concrete class, wich | ||||||
|  | 	 * @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; | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								src/Core/Hooks/Exceptions/HookInstanceException.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/Core/Hooks/Exceptions/HookInstanceException.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | <?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 HookInstanceException extends \RuntimeException | ||||||
|  | { | ||||||
|  | 	public function __construct($message = "", \Throwable $previous = null) | ||||||
|  | 	{ | ||||||
|  | 		parent::__construct($message, 500, $previous); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								src/Core/Hooks/Exceptions/HookRegisterArgumentException.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/Core/Hooks/Exceptions/HookRegisterArgumentException.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | <?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 HookRegisterArgumentException extends \RuntimeException | ||||||
|  | { | ||||||
|  | 	public function __construct($message = "", \Throwable $previous = null) | ||||||
|  | 	{ | ||||||
|  | 		parent::__construct($message, 500, $previous); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								src/Core/Hooks/Model/InstanceManager.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/Core/Hooks/Model/InstanceManager.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,104 @@ | ||||||
|  | <?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 subsituation 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; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								src/Core/Logger/Exception/LoggerInvalidException.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/Core/Logger/Exception/LoggerInvalidException.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | <?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); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -22,16 +22,11 @@ | ||||||
| namespace Friendica\Core\Logger\Factory; | namespace Friendica\Core\Logger\Factory; | ||||||
| 
 | 
 | ||||||
| use Friendica\Core\Config\Capability\IManageConfigValues; | use Friendica\Core\Config\Capability\IManageConfigValues; | ||||||
| use Friendica\Core; | use Friendica\Core\Hooks\Capabilities\ICanManageInstances; | ||||||
| use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; |  | ||||||
| use Friendica\Core\Logger\Exception\LogLevelException; | use Friendica\Core\Logger\Exception\LogLevelException; | ||||||
| use Friendica\Database\Database; |  | ||||||
| use Friendica\Network\HTTPException\InternalServerErrorException; |  | ||||||
| use Friendica\Util\FileSystem; |  | ||||||
| use Friendica\Core\Logger\Type\ProfilerLogger; | use Friendica\Core\Logger\Type\ProfilerLogger; | ||||||
| use Friendica\Core\Logger\Type\StreamLogger; | use Friendica\Core\Logger\Type\StreamLogger; | ||||||
| use Friendica\Core\Logger\Type\SyslogLogger; | use Friendica\Core\Logger\Type\SyslogLogger; | ||||||
| use Friendica\Util\Profiler; |  | ||||||
| use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||||
| use Psr\Log\LogLevel; | use Psr\Log\LogLevel; | ||||||
| use Psr\Log\NullLogger; | use Psr\Log\NullLogger; | ||||||
|  | @ -44,115 +39,55 @@ class Logger | ||||||
| 	const DEV_CHANNEL = 'dev'; | 	const DEV_CHANNEL = 'dev'; | ||||||
| 
 | 
 | ||||||
| 	/** @var string The log-channel (app, worker, ...) */ | 	/** @var string The log-channel (app, worker, ...) */ | ||||||
| 	private $channel; | 	protected $channel; | ||||||
|  | 	/** @var ICanManageInstances */ | ||||||
|  | 	protected $instanceManager; | ||||||
|  | 	/** @var IManageConfigValues */ | ||||||
|  | 	protected $config; | ||||||
| 
 | 
 | ||||||
| 	public function __construct(string $channel, bool $includeAddon = true) | 	public function __construct(string $channel, ICanManageInstances $instanceManager, IManageConfigValues $config, string $logfile = null) | ||||||
| 	{ | 	{ | ||||||
| 		$this->channel = $channel; | 		$this->channel         = $channel; | ||||||
|  | 		$this->instanceManager = $instanceManager; | ||||||
|  | 		$this->config          = $config; | ||||||
| 
 | 
 | ||||||
| 		/// @fixme clean solution = Making Addon & Hook dynamic and load them inside the constructor, so there's no custom load logic necessary anymore
 | 		$this->instanceManager | ||||||
| 		if ($includeAddon) { | 			->registerStrategy(LoggerInterface::class, 'syslog', SyslogLogger::class) | ||||||
| 			Core\Addon::loadAddons(); | 			->registerStrategy(LoggerInterface::class, 'stream', StreamLogger::class, isset($logfile) ? [$logfile] : null); | ||||||
| 			Core\Hook::loadHooks(); | 
 | ||||||
|  | 		if ($this->config->get('system', 'profiling') ?? false) { | ||||||
|  | 			$this->instanceManager->registerDecorator(LoggerInterface::class, ProfilerLogger::class); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a new PSR-3 compliant logger instances | 	 * Creates a new PSR-3 compliant logger instances | ||||||
| 	 * | 	 * | ||||||
| 	 * @param Database            $database   The Friendica Database instance | 	 * @param string|null $loglevel (optional) A given loglevel in case the loglevel in the config isn't applicable | ||||||
| 	 * @param IManageConfigValues $config     The config |  | ||||||
| 	 * @param Profiler            $profiler   The profiler of the app |  | ||||||
| 	 * @param FileSystem          $fileSystem FileSystem utils |  | ||||||
| 	 * @param string|null         $minLevel   (optional) Override minimum Loglevel to log |  | ||||||
| 	 * | 	 * | ||||||
| 	 * @return LoggerInterface The PSR-3 compliant logger instance | 	 * @return LoggerInterface The PSR-3 compliant logger instance | ||||||
| 	 */ | 	 */ | ||||||
| 	public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection, ?string $minLevel = null): LoggerInterface | 	public function create(string $loglevel = null): LoggerInterface | ||||||
| 	{ | 	{ | ||||||
| 		if (empty($config->get('system', 'debugging', false))) { | 		if (empty($this->config->get('system', 'debugging') ?? false)) { | ||||||
| 			$logger = new NullLogger(); | 			return new NullLogger(); | ||||||
| 			$database->setLogger($logger); | 		} | ||||||
|  | 
 | ||||||
|  | 		$loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($this->config->get('system', 'loglevel')); | ||||||
|  | 		$name     = $this->config->get('system', 'logger_config') ?? 'stream'; | ||||||
|  | 
 | ||||||
|  | 		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; | 			return $logger; | ||||||
|  | 		} catch (\Throwable $e) { | ||||||
|  | 			// No logger ...
 | ||||||
|  | 			return new NullLogger(); | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		$minLevel      = $minLevel ?? $config->get('system', 'loglevel'); |  | ||||||
| 		$loglevel      = self::mapLegacyConfigDebugLevel((string)$minLevel); |  | ||||||
| 
 |  | ||||||
| 		$name = $config->get('system', 'logger_config', 'stream'); |  | ||||||
| 
 |  | ||||||
| 		switch ($name) { |  | ||||||
| 			case 'syslog': |  | ||||||
| 				try { |  | ||||||
| 					$logger = new SyslogLogger($this->channel, $introspection, $loglevel, $config->get('system', 'syslog_flags', SyslogLogger::DEFAULT_FLAGS), $config->get('system', 'syslog_facility', SyslogLogger::DEFAULT_FACILITY)); |  | ||||||
| 				} catch (LogLevelException $exception) { |  | ||||||
| 					// If there's a wrong config value for loglevel, try again with standard
 |  | ||||||
| 					$logger = $this->create($database, $config, $profiler, $fileSystem,  $introspection, LogLevel::NOTICE); |  | ||||||
| 					$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); |  | ||||||
| 				} catch (\Throwable $e) { |  | ||||||
| 					// No logger ...
 |  | ||||||
| 					$logger = new NullLogger(); |  | ||||||
| 				} |  | ||||||
| 				break; |  | ||||||
| 
 |  | ||||||
| 			case 'stream': |  | ||||||
| 			default: |  | ||||||
| 				$data = [ |  | ||||||
| 					'name'          => $name, |  | ||||||
| 					'channel'       => $this->channel, |  | ||||||
| 					'introspection' => $introspection, |  | ||||||
| 					'loglevel'      => $loglevel, |  | ||||||
| 					'logger'        => null, |  | ||||||
| 				]; |  | ||||||
| 				try { |  | ||||||
| 					Core\Hook::callAll('logger_instance', $data); |  | ||||||
| 				} catch (InternalServerErrorException $exception) { |  | ||||||
| 					$data['logger'] = null; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (($data['logger'] ?? null) instanceof LoggerInterface) { |  | ||||||
| 					$logger = $data['logger']; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (empty($logger)) { |  | ||||||
| 					$stream = $config->get('system', 'logfile'); |  | ||||||
| 					// just add a stream in case it's either writable or not file
 |  | ||||||
| 					if (!is_file($stream) || is_writable($stream)) { |  | ||||||
| 						try { |  | ||||||
| 							$logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel); |  | ||||||
| 						} catch (LogLevelException $exception) { |  | ||||||
| 							// If there's a wrong config value for loglevel, try again with standard
 |  | ||||||
| 							$logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); |  | ||||||
| 							$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); |  | ||||||
| 						} catch (\Throwable $t) { |  | ||||||
| 							// No logger ...
 |  | ||||||
| 							$logger = new NullLogger(); |  | ||||||
| 						} |  | ||||||
| 					} else { |  | ||||||
| 						try { |  | ||||||
| 							$logger = new SyslogLogger($this->channel, $introspection, $loglevel); |  | ||||||
| 						} catch (LogLevelException $exception) { |  | ||||||
| 							// If there's a wrong config value for loglevel, try again with standard
 |  | ||||||
| 							$logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); |  | ||||||
| 							$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); |  | ||||||
| 						} catch (\Throwable $e) { |  | ||||||
| 							// No logger ...
 |  | ||||||
| 							$logger = new NullLogger(); |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		$profiling = $config->get('system', 'profiling', false); |  | ||||||
| 
 |  | ||||||
| 		// In case profiling is enabled, wrap the ProfilerLogger around the current logger
 |  | ||||||
| 		if (isset($profiling) && $profiling !== false) { |  | ||||||
| 			$logger = new ProfilerLogger($logger, $profiler); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		$database->setLogger($logger); |  | ||||||
| 		return $logger; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -163,63 +98,24 @@ class Logger | ||||||
| 	 * | 	 * | ||||||
| 	 * It should never get filled during normal usage of Friendica | 	 * It should never get filled during normal usage of Friendica | ||||||
| 	 * | 	 * | ||||||
| 	 * @param IManageConfigValues $config     The config |  | ||||||
| 	 * @param Profiler            $profiler   The profiler of the app |  | ||||||
| 	 * @param FileSystem          $fileSystem FileSystem utils |  | ||||||
| 	 * |  | ||||||
| 	 * @return LoggerInterface The PSR-3 compliant logger instance | 	 * @return LoggerInterface The PSR-3 compliant logger instance | ||||||
| 	 * @throws \Exception | 	 * @throws \Exception | ||||||
| 	 */ | 	 */ | ||||||
| 	public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection) | 	public function createDev() | ||||||
| 	{ | 	{ | ||||||
| 		$debugging   = $config->get('system', 'debugging'); | 		$debugging   = $this->config->get('system', 'debugging'); | ||||||
| 		$stream      = $config->get('system', 'dlogfile'); | 		$stream      = $this->config->get('system', 'dlogfile'); | ||||||
| 		$developerIp = $config->get('system', 'dlogip'); | 		$developerIp = $this->config->get('system', 'dlogip'); | ||||||
| 
 | 
 | ||||||
| 		if ((!isset($developerIp) || !$debugging) && | 		if ((!isset($developerIp) || !$debugging) && | ||||||
| 			(!is_file($stream) || is_writable($stream))) { | 			(!is_file($stream) || is_writable($stream))) { | ||||||
| 			return new NullLogger(); | 			return new NullLogger(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		$name = $config->get('system', 'logger_config', 'stream'); | 		$name = $this->config->get('system', 'logger_config') ?? 'stream'; | ||||||
| 
 | 
 | ||||||
| 		switch ($name) { | 		/** @var LoggerInterface */ | ||||||
| 
 | 		return $this->instanceManager->getInstance(LoggerInterface::class, $name, [self::DEV_CHANNEL, LogLevel::DEBUG, $stream]); | ||||||
| 			case 'syslog': |  | ||||||
| 				$logger = new SyslogLogger(self::DEV_CHANNEL, $introspection, LogLevel::DEBUG); |  | ||||||
| 				break; |  | ||||||
| 
 |  | ||||||
| 			case 'stream': |  | ||||||
| 			default: |  | ||||||
| 				$data = [ |  | ||||||
| 					'name'          => $name, |  | ||||||
| 					'channel'       => self::DEV_CHANNEL, |  | ||||||
| 					'introspection' => $introspection, |  | ||||||
| 					'loglevel'      => LogLevel::DEBUG, |  | ||||||
| 					'logger'        => null, |  | ||||||
| 				]; |  | ||||||
| 				try { |  | ||||||
| 					Core\Hook::callAll('logger_instance', $data); |  | ||||||
| 				} catch (InternalServerErrorException $exception) { |  | ||||||
| 					$data['logger'] = null; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (($data['logger'] ?? null) instanceof LoggerInterface) { |  | ||||||
| 					return $data['logger']; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				$logger = new StreamLogger(self::DEV_CHANNEL, $stream, $introspection, $fileSystem, LogLevel::DEBUG); |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		$profiling = $config->get('system', 'profiling', false); |  | ||||||
| 
 |  | ||||||
| 		// In case profiling is enabled, wrap the ProfilerLogger around the current logger
 |  | ||||||
| 		if (isset($profiling) && $profiling !== false) { |  | ||||||
| 			$logger = new ProfilerLogger($logger, $profiler); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return $logger; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  |  | ||||||
|  | @ -21,6 +21,8 @@ | ||||||
| 
 | 
 | ||||||
| namespace Friendica\Core\Logger\Type; | namespace Friendica\Core\Logger\Type; | ||||||
| 
 | 
 | ||||||
|  | use Friendica\Core\Config\Capability\IManageConfigValues; | ||||||
|  | use Friendica\Core\Hooks\Capabilities\IAmAStrategy; | ||||||
| use Friendica\Core\Logger\Exception\LoggerArgumentException; | use Friendica\Core\Logger\Exception\LoggerArgumentException; | ||||||
| use Friendica\Core\Logger\Exception\LoggerException; | use Friendica\Core\Logger\Exception\LoggerException; | ||||||
| use Friendica\Core\Logger\Exception\LogLevelException; | use Friendica\Core\Logger\Exception\LogLevelException; | ||||||
|  | @ -32,7 +34,7 @@ use Psr\Log\LogLevel; | ||||||
| /** | /** | ||||||
|  * A Logger instance for logging into a stream (file, stdout, stderr) |  * A Logger instance for logging into a stream (file, stdout, stderr) | ||||||
|  */ |  */ | ||||||
| class StreamLogger extends AbstractLogger | class StreamLogger extends AbstractLogger implements IAmAStrategy | ||||||
| { | { | ||||||
| 	/** | 	/** | ||||||
| 	 * The minimum loglevel at which this logger will be triggered | 	 * The minimum loglevel at which this logger will be triggered | ||||||
|  | @ -80,16 +82,20 @@ class StreamLogger extends AbstractLogger | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * {@inheritdoc} | 	 * {@inheritdoc} | ||||||
| 	 * @param string|resource $stream The stream to write with this logger (either a file or a stream, i.e. stdout) |  | ||||||
| 	 * @param string          $level  The minimum loglevel at which this logger will be triggered | 	 * @param string          $level  The minimum loglevel at which this logger will be triggered | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws LoggerArgumentException | 	 * @throws LoggerArgumentException | ||||||
| 	 * @throws LogLevelException | 	 * @throws LogLevelException | ||||||
| 	 */ | 	 */ | ||||||
| 	public function __construct($channel, $stream, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) | 	public function __construct(string $channel, IManageConfigValues $config, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) | ||||||
| 	{ | 	{ | ||||||
| 		$this->fileSystem = $fileSystem; | 		$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); | 		parent::__construct($channel, $introspection); | ||||||
| 
 | 
 | ||||||
| 		if (is_resource($stream)) { | 		if (is_resource($stream)) { | ||||||
|  |  | ||||||
|  | @ -21,6 +21,8 @@ | ||||||
| 
 | 
 | ||||||
| namespace Friendica\Core\Logger\Type; | namespace Friendica\Core\Logger\Type; | ||||||
| 
 | 
 | ||||||
|  | use Friendica\Core\Config\Capability\IManageConfigValues; | ||||||
|  | use Friendica\Core\Hooks\Capabilities\IAmAStrategy; | ||||||
| use Friendica\Core\Logger\Exception\LoggerException; | use Friendica\Core\Logger\Exception\LoggerException; | ||||||
| use Friendica\Core\Logger\Exception\LogLevelException; | use Friendica\Core\Logger\Exception\LogLevelException; | ||||||
| use Friendica\Core\Logger\Util\Introspection; | use Friendica\Core\Logger\Util\Introspection; | ||||||
|  | @ -30,7 +32,7 @@ use Psr\Log\LogLevel; | ||||||
|  * A Logger instance for syslogging (fast, but simple) |  * A Logger instance for syslogging (fast, but simple) | ||||||
|  * @see http://php.net/manual/en/function.syslog.php |  * @see http://php.net/manual/en/function.syslog.php | ||||||
|  */ |  */ | ||||||
| class SyslogLogger extends AbstractLogger | class SyslogLogger extends AbstractLogger implements IAmAStrategy | ||||||
| { | { | ||||||
| 	const IDENT = 'Friendica'; | 	const IDENT = 'Friendica'; | ||||||
| 
 | 
 | ||||||
|  | @ -100,17 +102,16 @@ class SyslogLogger extends AbstractLogger | ||||||
| 	/** | 	/** | ||||||
| 	 * {@inheritdoc} | 	 * {@inheritdoc} | ||||||
| 	 * @param string $level       The minimum loglevel at which this logger will be triggered | 	 * @param string $level       The minimum loglevel at which this logger will be triggered | ||||||
| 	 * @param int    $logOpts     Indicates what logging options will be used when generating a log message |  | ||||||
| 	 * @param int    $logFacility Used to specify what type of program is logging the message |  | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws LogLevelException | 	 * @throws LogLevelException | ||||||
| 	 * @throws LoggerException | 	 * @throws LoggerException | ||||||
| 	 */ | 	 */ | ||||||
| 	public function __construct($channel, Introspection $introspection, string $level = LogLevel::NOTICE, int $logOpts = self::DEFAULT_FLAGS, int $logFacility = self::DEFAULT_FACILITY ) | 	public function __construct(string $channel, IManageConfigValues $config, Introspection $introspection, string $level = LogLevel::NOTICE) | ||||||
| 	{ | 	{ | ||||||
| 		parent::__construct($channel, $introspection); | 		parent::__construct($channel, $introspection); | ||||||
| 		$this->logOpts     = $logOpts; | 
 | ||||||
| 		$this->logFacility = $logFacility; | 		$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->logLevel    = $this->mapLevelToPriority($level); | ||||||
| 		$this->introspection->addClasses([self::class]); | 		$this->introspection->addClasses([self::class]); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -36,7 +36,6 @@ use PDO; | ||||||
| use PDOException; | use PDOException; | ||||||
| use PDOStatement; | use PDOStatement; | ||||||
| use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||||
| use Psr\Log\NullLogger; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * This class is for the low level database stuff that does driver specific things. |  * This class is for the low level database stuff that does driver specific things. | ||||||
|  | @ -81,16 +80,14 @@ class Database | ||||||
| 	/** @var ViewDefinition */ | 	/** @var ViewDefinition */ | ||||||
| 	protected $viewDefinition; | 	protected $viewDefinition; | ||||||
| 
 | 
 | ||||||
| 	public function __construct(IManageConfigValues $config, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition) | 	public function __construct(IManageConfigValues $config, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, LoggerInterface $logger) | ||||||
| 	{ | 	{ | ||||||
| 		// We are storing these values for being able to perform a reconnect
 | 		// We are storing these values for being able to perform a reconnect
 | ||||||
| 		$this->config   = $config; | 		$this->config         = $config; | ||||||
| 		$this->profiler = $profiler; | 		$this->profiler       = $profiler; | ||||||
| 		$this->dbaDefinition  = $dbaDefinition; | 		$this->dbaDefinition  = $dbaDefinition; | ||||||
| 		$this->viewDefinition = $viewDefinition; | 		$this->viewDefinition = $viewDefinition; | ||||||
| 
 | 		$this->logger         = $logger; | ||||||
| 		// Temporary NullLogger until we can fetch the logger class from the config
 |  | ||||||
| 		$this->logger = new NullLogger(); |  | ||||||
| 
 | 
 | ||||||
| 		$this->connect(); | 		$this->connect(); | ||||||
| 	} | 	} | ||||||
|  | @ -196,21 +193,6 @@ class Database | ||||||
| 		$this->testmode = $test; | 		$this->testmode = $test; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Sets the logger for DBA |  | ||||||
| 	 * |  | ||||||
| 	 * @note this is necessary because if we want to load the logger configuration |  | ||||||
| 	 *       from the DB, but there's an error, we would print out an exception. |  | ||||||
| 	 *       So the logger gets updated after the logger configuration can be retrieved |  | ||||||
| 	 *       from the database |  | ||||||
| 	 * |  | ||||||
| 	 * @param LoggerInterface $logger |  | ||||||
| 	 */ |  | ||||||
| 	public function setLogger(LoggerInterface $logger) |  | ||||||
| 	{ |  | ||||||
| 		$this->logger = $logger; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Sets the profiler for DBA | 	 * Sets the profiler for DBA | ||||||
| 	 * | 	 * | ||||||
|  |  | ||||||
|  | @ -37,6 +37,8 @@ use Dice\Dice; | ||||||
| use Friendica\App; | use Friendica\App; | ||||||
| use Friendica\Core\Cache; | use Friendica\Core\Cache; | ||||||
| use Friendica\Core\Config; | use Friendica\Core\Config; | ||||||
|  | use Friendica\Core\Hooks\Capabilities\ICanManageInstances; | ||||||
|  | use Friendica\Core\Hooks\Model\InstanceManager; | ||||||
| use Friendica\Core\PConfig; | use Friendica\Core\PConfig; | ||||||
| use Friendica\Core\L10n; | use Friendica\Core\L10n; | ||||||
| use Friendica\Core\Lock; | use Friendica\Core\Lock; | ||||||
|  | @ -76,6 +78,12 @@ return [ | ||||||
| 			$_SERVER | 			$_SERVER | ||||||
| 		] | 		] | ||||||
| 	], | 	], | ||||||
|  | 	ICanManageInstances::class => [ | ||||||
|  | 		'instanceOf' => InstanceManager::class, | ||||||
|  | 		'constructParams' => [ | ||||||
|  | 			[Dice::INSTANCE => Dice::SELF], | ||||||
|  | 		], | ||||||
|  | 	], | ||||||
| 	Config\Util\ConfigFileManager::class => [ | 	Config\Util\ConfigFileManager::class => [ | ||||||
| 		'instanceOf' => Config\Factory\Config::class, | 		'instanceOf' => Config\Factory\Config::class, | ||||||
| 		'call'       => [ | 		'call'       => [ | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ use Friendica\Database\Definition\ViewDefinition; | ||||||
| use Friendica\Test\DatabaseTestTrait; | use Friendica\Test\DatabaseTestTrait; | ||||||
| use Friendica\Test\Util\Database\StaticDatabase; | use Friendica\Test\Util\Database\StaticDatabase; | ||||||
| use Friendica\Util\Profiler; | use Friendica\Util\Profiler; | ||||||
|  | use Psr\Log\NullLogger; | ||||||
| 
 | 
 | ||||||
| trait CreateDatabaseTrait | trait CreateDatabaseTrait | ||||||
| { | { | ||||||
|  | @ -45,7 +46,7 @@ trait CreateDatabaseTrait | ||||||
| 			], | 			], | ||||||
| 		])); | 		])); | ||||||
| 
 | 
 | ||||||
| 		$database = new StaticDatabase($config, new Profiler($config), (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load()); | 		$database = new StaticDatabase($config, new Profiler($config), (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load(), new NullLogger()); | ||||||
| 		$database->setTestmode(true); | 		$database->setTestmode(true); | ||||||
| 
 | 
 | ||||||
| 		return $database; | 		return $database; | ||||||
|  |  | ||||||
							
								
								
									
										60
									
								
								tests/Util/Hooks/InstanceMocks/FakeInstance.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								tests/Util/Hooks/InstanceMocks/FakeInstance.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | ||||||
|  | <?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\Test\Util\Hooks\InstanceMocks; | ||||||
|  | 
 | ||||||
|  | use Friendica\Core\Hooks\Capabilities\IAmAStrategy; | ||||||
|  | 
 | ||||||
|  | class FakeInstance implements IAmADecoratedInterface, IAmAStrategy | ||||||
|  | { | ||||||
|  | 	protected $aText = null; | ||||||
|  | 	protected $cBool = null; | ||||||
|  | 	protected $bText = null; | ||||||
|  | 
 | ||||||
|  | 	public function __construct(string $aText = null, bool $cBool = null, string $bText = null) | ||||||
|  | 	{ | ||||||
|  | 		$this->aText         = $aText; | ||||||
|  | 		$this->cBool         = $cBool; | ||||||
|  | 		$this->bText         = $bText; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function createSomething(string $aText, bool $cBool, string $bText): string | ||||||
|  | 	{ | ||||||
|  | 		$this->aText         = $aText; | ||||||
|  | 		$this->cBool         = $cBool; | ||||||
|  | 		$this->bText         = $bText; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function getAText(): ?string | ||||||
|  | 	{ | ||||||
|  | 		return $this->aText; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function getBText(): ?string | ||||||
|  | 	{ | ||||||
|  | 		return $this->bText; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function getCBool(): ?bool | ||||||
|  | 	{ | ||||||
|  | 		return $this->cBool; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | ||||||
|  | <?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\Test\Util\Hooks\InstanceMocks; | ||||||
|  | 
 | ||||||
|  | class FakeInstanceDecorator implements IAmADecoratedInterface | ||||||
|  | { | ||||||
|  | 	public static $countInstance = 0; | ||||||
|  | 
 | ||||||
|  | 	/** @var IAmADecoratedInterface */ | ||||||
|  | 	protected $orig; | ||||||
|  | 	protected $prefix = ''; | ||||||
|  | 
 | ||||||
|  | 	public function __construct(IAmADecoratedInterface $orig, string $prefix = '') | ||||||
|  | 	{ | ||||||
|  | 		$this->orig   = $orig; | ||||||
|  | 		$this->prefix = $prefix; | ||||||
|  | 
 | ||||||
|  | 		self::$countInstance++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function createSomething(string $aText, bool $cBool, string $bText): string | ||||||
|  | 	{ | ||||||
|  | 		return $this->orig->createSomething($aText, $cBool, $bText); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function getAText(): ?string | ||||||
|  | 	{ | ||||||
|  | 		return $this->prefix . $this->orig->getAText(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function getBText(): ?string | ||||||
|  | 	{ | ||||||
|  | 		return $this->prefix . $this->orig->getBText(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function getCBool(): ?bool | ||||||
|  | 	{ | ||||||
|  | 		return $this->prefix . $this->orig->getCBool(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								tests/Util/Hooks/InstanceMocks/IAmADecoratedInterface.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/Util/Hooks/InstanceMocks/IAmADecoratedInterface.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | ||||||
|  | <?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\Test\Util\Hooks\InstanceMocks; | ||||||
|  | 
 | ||||||
|  | interface IAmADecoratedInterface | ||||||
|  | { | ||||||
|  | 	public function createSomething(string $aText, bool $cBool, string $bText): string; | ||||||
|  | 
 | ||||||
|  | 	public function getAText(): ?string; | ||||||
|  | 
 | ||||||
|  | 	public function getBText(): ?string; | ||||||
|  | 
 | ||||||
|  | 	public function getCBool(): ?bool; | ||||||
|  | } | ||||||
|  | @ -25,7 +25,6 @@ use Dice\Dice; | ||||||
| use Friendica\App; | use Friendica\App; | ||||||
| use Friendica\Core\Cache\Capability\ICanCache; | use Friendica\Core\Cache\Capability\ICanCache; | ||||||
| use Friendica\Core\Cache\Capability\ICanCacheInMemory; | use Friendica\Core\Cache\Capability\ICanCacheInMemory; | ||||||
| use Friendica\Core\Config\Model\Config; |  | ||||||
| use Friendica\Core\Config\ValueObject\Cache; | use Friendica\Core\Config\ValueObject\Cache; | ||||||
| use Friendica\Core\Config\Capability\IManageConfigValues; | use Friendica\Core\Config\Capability\IManageConfigValues; | ||||||
| use Friendica\Core\Lock\Capability\ICanLock; | use Friendica\Core\Lock\Capability\ICanLock; | ||||||
|  | @ -33,7 +32,6 @@ use Friendica\Database\Database; | ||||||
| use Friendica\Test\Util\VFSTrait; | use Friendica\Test\Util\VFSTrait; | ||||||
| use Friendica\Util\BasePath; | use Friendica\Util\BasePath; | ||||||
| use Friendica\Core\Config\Util\ConfigFileManager; | use Friendica\Core\Config\Util\ConfigFileManager; | ||||||
| use Friendica\Util\Profiler; |  | ||||||
| use PHPUnit\Framework\TestCase; | use PHPUnit\Framework\TestCase; | ||||||
| use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||||
| 
 | 
 | ||||||
|  | @ -53,7 +51,18 @@ class DependencyCheckTest extends TestCase | ||||||
| 		$this->setUpVfsDir(); | 		$this->setUpVfsDir(); | ||||||
| 
 | 
 | ||||||
| 		$this->dice = (new Dice()) | 		$this->dice = (new Dice()) | ||||||
| 			->addRules(include __DIR__ . '/../../static/dependencies.config.php'); | 			->addRules(include __DIR__ . '/../../static/dependencies.config.php') | ||||||
|  | 			->addRule(BasePath::class, [ | ||||||
|  | 				'constructParams' => [ | ||||||
|  | 					$this->root->url(), | ||||||
|  | 					[], | ||||||
|  | 				], | ||||||
|  | 			]) | ||||||
|  | 			->addRule(LoggerInterface::class, ['constructParams' => ['test']]); | ||||||
|  | 
 | ||||||
|  | 		/** @var IManageConfigValues $config */ | ||||||
|  | 		$config = $this->dice->create(IManageConfigValues::class); | ||||||
|  | 		$config->set('system', 'logfile', $this->root->url() . '/logs/friendica.log'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -142,7 +151,7 @@ class DependencyCheckTest extends TestCase | ||||||
| 	public function testLogger() | 	public function testLogger() | ||||||
| 	{ | 	{ | ||||||
| 		/** @var LoggerInterface $logger */ | 		/** @var LoggerInterface $logger */ | ||||||
| 		$logger = $this->dice->create(LoggerInterface::class, ['test']); | 		$logger = $this->dice->create(LoggerInterface::class, [['$channel' => 'test']]); | ||||||
| 
 | 
 | ||||||
| 		self::assertInstanceOf(LoggerInterface::class, $logger); | 		self::assertInstanceOf(LoggerInterface::class, $logger); | ||||||
| 	} | 	} | ||||||
|  | @ -154,7 +163,7 @@ class DependencyCheckTest extends TestCase | ||||||
| 		$config->set('system', 'dlogfile', $this->root->url() . '/friendica.log'); | 		$config->set('system', 'dlogfile', $this->root->url() . '/friendica.log'); | ||||||
| 
 | 
 | ||||||
| 		/** @var LoggerInterface $logger */ | 		/** @var LoggerInterface $logger */ | ||||||
| 		$logger = $this->dice->create('$devLogger', ['dev']); | 		$logger = $this->dice->create('$devLogger', [['$channel' => 'dev']]); | ||||||
| 
 | 
 | ||||||
| 		self::assertInstanceOf(LoggerInterface::class, $logger); | 		self::assertInstanceOf(LoggerInterface::class, $logger); | ||||||
| 	} | 	} | ||||||
|  | @ -164,6 +173,7 @@ class DependencyCheckTest extends TestCase | ||||||
| 		/** @var ICanCache $cache */ | 		/** @var ICanCache $cache */ | ||||||
| 		$cache = $this->dice->create(ICanCache::class); | 		$cache = $this->dice->create(ICanCache::class); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 		self::assertInstanceOf(ICanCache::class, $cache); | 		self::assertInstanceOf(ICanCache::class, $cache); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -62,7 +62,7 @@ class DatabaseCacheTest extends CacheTest | ||||||
| 		$dbaDefinition  = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); | 		$dbaDefinition  = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); | ||||||
| 		$viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); | 		$viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); | ||||||
| 
 | 
 | ||||||
| 		$dba = new StaticDatabase($config, $profiler, $dbaDefinition, $viewDefinition); | 		$dba = new StaticDatabase($config, $profiler, $dbaDefinition, $viewDefinition, new NullLogger()); | ||||||
| 
 | 
 | ||||||
| 		$this->cache = new Cache\Type\DatabaseCache('database', $dba); | 		$this->cache = new Cache\Type\DatabaseCache('database', $dba); | ||||||
| 		return $this->cache; | 		return $this->cache; | ||||||
|  |  | ||||||
							
								
								
									
										258
									
								
								tests/src/Core/Hooks/Model/InstanceManagerTest.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								tests/src/Core/Hooks/Model/InstanceManagerTest.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,258 @@ | ||||||
|  | <?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\Test\src\Core\Hooks\Model; | ||||||
|  | 
 | ||||||
|  | use Dice\Dice; | ||||||
|  | use Friendica\Core\Hooks\Model\InstanceManager; | ||||||
|  | use Friendica\Test\MockedTest; | ||||||
|  | use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstance; | ||||||
|  | use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstanceDecorator; | ||||||
|  | use Friendica\Test\Util\Hooks\InstanceMocks\IAmADecoratedInterface; | ||||||
|  | 
 | ||||||
|  | class InstanceManagerTest extends MockedTest | ||||||
|  | { | ||||||
|  | 	public function testEqualButNotSameInstance() | ||||||
|  | 	{ | ||||||
|  | 		$instance = new InstanceManager(new Dice()); | ||||||
|  | 
 | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class); | ||||||
|  | 
 | ||||||
|  | 		$getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); | ||||||
|  | 		$getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); | ||||||
|  | 
 | ||||||
|  | 		self::assertEquals($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertNotSame($getInstanceA, $getInstanceB); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protected function tearDown(): void | ||||||
|  | 	{ | ||||||
|  | 		FakeInstanceDecorator::$countInstance = 0; | ||||||
|  | 
 | ||||||
|  | 		parent::tearDown(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public function dataTests(): array | ||||||
|  | 	{ | ||||||
|  | 		return [ | ||||||
|  | 			'only_a'           => [ | ||||||
|  | 				'aString' => 'test', | ||||||
|  | 			], | ||||||
|  | 			'a_b'              => [ | ||||||
|  | 				'aString' => 'test', | ||||||
|  | 				'cBool' => false, | ||||||
|  | 				'bString' => 'test23', | ||||||
|  | 
 | ||||||
|  | 			], | ||||||
|  | 			'a_c'              => [ | ||||||
|  | 				'aString' => 'test', | ||||||
|  | 				'cBool'   => false, | ||||||
|  | 				'bString' => null, | ||||||
|  | 			], | ||||||
|  | 			'a_b_c'            => [ | ||||||
|  | 				'aString' => 'test', | ||||||
|  | 				'cBool'   => false, | ||||||
|  | 				'bString' => 'test23', | ||||||
|  | 			], | ||||||
|  | 			'null'             => [], | ||||||
|  | 		]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @dataProvider dataTests | ||||||
|  | 	 */ | ||||||
|  | 	public function testInstanceWithConstructorAnonymArgs(string $aString = null, bool $cBool = null, string $bString = null) | ||||||
|  | 	{ | ||||||
|  | 		$instance = new InstanceManager(new Dice()); | ||||||
|  | 
 | ||||||
|  | 		$args = []; | ||||||
|  | 
 | ||||||
|  | 		if (isset($aString)) { | ||||||
|  | 			$args[] = $aString; | ||||||
|  | 		} | ||||||
|  | 		if (isset($bString)) { | ||||||
|  | 			$args[] = $bString; | ||||||
|  | 		} | ||||||
|  | 		if (isset($cBool)) { | ||||||
|  | 			$args[] = $cBool; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); | ||||||
|  | 
 | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceA */ | ||||||
|  | 		$getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceB */ | ||||||
|  | 		$getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); | ||||||
|  | 
 | ||||||
|  | 		self::assertEquals($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertNotSame($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertEquals($aString, $getInstanceA->getAText()); | ||||||
|  | 		self::assertEquals($aString, $getInstanceB->getAText()); | ||||||
|  | 		self::assertEquals($bString, $getInstanceA->getBText()); | ||||||
|  | 		self::assertEquals($bString, $getInstanceB->getBText()); | ||||||
|  | 		self::assertEquals($cBool, $getInstanceA->getCBool()); | ||||||
|  | 		self::assertEquals($cBool, $getInstanceB->getCBool()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @dataProvider dataTests | ||||||
|  | 	 */ | ||||||
|  | 	public function testInstanceConstructorAndGetInstanceWithNamedArgs(string $aString = null, bool $cBool = null, string $bString = null) | ||||||
|  | 	{ | ||||||
|  | 		$instance = new InstanceManager(new Dice()); | ||||||
|  | 
 | ||||||
|  | 		$args = []; | ||||||
|  | 
 | ||||||
|  | 		if (isset($aString)) { | ||||||
|  | 			$args[] = $aString; | ||||||
|  | 		} | ||||||
|  | 		if (isset($cBool)) { | ||||||
|  | 			$args[] = $cBool; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); | ||||||
|  | 
 | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceA */ | ||||||
|  | 		$getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceB */ | ||||||
|  | 		$getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); | ||||||
|  | 
 | ||||||
|  | 		self::assertEquals($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertNotSame($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertEquals($aString, $getInstanceA->getAText()); | ||||||
|  | 		self::assertEquals($aString, $getInstanceB->getAText()); | ||||||
|  | 		self::assertEquals($bString, $getInstanceA->getBText()); | ||||||
|  | 		self::assertEquals($bString, $getInstanceB->getBText()); | ||||||
|  | 		self::assertEquals($cBool, $getInstanceA->getCBool()); | ||||||
|  | 		self::assertEquals($cBool, $getInstanceB->getCBool()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @dataProvider dataTests | ||||||
|  | 	 */ | ||||||
|  | 	public function testInstanceWithTwoStrategies(string $aString = null, bool $cBool = null, string $bString = null) | ||||||
|  | 	{ | ||||||
|  | 		$instance = new InstanceManager(new Dice()); | ||||||
|  | 
 | ||||||
|  | 		$args = []; | ||||||
|  | 
 | ||||||
|  | 		if (isset($aString)) { | ||||||
|  | 			$args[] = $aString; | ||||||
|  | 		} | ||||||
|  | 		if (isset($cBool)) { | ||||||
|  | 			$args[] = $cBool; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); | ||||||
|  | 
 | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceA */ | ||||||
|  | 		$getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceB */ | ||||||
|  | 		$getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); | ||||||
|  | 
 | ||||||
|  | 		self::assertEquals($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertNotSame($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertEquals($aString, $getInstanceA->getAText()); | ||||||
|  | 		self::assertEquals($aString, $getInstanceB->getAText()); | ||||||
|  | 		self::assertEquals($bString, $getInstanceA->getBText()); | ||||||
|  | 		self::assertEquals($bString, $getInstanceB->getBText()); | ||||||
|  | 		self::assertEquals($cBool, $getInstanceA->getCBool()); | ||||||
|  | 		self::assertEquals($cBool, $getInstanceB->getCBool()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @dataProvider dataTests | ||||||
|  | 	 */ | ||||||
|  | 	public function testDecorator(string $aString = null, bool $cBool = null, string $bString = null) | ||||||
|  | 	{ | ||||||
|  | 		$instance = new InstanceManager(new Dice()); | ||||||
|  | 
 | ||||||
|  | 		$args = []; | ||||||
|  | 
 | ||||||
|  | 		if (isset($aString)) { | ||||||
|  | 			$args[] = $aString; | ||||||
|  | 		} | ||||||
|  | 		if (isset($cBool)) { | ||||||
|  | 			$args[] = $cBool; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$prefix = 'prefix1'; | ||||||
|  | 
 | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); | ||||||
|  | 		$instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); | ||||||
|  | 
 | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceA */ | ||||||
|  | 		$getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceB */ | ||||||
|  | 		$getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); | ||||||
|  | 
 | ||||||
|  | 		self::assertEquals(2, FakeInstanceDecorator::$countInstance); | ||||||
|  | 		self::assertEquals($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertNotSame($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertEquals($prefix . $aString, $getInstanceA->getAText()); | ||||||
|  | 		self::assertEquals($prefix . $aString, $getInstanceB->getAText()); | ||||||
|  | 		self::assertEquals($prefix . $bString, $getInstanceA->getBText()); | ||||||
|  | 		self::assertEquals($prefix . $bString, $getInstanceB->getBText()); | ||||||
|  | 		self::assertEquals($prefix . $cBool, $getInstanceA->getCBool()); | ||||||
|  | 		self::assertEquals($prefix . $cBool, $getInstanceB->getCBool()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @dataProvider dataTests | ||||||
|  | 	 */ | ||||||
|  | 	public function testTwoDecoratorWithPrefix(string $aString = null, bool $cBool = null, string $bString = null) | ||||||
|  | 	{ | ||||||
|  | 		$instance = new InstanceManager(new Dice()); | ||||||
|  | 
 | ||||||
|  | 		$args = []; | ||||||
|  | 
 | ||||||
|  | 		if (isset($aString)) { | ||||||
|  | 			$args[] = $aString; | ||||||
|  | 		} | ||||||
|  | 		if (isset($cBool)) { | ||||||
|  | 			$args[] = $cBool; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$prefix = 'prefix1'; | ||||||
|  | 
 | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); | ||||||
|  | 		$instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); | ||||||
|  | 		$instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); | ||||||
|  | 		$instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class); | ||||||
|  | 
 | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceA */ | ||||||
|  | 		$getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); | ||||||
|  | 		/** @var IAmADecoratedInterface $getInstanceB */ | ||||||
|  | 		$getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); | ||||||
|  | 
 | ||||||
|  | 		self::assertEquals(4, FakeInstanceDecorator::$countInstance); | ||||||
|  | 		self::assertEquals($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertNotSame($getInstanceA, $getInstanceB); | ||||||
|  | 		self::assertEquals($prefix . $aString, $getInstanceA->getAText()); | ||||||
|  | 		self::assertEquals($prefix . $aString, $getInstanceB->getAText()); | ||||||
|  | 		self::assertEquals($prefix . $bString, $getInstanceA->getBText()); | ||||||
|  | 		self::assertEquals($prefix . $bString, $getInstanceB->getBText()); | ||||||
|  | 		self::assertEquals($prefix . $cBool, $getInstanceA->getCBool()); | ||||||
|  | 		self::assertEquals($prefix . $cBool, $getInstanceB->getCBool()); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -21,6 +21,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace Friendica\Test\src\Core\Logger; | namespace Friendica\Test\src\Core\Logger; | ||||||
| 
 | 
 | ||||||
|  | use Friendica\Core\Config\Capability\IManageConfigValues; | ||||||
| use Friendica\Test\MockedTest; | use Friendica\Test\MockedTest; | ||||||
| use Friendica\Core\Logger\Util\Introspection; | use Friendica\Core\Logger\Util\Introspection; | ||||||
| use Mockery\MockInterface; | use Mockery\MockInterface; | ||||||
|  | @ -41,6 +42,10 @@ abstract class AbstractLoggerTest extends MockedTest | ||||||
| 	 * @var Introspection|MockInterface | 	 * @var Introspection|MockInterface | ||||||
| 	 */ | 	 */ | ||||||
| 	protected $introspection; | 	protected $introspection; | ||||||
|  | 	/** | ||||||
|  | 	 * @var IManageConfigValues|MockInterface | ||||||
|  | 	 */ | ||||||
|  | 	protected $config; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Returns the content of the current logger instance | 	 * Returns the content of the current logger instance | ||||||
|  | @ -68,6 +73,8 @@ abstract class AbstractLoggerTest extends MockedTest | ||||||
| 			'line'     => self::LINE, | 			'line'     => self::LINE, | ||||||
| 			'function' => self::FUNC | 			'function' => self::FUNC | ||||||
| 		]); | 		]); | ||||||
|  | 
 | ||||||
|  | 		$this->config = \Mockery::mock(IManageConfigValues::class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public function assertLogline($string) | 	public function assertLogline($string) | ||||||
|  |  | ||||||
|  | @ -62,7 +62,9 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 		$this->logfile = vfsStream::newFile('friendica.log') | 		$this->logfile = vfsStream::newFile('friendica.log') | ||||||
| 			->at($this->root); | 			->at($this->root); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', $this->logfile->url(), $this->introspection, $this->fileSystem, $level); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($this->logfile->url())->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem, $level); | ||||||
| 
 | 
 | ||||||
| 		return $logger; | 		return $logger; | ||||||
| 	} | 	} | ||||||
|  | @ -75,43 +77,6 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 		return $this->logfile->getContent(); | 		return $this->logfile->getContent(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Test if a stream is working |  | ||||||
| 	 */ |  | ||||||
| 	public function testStream() |  | ||||||
| 	{ |  | ||||||
| 		$logfile = vfsStream::newFile('friendica.log') |  | ||||||
| 			->at($this->root); |  | ||||||
| 
 |  | ||||||
| 		$filehandler = fopen($logfile->url(), 'ab'); |  | ||||||
| 
 |  | ||||||
| 		$logger = new \Friendica\Core\Logger\Type\StreamLogger('test', $filehandler, $this->introspection, $this->fileSystem); |  | ||||||
| 		$logger->emergency('working'); |  | ||||||
| 
 |  | ||||||
| 		$text = $logfile->getContent(); |  | ||||||
| 
 |  | ||||||
| 		self::assertLogline($text); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Test if the close statement is working |  | ||||||
| 	 */ |  | ||||||
| 	public function testClose() |  | ||||||
| 	{ |  | ||||||
| 		$logfile = vfsStream::newFile('friendica.log') |  | ||||||
| 			->at($this->root); |  | ||||||
| 
 |  | ||||||
| 		$logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem); |  | ||||||
| 		$logger->emergency('working'); |  | ||||||
| 		$logger->close(); |  | ||||||
| 		// close doesn't affect
 |  | ||||||
| 		$logger->emergency('working too'); |  | ||||||
| 
 |  | ||||||
| 		$text = $logfile->getContent(); |  | ||||||
| 
 |  | ||||||
| 		self::assertLoglineNums(2, $text); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Test when a file isn't set | 	 * Test when a file isn't set | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -120,7 +85,9 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 		$this->expectException(LoggerArgumentException::class); | 		$this->expectException(LoggerArgumentException::class); | ||||||
| 		$this->expectExceptionMessage("Missing stream URL."); | 		$this->expectExceptionMessage("Missing stream URL."); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', '', $this->introspection, $this->fileSystem); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('')->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); | ||||||
| 
 | 
 | ||||||
| 		$logger->emergency('not working'); | 		$logger->emergency('not working'); | ||||||
| 	} | 	} | ||||||
|  | @ -130,13 +97,14 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 	 */ | 	 */ | ||||||
| 	public function testWrongUrl() | 	public function testWrongUrl() | ||||||
| 	{ | 	{ | ||||||
| 		$this->expectException(LoggerException::class); | 		$this->expectException(LoggerArgumentException::class); | ||||||
| 		$this->expectExceptionMessage("Cannot create stream."); |  | ||||||
| 
 | 
 | ||||||
| 		$logfile = vfsStream::newFile('friendica.log') | 		$logfile = vfsStream::newFile('friendica.log') | ||||||
| 			->at($this->root)->chmod(0); | 			->at($this->root)->chmod(0); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($logfile->url())->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); | ||||||
| 
 | 
 | ||||||
| 		$logger->emergency('not working'); | 		$logger->emergency('not working'); | ||||||
| 	} | 	} | ||||||
|  | @ -164,7 +132,9 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 		$this->expectException(LogLevelException::class); | 		$this->expectException(LogLevelException::class); | ||||||
| 		$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); | 		$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', 'file.text', $this->introspection, $this->fileSystem, 'NOPE'); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('file.text')->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem, 'NOPE'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -178,7 +148,9 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 		$logfile = vfsStream::newFile('friendica.log') | 		$logfile = vfsStream::newFile('friendica.log') | ||||||
| 			->at($this->root); | 			->at($this->root); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($logfile->url())->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); | ||||||
| 
 | 
 | ||||||
| 		$logger->log('NOPE', 'a test'); | 		$logger->log('NOPE', 'a test'); | ||||||
| 	} | 	} | ||||||
|  | @ -191,7 +163,9 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 		$this->expectException(LoggerArgumentException::class); | 		$this->expectException(LoggerArgumentException::class); | ||||||
| 		$this->expectExceptionMessage("A stream must either be a resource or a string."); | 		$this->expectExceptionMessage("A stream must either be a resource or a string."); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', null, $this->introspection, $this->fileSystem); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn(null)->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -207,7 +181,9 @@ class StreamLoggerTest extends AbstractLoggerTest | ||||||
| 
 | 
 | ||||||
| 		chdir($this->root->getChild('logs')->url()); | 		chdir($this->root->getChild('logs')->url()); | ||||||
| 
 | 
 | ||||||
| 		$logger = new StreamLogger('test', '../friendica.log' , $this->introspection, $this->fileSystem); | 		$this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('../friendica.log')->once(); | ||||||
|  | 
 | ||||||
|  | 		$logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); | ||||||
| 
 | 
 | ||||||
| 		$logger->info('Test'); | 		$logger->info('Test'); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -39,6 +39,10 @@ class SyslogLoggerTest extends AbstractLoggerTest | ||||||
| 		parent::setUp(); | 		parent::setUp(); | ||||||
| 
 | 
 | ||||||
| 		$this->introspection->shouldReceive('addClasses')->with([SyslogLogger::class]); | 		$this->introspection->shouldReceive('addClasses')->with([SyslogLogger::class]); | ||||||
|  | 		$this->config->shouldReceive('get')->with('system', 'syslog_flags')->andReturn(SyslogLogger::DEFAULT_FLAGS) | ||||||
|  | 					 ->once(); | ||||||
|  | 		$this->config->shouldReceive('get')->with('system', 'syslog_facility') | ||||||
|  | 					 ->andReturn(SyslogLogger::DEFAULT_FACILITY)->once(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -54,7 +58,7 @@ class SyslogLoggerTest extends AbstractLoggerTest | ||||||
| 	 */ | 	 */ | ||||||
| 	protected function getInstance($level = LogLevel::DEBUG) | 	protected function getInstance($level = LogLevel::DEBUG) | ||||||
| 	{ | 	{ | ||||||
| 		$this->logger = new SyslogLoggerWrapper('test', $this->introspection, $level); | 		$this->logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection, $level); | ||||||
| 
 | 
 | ||||||
| 		return $this->logger; | 		return $this->logger; | ||||||
| 	} | 	} | ||||||
|  | @ -68,7 +72,7 @@ class SyslogLoggerTest extends AbstractLoggerTest | ||||||
| 		$this->expectException(LogLevelException::class); | 		$this->expectException(LogLevelException::class); | ||||||
| 		$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); | 		$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); | ||||||
| 		 | 		 | ||||||
| 		$logger = new SyslogLoggerWrapper('test', $this->introspection, 'NOPE'); | 		$logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection, 'NOPE'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -79,7 +83,7 @@ class SyslogLoggerTest extends AbstractLoggerTest | ||||||
| 		$this->expectException(LogLevelException::class); | 		$this->expectException(LogLevelException::class); | ||||||
| 		$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); | 		$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); | ||||||
| 
 | 
 | ||||||
| 		$logger = new SyslogLoggerWrapper('test', $this->introspection); | 		$logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection); | ||||||
| 
 | 
 | ||||||
| 		$logger->log('NOPE', 'a test'); | 		$logger->log('NOPE', 'a test'); | ||||||
| 	} | 	} | ||||||
|  | @ -90,7 +94,7 @@ class SyslogLoggerTest extends AbstractLoggerTest | ||||||
| 	 */ | 	 */ | ||||||
| 	public function testClose() | 	public function testClose() | ||||||
| 	{ | 	{ | ||||||
| 		$logger = new SyslogLoggerWrapper('test', $this->introspection); | 		$logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection); | ||||||
| 		$logger->emergency('test'); | 		$logger->emergency('test'); | ||||||
| 		$logger->close(); | 		$logger->close(); | ||||||
| 		// Reopened itself
 | 		// Reopened itself
 | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace Friendica\Test\src\Core\Logger; | namespace Friendica\Test\src\Core\Logger; | ||||||
| 
 | 
 | ||||||
|  | use Friendica\Core\Config\Capability\IManageConfigValues; | ||||||
| use Friendica\Core\Logger\Type\SyslogLogger; | use Friendica\Core\Logger\Type\SyslogLogger; | ||||||
| use Friendica\Core\Logger\Util\Introspection; | use Friendica\Core\Logger\Util\Introspection; | ||||||
| use Psr\Log\LogLevel; | use Psr\Log\LogLevel; | ||||||
|  | @ -32,9 +33,9 @@ class SyslogLoggerWrapper extends SyslogLogger | ||||||
| { | { | ||||||
| 	private $content; | 	private $content; | ||||||
| 
 | 
 | ||||||
| 	public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER) | 	public function __construct($channel, IManageConfigValues $config, Introspection $introspection, $level = LogLevel::NOTICE) | ||||||
| 	{ | 	{ | ||||||
| 		parent::__construct($channel, $introspection, $level, $logOpts, $logFacility); | 		parent::__construct($channel, $config, $introspection, $level); | ||||||
| 
 | 
 | ||||||
| 		$this->content = ''; | 		$this->content = ''; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue