Merge pull request #12680 from nupplaphil/feat/addon_logger
Introduce new Hook logic
This commit is contained in:
commit
c7e944e793
26 changed files with 965 additions and 244 deletions
|
@ -28,6 +28,7 @@
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"asika/simple-console": "^1.0",
|
"asika/simple-console": "^1.0",
|
||||||
"bacon/bacon-qr-code": "^2.0.0",
|
"bacon/bacon-qr-code": "^2.0.0",
|
||||||
|
"cweagans/composer-patches": "^1.7",
|
||||||
"divineomega/password_exposed": "^2.8",
|
"divineomega/password_exposed": "^2.8",
|
||||||
"ezyang/htmlpurifier": "^4.7",
|
"ezyang/htmlpurifier": "^4.7",
|
||||||
"friendica/json-ld": "^1.0",
|
"friendica/json-ld": "^1.0",
|
||||||
|
@ -126,7 +127,8 @@
|
||||||
"mockery/mockery": "^1.3",
|
"mockery/mockery": "^1.3",
|
||||||
"mikey179/vfsstream": "^1.6",
|
"mikey179/vfsstream": "^1.6",
|
||||||
"phpunit/phpunit": "^9",
|
"phpunit/phpunit": "^9",
|
||||||
"dms/phpunit-arraysubset-asserts": "^0.3.1"
|
"dms/phpunit-arraysubset-asserts": "^0.3.1",
|
||||||
|
"symplify/vendor-patches": "11.2.0.72"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "phpunit",
|
"test": "phpunit",
|
||||||
|
@ -134,5 +136,12 @@
|
||||||
"cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer",
|
"cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer",
|
||||||
"cs:check": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"],
|
"cs:check": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"],
|
||||||
"cs:fix": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"]
|
"cs:fix": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"patches": {
|
||||||
|
"level-2/dice": [
|
||||||
|
"mods/patches/level-2-dice-dice-php.patch"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
96
composer.lock
generated
96
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "5af9ac9003f4653f3aa1860dd5a4d821",
|
"content-hash": "0bbc4011b7628c0d563f80f361e98cdd",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "asika/simple-console",
|
"name": "asika/simple-console",
|
||||||
|
@ -368,6 +368,50 @@
|
||||||
],
|
],
|
||||||
"time": "2022-07-20T07:14:26+00:00"
|
"time": "2022-07-20T07:14:26+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "cweagans/composer-patches",
|
||||||
|
"version": "1.7.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cweagans/composer-patches.git",
|
||||||
|
"reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e190d4466fe2b103a55467dfa83fc2fecfcaf2db",
|
||||||
|
"reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer-plugin-api": "^1.0 || ^2.0",
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/composer": "~1.0 || ~2.0",
|
||||||
|
"phpunit/phpunit": "~4.6"
|
||||||
|
},
|
||||||
|
"type": "composer-plugin",
|
||||||
|
"extra": {
|
||||||
|
"class": "cweagans\\Composer\\Patches"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"cweagans\\Composer\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Cameron Eagans",
|
||||||
|
"email": "me@cweagans.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides a way to patch Composer packages.",
|
||||||
|
"time": "2022-12-20T22:53:13+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "dasprid/enum",
|
"name": "dasprid/enum",
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
|
@ -666,6 +710,7 @@
|
||||||
"x509",
|
"x509",
|
||||||
"x690"
|
"x690"
|
||||||
],
|
],
|
||||||
|
"abandoned": true,
|
||||||
"time": "2021-12-11T12:41:06+00:00"
|
"time": "2021-12-11T12:41:06+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1263,6 +1308,11 @@
|
||||||
"phpunit/phpunit": "^6.5"
|
"phpunit/phpunit": "^6.5"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"patches_applied": [
|
||||||
|
"mods/patches/level-2-dice-dice-php.patch"
|
||||||
|
]
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Dice\\": "./"
|
"Dice\\": "./"
|
||||||
|
@ -6368,6 +6418,50 @@
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T06:39:44+00:00"
|
"time": "2020-09-28T06:39:44+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symplify/vendor-patches",
|
||||||
|
"version": "11.2.0.72",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symplify/vendor-patches.git",
|
||||||
|
"reference": "83204e1a7a33ca958f9d1cc9c3b1b25f75270775"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symplify/vendor-patches/zipball/83204e1a7a33ca958f9d1cc9c3b1b25f75270775",
|
||||||
|
"reference": "83204e1a7a33ca958f9d1cc9c3b1b25f75270775",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"cweagans/composer-patches": "^1.7",
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/vendor-patches"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "10.3-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "Generate vendor patches for packages with single command",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.paypal.me/rectorphp",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/tomasvotruba",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-01-11T09:41:31+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
|
|
10
mods/patches/level-2-dice-dice-php.patch
Normal file
10
mods/patches/level-2-dice-dice-php.patch
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
--- /dev/null
|
||||||
|
+++ ../Dice.php
|
||||||
|
@@ -257,6 +257,7 @@
|
||||||
|
for ($i = 0; $i < count($args); $i++) {
|
||||||
|
if (call_user_func('is_' . $param->getType()->getName(), $args[$i])) {
|
||||||
|
$parameters[] = array_splice($args, $i, 1)[0];
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
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 classes, implementing 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 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;
|
||||||
|
}
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
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,8 +21,8 @@
|
||||||
|
|
||||||
namespace Friendica\Core\Logger\Type;
|
namespace Friendica\Core\Logger\Type;
|
||||||
|
|
||||||
|
use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections;
|
||||||
use Friendica\Core\Logger\Exception\LoggerException;
|
use Friendica\Core\Logger\Exception\LoggerException;
|
||||||
use Friendica\Core\Logger\Util\Introspection;
|
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
|
@ -46,7 +46,7 @@ abstract class AbstractLogger implements LoggerInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Introspection for the current call
|
* The Introspection for the current call
|
||||||
* @var Introspection
|
* @var IHaveCallIntrospections
|
||||||
*/
|
*/
|
||||||
protected $introspection;
|
protected $introspection;
|
||||||
|
|
||||||
|
@ -69,11 +69,11 @@ abstract class AbstractLogger implements LoggerInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $channel The output channel
|
* @param string $channel The output channel
|
||||||
* @param Introspection $introspection The introspection of the current call
|
* @param IHaveCallIntrospections $introspection The introspection of the current call
|
||||||
*
|
*
|
||||||
* @throws LoggerException
|
* @throws LoggerException
|
||||||
*/
|
*/
|
||||||
public function __construct(string $channel, Introspection $introspection)
|
public function __construct(string $channel, IHaveCallIntrospections $introspection)
|
||||||
{
|
{
|
||||||
$this->channel = $channel;
|
$this->channel = $channel;
|
||||||
$this->introspection = $introspection;
|
$this->introspection = $introspection;
|
||||||
|
|
|
@ -21,18 +21,20 @@
|
||||||
|
|
||||||
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\Capabilities\IHaveCallIntrospections;
|
||||||
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;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Util\FileSystem;
|
use Friendica\Util\FileSystem;
|
||||||
use Friendica\Core\Logger\Util\Introspection;
|
|
||||||
use Psr\Log\LogLevel;
|
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, IHaveCallIntrospections $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,16 +21,18 @@
|
||||||
|
|
||||||
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\Capabilities\IHaveCallIntrospections;
|
||||||
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 Psr\Log\LogLevel;
|
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, IHaveCallIntrospections $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…
Reference in a new issue