mirror of
https://git.friendi.ca/friendica/friendica.git
synced 2025-06-11 14:14:26 +02:00
Provide dependencies as PSR-11 container instead of arrays
This commit is contained in:
parent
1f25fe9bf5
commit
bc8d0d5fae
9 changed files with 54 additions and 62 deletions
|
@ -9,20 +9,22 @@ declare(strict_types=1);
|
|||
|
||||
namespace Friendica\Addon\Event;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Start an addon.
|
||||
*/
|
||||
final class AddonStartEvent
|
||||
{
|
||||
private array $dependencies;
|
||||
private ContainerInterface $container;
|
||||
|
||||
public function __construct(array $dependencies)
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->dependencies = $dependencies;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function getDependencies(): array
|
||||
public function getContainer(): ContainerInterface
|
||||
{
|
||||
return $this->dependencies;
|
||||
return $this->container;
|
||||
}
|
||||
}
|
||||
|
|
12
src/App.php
12
src/App.php
|
@ -38,6 +38,7 @@ use Friendica\Protocol\ATProtocol\DID;
|
|||
use Friendica\Security\Authentication;
|
||||
use Friendica\Security\ExAuth;
|
||||
use Friendica\Security\OpenWebAuth;
|
||||
use Friendica\Service\Addon\AddonContainer;
|
||||
use Friendica\Service\Addon\AddonManager;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
@ -208,17 +209,18 @@ class App
|
|||
|
||||
// At this place we should be careful because addons can change the container
|
||||
// Maybe we should create a new container especially for the addons
|
||||
foreach ($$this->addonManager->getProvidedDependencyRules() as $name => $rule) {
|
||||
foreach ($this->addonManager->getProvidedDependencyRules() as $name => $rule) {
|
||||
$this->container->addRule($name, $rule);
|
||||
}
|
||||
|
||||
$dependencies = [];
|
||||
$containers = [];
|
||||
|
||||
foreach ($this->addonManager->getAllRequiredDependencies() as $dependency) {
|
||||
$dependencies[$dependency] = $this->container->create($dependency);
|
||||
foreach ($this->addonManager->getRequiredDependencies() as $addonId => $dependencies) {
|
||||
// @TODO At this point we can filter or restrict the dependencies of addons
|
||||
$containers[$addonId] = AddonContainer::fromContainer($this->container, $dependencies);
|
||||
}
|
||||
|
||||
$this->addonManager->initAddons($dependencies);
|
||||
$this->addonManager->initAddons($containers);
|
||||
}
|
||||
|
||||
private function registerEventDispatcher(): void
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Friendica\Service\Addon;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Interface to communicate with an addon.
|
||||
*/
|
||||
|
@ -22,7 +24,7 @@ interface Addon
|
|||
|
||||
public function getProvidedDependencyRules(): array;
|
||||
|
||||
public function initAddon(array $dependencies): void;
|
||||
public function initAddon(ContainerInterface $container): void;
|
||||
|
||||
public function installAddon(): void;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Friendica\Service\Addon;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Manager for all addons.
|
||||
*/
|
||||
|
@ -29,18 +31,6 @@ final class AddonManager
|
|||
$this->addons = $this->addonFactory->getAddons($addonNames);
|
||||
}
|
||||
|
||||
public function getAllRequiredDependencies(): array
|
||||
{
|
||||
$dependencies = [];
|
||||
|
||||
foreach ($this->addons as $addon) {
|
||||
// @TODO Here we can filter or deny dependencies from addons
|
||||
$dependencies = array_merge($dependencies, $addon->getRequiredDependencies());
|
||||
}
|
||||
|
||||
return array_unique($dependencies);
|
||||
}
|
||||
|
||||
public function getRequiredDependencies(): array
|
||||
{
|
||||
$dependencies = [];
|
||||
|
@ -76,21 +66,19 @@ final class AddonManager
|
|||
return $events;
|
||||
}
|
||||
|
||||
public function initAddons(array $dependencies): void
|
||||
/**
|
||||
* @param ContainerInterface[] $containers
|
||||
*/
|
||||
public function initAddons(array $containers): void
|
||||
{
|
||||
foreach ($this->addons as $addon) {
|
||||
$required = $addon->getRequiredDependencies();
|
||||
$addonDependencies = [];
|
||||
$container = $containers[$addon->getId()] ?? null;
|
||||
|
||||
foreach ($required as $dependency) {
|
||||
if (!array_key_exists($dependency, $dependencies)) {
|
||||
throw new \RuntimeException(sprintf('Dependency "%s" required by addon "%s" not found.', $dependency, $addon));
|
||||
if ($container === null) {
|
||||
throw new \RuntimeException(sprintf('Container for addon "%s" is missing.', $addon->getId()));
|
||||
}
|
||||
|
||||
$addonDependencies[$dependency] = $dependencies[$dependency];
|
||||
}
|
||||
|
||||
$addon->initAddon($addonDependencies);
|
||||
$addon->initAddon($container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use Friendica\Addon\AddonBootstrap;
|
|||
use Friendica\Addon\DependencyProvider;
|
||||
use Friendica\Addon\Event\AddonStartEvent;
|
||||
use Friendica\Addon\InstallableAddon;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Proxy object for an addon.
|
||||
|
@ -61,7 +62,7 @@ final class AddonProxy implements Addon
|
|||
return [];
|
||||
}
|
||||
|
||||
public function initAddon(array $dependencies): void
|
||||
public function initAddon(ContainerInterface $container): void
|
||||
{
|
||||
if ($this->isInit) {
|
||||
return;
|
||||
|
@ -69,7 +70,7 @@ final class AddonProxy implements Addon
|
|||
|
||||
$this->isInit = true;
|
||||
|
||||
$event = new AddonStartEvent($dependencies);
|
||||
$event = new AddonStartEvent($container);
|
||||
|
||||
$this->bootstrap->initAddon($event);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Friendica\Service\Addon;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Proxy object for a legacy addon.
|
||||
*/
|
||||
|
@ -52,7 +54,7 @@ final class LegacyAddonProxy implements Addon
|
|||
return [];
|
||||
}
|
||||
|
||||
public function initAddon(array $dependencies): void
|
||||
public function initAddon(ContainerInterface $container): void
|
||||
{
|
||||
if ($this->isInit) {
|
||||
return;
|
||||
|
|
|
@ -16,6 +16,7 @@ use Friendica\Addon\InstallableAddon;
|
|||
use Friendica\Service\Addon\Addon;
|
||||
use Friendica\Service\Addon\AddonProxy;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
|
@ -97,7 +98,7 @@ class AddonProxyTest extends TestCase
|
|||
|
||||
$addon = new AddonProxy('id', $bootstrap);
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
}
|
||||
|
||||
public function testInitAddonMultipleTimesWillCallBootstrapOnce(): void
|
||||
|
@ -109,26 +110,22 @@ class AddonProxyTest extends TestCase
|
|||
|
||||
$addon = new AddonProxy('id', $bootstrap);
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
}
|
||||
|
||||
public function testInitAddonCallsBootstrapWithDependencies(): void
|
||||
{
|
||||
$container = $this->createStub(ContainerInterface::class);
|
||||
|
||||
$bootstrap = $this->createMock(AddonBootstrap::class);
|
||||
|
||||
$bootstrap->expects($this->once())->method('initAddon')->willReturnCallback(function (AddonStartEvent $event) {
|
||||
$dependencies = $event->getDependencies();
|
||||
|
||||
$this->assertArrayHasKey(LoggerInterface::class, $dependencies);
|
||||
$this->assertInstanceOf(LoggerInterface::class, $dependencies[LoggerInterface::class]);
|
||||
$bootstrap->expects($this->once())->method('initAddon')->willReturnCallback(function (AddonStartEvent $event) use ($container) {
|
||||
$this->assertSame($container, $event->getContainer());
|
||||
});
|
||||
|
||||
$addon = new AddonProxy('id', $bootstrap);
|
||||
|
||||
$addon->initAddon(
|
||||
[LoggerInterface::class => $this->createStub(LoggerInterface::class)]
|
||||
);
|
||||
$addon->initAddon($container);
|
||||
}
|
||||
|
||||
public function testInstallAddonCallsBootstrap(): void
|
||||
|
@ -138,7 +135,7 @@ class AddonProxyTest extends TestCase
|
|||
|
||||
$addon = new AddonProxy('id', $bootstrap);
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
$addon->installAddon();
|
||||
}
|
||||
|
||||
|
@ -149,7 +146,7 @@ class AddonProxyTest extends TestCase
|
|||
|
||||
$addon = new AddonProxy('id', $bootstrap);
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
$addon->uninstallAddon();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use Friendica\Service\Addon\Addon;
|
|||
use Friendica\Service\Addon\LegacyAddonProxy;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class LegacyAddonProxyTest extends TestCase
|
||||
{
|
||||
|
@ -85,7 +86,7 @@ class LegacyAddonProxyTest extends TestCase
|
|||
$addon = new LegacyAddonProxy('helloaddon', $root->url());
|
||||
|
||||
try {
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
} catch (\Throwable $th) {
|
||||
$this->assertSame(
|
||||
'Addon loaded',
|
||||
|
@ -105,7 +106,7 @@ class LegacyAddonProxyTest extends TestCase
|
|||
$addon = new LegacyAddonProxy('helloaddon', $root->url());
|
||||
|
||||
try {
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
} catch (\Exception $th) {
|
||||
$this->assertSame(
|
||||
'Addon loaded',
|
||||
|
@ -113,8 +114,8 @@ class LegacyAddonProxyTest extends TestCase
|
|||
);
|
||||
}
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
}
|
||||
|
||||
public function testInstallAddonWillCallInstallFunction(): void
|
||||
|
@ -127,7 +128,7 @@ class LegacyAddonProxyTest extends TestCase
|
|||
|
||||
$addon = new LegacyAddonProxy('helloaddon', $root->url());
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
try {
|
||||
$addon->installAddon();
|
||||
} catch (\Exception $th) {
|
||||
|
@ -148,7 +149,7 @@ class LegacyAddonProxyTest extends TestCase
|
|||
|
||||
$addon = new LegacyAddonProxy('helloaddon', $root->url());
|
||||
|
||||
$addon->initAddon([]);
|
||||
$addon->initAddon($this->createStub(ContainerInterface::class));
|
||||
try {
|
||||
$addon->uninstallAddon();
|
||||
} catch (\Exception $th) {
|
||||
|
|
|
@ -32,7 +32,7 @@ class HelloAddon implements AddonBootstrap, DependencyProvider, InstallableAddon
|
|||
*
|
||||
* The array should contain FQCN of the required services.
|
||||
*
|
||||
* The dependencies will be passed to the initAddon() method via AddonStartEvent::getDependencies().
|
||||
* The dependencies will be passed as a PSR-11 Container to the initAddon() method via AddonStartEvent::getContainer().
|
||||
*/
|
||||
public function getRequiredDependencies(): array
|
||||
{
|
||||
|
@ -87,12 +87,9 @@ class HelloAddon implements AddonBootstrap, DependencyProvider, InstallableAddon
|
|||
|
||||
public function initAddon(AddonStartEvent $event): void
|
||||
{
|
||||
// $dependencies containts an array of services defined in getRequiredDependencies().
|
||||
// The keys are the FQCN of the services.
|
||||
// The values are the instances of the services.
|
||||
$dependencies = $event->getDependencies();
|
||||
$container = $event->getContainer();
|
||||
|
||||
$this->logger = $dependencies[LoggerInterface::class];
|
||||
$this->logger = $container->get(LoggerInterface::class);
|
||||
|
||||
$this->logger->info('Hello from HelloAddon');
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue