From 694893e2bbd7610b0970fcf822c3617040ae8e6a Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 12:37:57 +0000 Subject: [PATCH 01/12] Implement getAddonDependencyConfig --- src/Core/Addon/AddonHelper.php | 13 ++++ src/Core/Addon/AddonManagerHelper.php | 29 ++++++++ .../Core/Addon/AddonManagerHelperTest.php | 71 +++++++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/src/Core/Addon/AddonHelper.php b/src/Core/Addon/AddonHelper.php index 03a21232e5..94dd721fa3 100644 --- a/src/Core/Addon/AddonHelper.php +++ b/src/Core/Addon/AddonHelper.php @@ -9,6 +9,8 @@ declare(strict_types=1); namespace Friendica\Core\Addon; +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; + /** * Some functions to handle addons */ @@ -64,6 +66,17 @@ interface AddonHelper */ public function getAddonInfo(string $addonId): AddonInfo; + /** + * Returns a dependency config array for a given addon + * + * This will load a potential config-file from the static directory, like `addon/{addonId}/static/dependencies.config.php` + * + * @throws AddonInvalidConfigFileException If the config file doesn't return an array + * + * @return array the config as array or empty array if no config file was found + */ + public function getAddonDependencyConfig(string $addonId): array; + /** * Checks if the provided addon is enabled */ diff --git a/src/Core/Addon/AddonManagerHelper.php b/src/Core/Addon/AddonManagerHelper.php index 21573ab89c..a5b8ccc96e 100644 --- a/src/Core/Addon/AddonManagerHelper.php +++ b/src/Core/Addon/AddonManagerHelper.php @@ -9,6 +9,7 @@ declare(strict_types=1); namespace Friendica\Core\Addon; +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; @@ -246,6 +247,34 @@ final class AddonManagerHelper implements AddonHelper return AddonInfo::fromString($addonId, $raw); } + /** + * Returns a dependency config array for a given addon + * + * This will load a potential config-file from the static directory, like `addon/{addonId}/static/dependencies.config.php` + * + * @throws AddonInvalidConfigFileException If the config file doesn't return an array + * + * @return array the config as array or empty array if no config file was found + */ + public function getAddonDependencyConfig(string $addonId): array + { + $addonId = Strings::sanitizeFilePathItem(trim($addonId)); + + $configFile = $this->getAddonPath() . '/' . $addonId . '/static/dependencies.config.php'; + + if (!file_exists($configFile)) { + return []; + } + + $config = include($configFile); + + if (!is_array($config)) { + throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); + } + + return $config; + } + /** * Checks if the provided addon is enabled */ diff --git a/tests/Unit/Core/Addon/AddonManagerHelperTest.php b/tests/Unit/Core/Addon/AddonManagerHelperTest.php index fae0502474..0008f80692 100644 --- a/tests/Unit/Core/Addon/AddonManagerHelperTest.php +++ b/tests/Unit/Core/Addon/AddonManagerHelperTest.php @@ -12,6 +12,7 @@ namespace Friendica\Test\Unit\Core\Addon; use Exception; use Friendica\Core\Addon\AddonInfo; use Friendica\Core\Addon\AddonManagerHelper; +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; @@ -54,6 +55,76 @@ class AddonManagerHelperTest extends TestCase $this->assertEquals('Hello Addon', $info->getName()); } + public function testGetAddonDependencyConfigReturnsArray(): void + { + $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ + 'helloaddon' => [ + 'static' => [ + 'dependencies.config.php' => << 'bar', + ]; + PHP, + ], + ] + ]); + + $addonManagerHelper = new AddonManagerHelper( + $root->url(), + $this->createStub(Database::class), + $this->createStub(IManageConfigValues::class), + $this->createStub(ICanCache::class), + $this->createStub(LoggerInterface::class), + $this->createStub(Profiler::class) + ); + + $this->assertSame(['foo' => 'bar'], $addonManagerHelper->getAddonDependencyConfig('helloaddon')); + } + + public function testGetAddonDependencyConfigWithoutConfigFileReturnsEmptyArray(): void + { + $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ + 'helloaddon' => [] + ]); + + $addonManagerHelper = new AddonManagerHelper( + $root->url(), + $this->createStub(Database::class), + $this->createStub(IManageConfigValues::class), + $this->createStub(ICanCache::class), + $this->createStub(LoggerInterface::class), + $this->createStub(Profiler::class) + ); + + $this->assertSame([], $addonManagerHelper->getAddonDependencyConfig('helloaddon')); + } + + public function testGetAddonDependencyConfigWithoutReturningAnArrayThrowsException(): void + { + $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ + 'helloaddon' => [ + 'static' => [ + 'dependencies.config.php' => 'url(), + $this->createStub(Database::class), + $this->createStub(IManageConfigValues::class), + $this->createStub(ICanCache::class), + $this->createStub(LoggerInterface::class), + $this->createStub(Profiler::class) + ); + + $this->expectException(AddonInvalidConfigFileException::class); + $this->expectExceptionMessageMatches('^#Error loading config file .+/helloaddon/static/dependencies\.config\.php#$'); + + $addonManagerHelper->getAddonDependencyConfig('helloaddon'); + } + public function testEnabledAddons(): void { $config = $this->createStub(IManageConfigValues::class); From 203e9642d515dbabb792e5ffc1671d80ac9ffae7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 13:12:17 +0000 Subject: [PATCH 02/12] Inline AddonLoader for strategies into StrategiesFileManager --- src/Core/Hooks/Util/StrategiesFileManager.php | 71 ++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php index a876dc832c..15b624b916 100644 --- a/src/Core/Hooks/Util/StrategiesFileManager.php +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -7,9 +7,15 @@ namespace Friendica\Core\Hooks\Util; +use Friendica\Core\Addon\AddonHelper; use Friendica\Core\Addon\Capability\ICanLoadAddons; +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; use Friendica\Core\Hooks\Exceptions\HookConfigException; +use Friendica\Core\Logger\Factory\LoggerFactory; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; /** * Manage all strategies.config.php files @@ -24,17 +30,15 @@ class StrategiesFileManager const STATIC_DIR = 'static'; const CONFIG_NAME = 'strategies'; - /** @var ICanLoadAddons */ - protected $addonLoader; - /** @var array */ - protected $config = []; + private AddonHelper $addonHelper; + protected array $config = []; /** @var string */ protected $basePath; - public function __construct(string $basePath, ICanLoadAddons $addonLoader) + public function __construct(string $basePath, AddonHelper $addonHelper) { $this->basePath = $basePath; - $this->addonLoader = $addonLoader; + $this->addonHelper = $addonHelper; } /** @@ -69,7 +73,7 @@ class StrategiesFileManager public function loadConfig() { // load core hook config - $configFile = $this->basePath . '/' . static::STATIC_DIR . '/' . static::CONFIG_NAME . '.config.php'; + $configFile = $this->addonHelper->getAddonPath() . '/' . static::STATIC_DIR . '/' . static::CONFIG_NAME . '.config.php'; if (!file_exists($configFile)) { throw new HookConfigException(sprintf('config file %s does not exist.', $configFile)); @@ -84,6 +88,57 @@ class StrategiesFileManager /** * @deprecated 2025.02 Providing strategies via addons is deprecated and will be removed in 5 months. */ - $this->config = array_merge_recursive($config, $this->addonLoader->getActiveAddonConfig(static::CONFIG_NAME)); + $this->config = array_merge_recursive($config, $this->getActiveAddonConfig(static::CONFIG_NAME)); + } + + /** + * @deprecated 2025.02 Providing strategies via addons is deprecated and will be removed in 5 months. + */ + private function getActiveAddonConfig(string $configName): array + { + $this->addonHelper->loadAddons(); + + $addons = $this->addonHelper->getEnabledAddons(); + $returnConfig = []; + + foreach ($addons as $addon) { + $addonName = Strings::sanitizeFilePathItem(trim($addon)); + + $configFile = $this->addonHelper->getAddonPath() . '/' . $addonName . '/' . static::STATIC_DIR . '/' . $configName . '.config.php'; + + if (!file_exists($configFile)) { + // Addon unmodified, skipping + continue; + } + + $config = include $configFile; + + if (!is_array($config)) { + throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); + } + + if ($configName === 'strategies') { + foreach ($config as $classname => $rule) { + if ($classname === LoggerInterface::class) { + @trigger_error(sprintf( + 'Providing a strategy for `%s` is deprecated since 2025.02 and will stop working in 5 months, please provide an implementation for `%s` via `dependency.config.php` and remove the `strategies.config.php` file in the `%s` addon.', + $classname, + LoggerFactory::class, + $addonName, + ), \E_USER_DEPRECATED); + } else { + @trigger_error(sprintf( + 'Providing strategies for `%s` via addons is deprecated since 2025.02 and will stop working in 5 months, please stop using this and remove the `strategies.config.php` file in the `%s` addon.', + $classname, + $addonName, + ), \E_USER_DEPRECATED); + } + } + } + + $returnConfig = array_merge_recursive($returnConfig, $config); + } + + return $returnConfig; } } From 1428085c4befc2a3db0a6d421dc9b8c802423bc0 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 13:15:52 +0000 Subject: [PATCH 03/12] Soft deprecate AddonLoader and ICanLoadAddons --- src/Core/Addon/Capability/ICanLoadAddons.php | 4 ++++ src/Core/Addon/Model/AddonLoader.php | 7 ++++++- static/dependencies.config.php | 1 - 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Core/Addon/Capability/ICanLoadAddons.php b/src/Core/Addon/Capability/ICanLoadAddons.php index 993c431497..63978462d3 100644 --- a/src/Core/Addon/Capability/ICanLoadAddons.php +++ b/src/Core/Addon/Capability/ICanLoadAddons.php @@ -9,12 +9,16 @@ namespace Friendica\Core\Addon\Capability; /** * Interface for loading Addons specific content + * + * @deprecated 2025.02 Use implementation of `\Friendica\Core\Addon\AddonHelper` instead. */ interface ICanLoadAddons { /** * Returns a merged config array of all active addons for a given config-name * + * @deprecated 2025.02 Use `\Friendica\Core\Addon\AddonHelper::getAddonDependencyConfig()` instead. + * * @param string $configName The config-name (config-file at the static directory, like 'hooks' => '{addon}/static/hooks.config.php) * * @return array the merged array diff --git a/src/Core/Addon/Model/AddonLoader.php b/src/Core/Addon/Model/AddonLoader.php index a608a66e3d..4e0da1c80b 100644 --- a/src/Core/Addon/Model/AddonLoader.php +++ b/src/Core/Addon/Model/AddonLoader.php @@ -14,6 +14,9 @@ use Friendica\Core\Logger\Factory\LoggerFactory; use Friendica\Util\Strings; use Psr\Log\LoggerInterface; +/** + * @deprecated 2025.02 Use implementation of `\Friendica\Core\Addon\AddonHelper` instead. + */ class AddonLoader implements ICanLoadAddons { const STATIC_PATH = 'static'; @@ -28,7 +31,9 @@ class AddonLoader implements ICanLoadAddons $this->config = $config; } - /** {@inheritDoc} */ + /** + * @deprecated 2025.02 Use `\Friendica\Core\Addon\AddonHelper::getAddonDependencyConfig()` instead. + */ public function getActiveAddonConfig(string $configName): array { $addons = array_keys(array_filter($this->config->get('addons') ?? [])); diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 04e2dd2aee..1ce02a2411 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -39,7 +39,6 @@ return (function(string $basepath, array $getVars, array $serverVars, array $coo 'instanceOf' => \Friendica\Core\Addon\Model\AddonLoader::class, 'constructParams' => [ $basepath, - [Dice::INSTANCE => Dice::SELF], ], ], \Friendica\Core\Addon\AddonHelper::class => [ From 9870fbf84fc07831435dc42d290d644dc124965c Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 13:26:34 +0000 Subject: [PATCH 04/12] Fix unit tests --- tests/Unit/Core/Addon/AddonManagerHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Core/Addon/AddonManagerHelperTest.php b/tests/Unit/Core/Addon/AddonManagerHelperTest.php index 0008f80692..f4118503f7 100644 --- a/tests/Unit/Core/Addon/AddonManagerHelperTest.php +++ b/tests/Unit/Core/Addon/AddonManagerHelperTest.php @@ -120,7 +120,7 @@ class AddonManagerHelperTest extends TestCase ); $this->expectException(AddonInvalidConfigFileException::class); - $this->expectExceptionMessageMatches('^#Error loading config file .+/helloaddon/static/dependencies\.config\.php#$'); + $this->expectExceptionMessageMatches('#Error loading config file .+/helloaddon/static/dependencies\.config\.php#'); $addonManagerHelper->getAddonDependencyConfig('helloaddon'); } From 59d22b87af2015c35815d0f5da7a962191f681f7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 13:55:48 +0000 Subject: [PATCH 05/12] Fix bath to static folder --- src/Core/Hooks/Util/StrategiesFileManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php index 15b624b916..9c3041c0a5 100644 --- a/src/Core/Hooks/Util/StrategiesFileManager.php +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -73,7 +73,7 @@ class StrategiesFileManager public function loadConfig() { // load core hook config - $configFile = $this->addonHelper->getAddonPath() . '/' . static::STATIC_DIR . '/' . static::CONFIG_NAME . '.config.php'; + $configFile = $this->basePath . '/' . static::STATIC_DIR . '/' . static::CONFIG_NAME . '.config.php'; if (!file_exists($configFile)) { throw new HookConfigException(sprintf('config file %s does not exist.', $configFile)); From d00fc89a59fdf6c723dbc94a05d28392c86ac074 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 14:06:36 +0000 Subject: [PATCH 06/12] Do not use AddonHelper in StrategiesFileManager to avoid circular dependendy with strategies ans cache --- src/Core/Hooks/Util/StrategiesFileManager.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php index 9c3041c0a5..e4144722dd 100644 --- a/src/Core/Hooks/Util/StrategiesFileManager.php +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -30,15 +30,15 @@ class StrategiesFileManager const STATIC_DIR = 'static'; const CONFIG_NAME = 'strategies'; - private AddonHelper $addonHelper; + private IManageConfigValues $configuration; protected array $config = []; /** @var string */ protected $basePath; - public function __construct(string $basePath, AddonHelper $addonHelper) + public function __construct(string $basePath, IManageConfigValues $configuration) { - $this->basePath = $basePath; - $this->addonHelper = $addonHelper; + $this->basePath = $basePath; + $this->configuration = $configuration; } /** @@ -96,15 +96,13 @@ class StrategiesFileManager */ private function getActiveAddonConfig(string $configName): array { - $this->addonHelper->loadAddons(); - - $addons = $this->addonHelper->getEnabledAddons(); + $addons = array_keys(array_filter($this->configuration->get('addons') ?? [])); $returnConfig = []; foreach ($addons as $addon) { $addonName = Strings::sanitizeFilePathItem(trim($addon)); - $configFile = $this->addonHelper->getAddonPath() . '/' . $addonName . '/' . static::STATIC_DIR . '/' . $configName . '.config.php'; + $configFile = $this->basePath . '/addon/' . $addonName . '/' . static::STATIC_DIR . '/' . $configName . '.config.php'; if (!file_exists($configFile)) { // Addon unmodified, skipping From f9d695d80d4f60a51bedb5e5f52e0a0de6dc979a Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 15 May 2025 14:09:36 +0000 Subject: [PATCH 07/12] Fix code style --- src/Core/Hooks/Util/StrategiesFileManager.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php index e4144722dd..f4fc5878c7 100644 --- a/src/Core/Hooks/Util/StrategiesFileManager.php +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -7,8 +7,6 @@ namespace Friendica\Core\Hooks\Util; -use Friendica\Core\Addon\AddonHelper; -use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; From 3f1082400a5f56468dc18cfeb3d99377502ff4e5 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 16 May 2025 07:12:08 +0000 Subject: [PATCH 08/12] Fix tests for StrategiesFileManager --- .../Hooks/Util/StrategiesFileManagerTest.php | 145 ++++++++++-------- 1 file changed, 85 insertions(+), 60 deletions(-) diff --git a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php index 633b636701..f06e0b09e9 100644 --- a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php +++ b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php @@ -8,6 +8,7 @@ namespace Friendica\Test\src\Core\Hooks\Util; use Friendica\Core\Addon\Capability\ICanLoadAddons; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; use Friendica\Core\Hooks\Exceptions\HookConfigException; use Friendica\Core\Hooks\Util\StrategiesFileManager; @@ -33,49 +34,61 @@ class StrategiesFileManagerTest extends MockedTestCase return [ 'normal' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], -]; -EOF, - 'addonsArray' => [], + return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ]; + EOF, + 'addonContent' => << [ [LoggerInterface::class, NullLogger::class, ''], ], ], 'normalWithString' => [ 'content' => << [ - \Psr\Log\NullLogger::class => '', - ], -]; -EOF, - 'addonsArray' => [], + return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => '', + ], + ]; + EOF, + 'addonContent' => << [ [LoggerInterface::class, NullLogger::class, ''], ], ], 'withAddons' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], -]; -EOF, - 'addonsArray' => [ - \Psr\Log\LoggerInterface::class => [ - \Psr\Log\NullLogger::class => ['null'], - ], - ], + return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ]; + EOF, + 'addonContent' => << [ + \Psr\Log\NullLogger::class => ['null'], + ], + ]; + EOF, 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], [LoggerInterface::class, NullLogger::class, 'null'], @@ -83,19 +96,23 @@ EOF, ], 'withAddonsWithString' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], -]; -EOF, - 'addonsArray' => [ - \Psr\Log\LoggerInterface::class => [ - \Psr\Log\NullLogger::class => 'null', - ], - ], + return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ]; + EOF, + 'addonContent' => << [ + \Psr\Log\NullLogger::class => ['null'], + ], + ]; + EOF, 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], [LoggerInterface::class, NullLogger::class, 'null'], @@ -104,19 +121,23 @@ EOF, // This should work because unique name convention is part of the instance manager logic, not of the file-infrastructure layer 'withAddonsDoubleNamed' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], -]; -EOF, - 'addonsArray' => [ - \Psr\Log\LoggerInterface::class => [ - \Psr\Log\NullLogger::class => [''], - ], - ], + return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ]; + EOF, + 'addonContent' => << [ + \Psr\Log\NullLogger::class => [''], + ], + ]; + EOF, 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], [LoggerInterface::class, NullLogger::class, ''], @@ -128,16 +149,20 @@ EOF, /** * @dataProvider dataHooks */ - public function testSetupHooks(string $content, array $addonsArray, array $assertStrategies) + public function testSetupHooks(string $content, string $addonContent, array $assertStrategies) { vfsStream::newFile(StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') ->withContent($content) ->at($this->root); - $addonLoader = \Mockery::mock(ICanLoadAddons::class); - $addonLoader->shouldReceive('getActiveAddonConfig')->andReturn($addonsArray)->once(); + vfsStream::newFile('addon/testaddon/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') + ->withContent($addonContent) + ->at($this->root); - $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get')->andReturn(['testaddon' => ['admin' => false]])->once(); + + $hookFileManager = new StrategiesFileManager($this->root->url(), $config); $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); foreach ($assertStrategies as $assertStrategy) { @@ -155,9 +180,9 @@ EOF, */ public function testMissingStrategiesFile() { - $addonLoader = \Mockery::mock(ICanLoadAddons::class); + $config = \Mockery::mock(IManageConfigValues::class); $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); - $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); + $hookFileManager = new StrategiesFileManager($this->root->url(), $config); self::expectException(HookConfigException::class); self::expectExceptionMessage(sprintf('config file %s does not exist.', @@ -171,9 +196,9 @@ EOF, */ public function testWrongStrategiesFile() { - $addonLoader = \Mockery::mock(ICanLoadAddons::class); + $config = \Mockery::mock(IManageConfigValues::class); $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); - $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); + $hookFileManager = new StrategiesFileManager($this->root->url(), $config); vfsStream::newFile(StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') ->withContent(" Date: Fri, 16 May 2025 08:20:58 +0000 Subject: [PATCH 09/12] Replace AddonLoader with AddonHelper in App --- src/App.php | 13 ++++++++----- .../Core/Hooks/Util/StrategiesFileManagerTest.php | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/App.php b/src/App.php index ffcbfd1544..b10e474885 100644 --- a/src/App.php +++ b/src/App.php @@ -18,7 +18,6 @@ use Friendica\Capabilities\ICanCreateResponses; use Friendica\Capabilities\ICanHandleRequests; use Friendica\Content\Nav; use Friendica\Core\Addon\AddonHelper; -use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Config\Factory\Config; use Friendica\Core\Container; use Friendica\Core\Hooks\HookEventBridge; @@ -278,11 +277,15 @@ class App private function setupContainerForAddons(): void { - /** @var ICanLoadAddons $addonLoader */ - $addonLoader = $this->container->create(ICanLoadAddons::class); + /** @var AddonHelper $addonHelper */ + $addonHelper = $this->container->create(AddonHelper::class); - foreach ($addonLoader->getActiveAddonConfig('dependencies') as $name => $rule) { - $this->container->addRule($name, $rule); + $addonHelper->loadAddons(); + + foreach ($addonHelper->getEnabledAddons() as $addonId) { + foreach ($addonHelper->getAddonDependencyConfig($addonId) as $name => $rule) { + $this->container->addRule($name, $rule); + } } } diff --git a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php index f06e0b09e9..3349f36fd6 100644 --- a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php +++ b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php @@ -7,7 +7,6 @@ namespace Friendica\Test\src\Core\Hooks\Util; -use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; use Friendica\Core\Hooks\Exceptions\HookConfigException; From b8b7d3cd150871f7106a52662d9d80e1b2731794 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 16 May 2025 08:23:31 +0000 Subject: [PATCH 10/12] Hard deprecate AddonLoader --- src/Core/Addon/Model/AddonLoader.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Core/Addon/Model/AddonLoader.php b/src/Core/Addon/Model/AddonLoader.php index 4e0da1c80b..b56ba3eed8 100644 --- a/src/Core/Addon/Model/AddonLoader.php +++ b/src/Core/Addon/Model/AddonLoader.php @@ -27,6 +27,8 @@ class AddonLoader implements ICanLoadAddons public function __construct(string $basePath, IManageConfigValues $config) { + @trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, use implementation of `Friendica\Core\Addon\AddonHelper` instead.', E_USER_DEPRECATED); + $this->basePath = $basePath; $this->config = $config; } @@ -36,6 +38,8 @@ class AddonLoader implements ICanLoadAddons */ public function getActiveAddonConfig(string $configName): array { + @trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, use `\Friendica\Core\Addon\AddonHelper::getAddonDependencyConfig()` instead.', E_USER_DEPRECATED); + $addons = array_keys(array_filter($this->config->get('addons') ?? [])); $returnConfig = []; From 603f96b40381cc9a6ce81712e94c0384a21eb4c5 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 16 May 2025 08:28:24 +0000 Subject: [PATCH 11/12] Refactor StrategiesFileManager --- src/Core/Hooks/Util/StrategiesFileManager.php | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php index f4fc5878c7..c56a13ee6a 100644 --- a/src/Core/Hooks/Util/StrategiesFileManager.php +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -86,13 +86,10 @@ class StrategiesFileManager /** * @deprecated 2025.02 Providing strategies via addons is deprecated and will be removed in 5 months. */ - $this->config = array_merge_recursive($config, $this->getActiveAddonConfig(static::CONFIG_NAME)); + $this->config = array_merge_recursive($config, $this->getActiveAddonConfig()); } - /** - * @deprecated 2025.02 Providing strategies via addons is deprecated and will be removed in 5 months. - */ - private function getActiveAddonConfig(string $configName): array + private function getActiveAddonConfig(): array { $addons = array_keys(array_filter($this->configuration->get('addons') ?? [])); $returnConfig = []; @@ -100,7 +97,7 @@ class StrategiesFileManager foreach ($addons as $addon) { $addonName = Strings::sanitizeFilePathItem(trim($addon)); - $configFile = $this->basePath . '/addon/' . $addonName . '/' . static::STATIC_DIR . '/' . $configName . '.config.php'; + $configFile = $this->basePath . '/addon/' . $addonName . '/' . static::STATIC_DIR . '/strategies.config.php'; if (!file_exists($configFile)) { // Addon unmodified, skipping @@ -113,22 +110,20 @@ class StrategiesFileManager throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); } - if ($configName === 'strategies') { - foreach ($config as $classname => $rule) { - if ($classname === LoggerInterface::class) { - @trigger_error(sprintf( - 'Providing a strategy for `%s` is deprecated since 2025.02 and will stop working in 5 months, please provide an implementation for `%s` via `dependency.config.php` and remove the `strategies.config.php` file in the `%s` addon.', - $classname, - LoggerFactory::class, - $addonName, - ), \E_USER_DEPRECATED); - } else { - @trigger_error(sprintf( - 'Providing strategies for `%s` via addons is deprecated since 2025.02 and will stop working in 5 months, please stop using this and remove the `strategies.config.php` file in the `%s` addon.', - $classname, - $addonName, - ), \E_USER_DEPRECATED); - } + foreach ($config as $classname => $rule) { + if ($classname === LoggerInterface::class) { + @trigger_error(sprintf( + 'Providing a strategy for `%s` is deprecated since 2025.02 and will stop working in 5 months, please provide an implementation for `%s` via `dependency.config.php` and remove the `strategies.config.php` file in the `%s` addon.', + $classname, + LoggerFactory::class, + $addonName, + ), \E_USER_DEPRECATED); + } else { + @trigger_error(sprintf( + 'Providing strategies for `%s` via addons is deprecated since 2025.02 and will stop working in 5 months, please stop using this and remove the `strategies.config.php` file in the `%s` addon.', + $classname, + $addonName, + ), \E_USER_DEPRECATED); } } From 53191caeac213cdb5bd601c1e5d6861bdeeed946 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 16 May 2025 08:33:01 +0000 Subject: [PATCH 12/12] fix code style --- .../Core/Hooks/Util/StrategiesFileManagerTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php index 3349f36fd6..7adcfc0a97 100644 --- a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php +++ b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php @@ -184,8 +184,10 @@ class StrategiesFileManagerTest extends MockedTestCase $hookFileManager = new StrategiesFileManager($this->root->url(), $config); self::expectException(HookConfigException::class); - self::expectExceptionMessage(sprintf('config file %s does not exist.', - $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php')); + self::expectExceptionMessage(sprintf( + 'config file %s does not exist.', + $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php' + )); $hookFileManager->loadConfig(); } @@ -204,8 +206,10 @@ class StrategiesFileManagerTest extends MockedTestCase ->at($this->root); self::expectException(HookConfigException::class); - self::expectExceptionMessage(sprintf('Error loading config file %s.', - $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php')); + self::expectExceptionMessage(sprintf( + 'Error loading config file %s.', + $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php' + )); $hookFileManager->loadConfig(); }