refactor(modules): configure integrations through runtime contexts
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\JsonResponse;
|
||||
use KTXC\L10N\LocaleResolver;
|
||||
use KTXC\Module\ModuleManager;
|
||||
use KTXC\Module\Configuration\BrowserModuleContext;
|
||||
use KTXC\Security\Authorization\PermissionChecker;
|
||||
use KTXC\Service\UserAccountsService;
|
||||
use KTXC\Context\IdentityContextInterface;
|
||||
@@ -30,7 +31,11 @@ class InitController extends ControllerAbstract
|
||||
$configuration = [];
|
||||
|
||||
// modules - filter by permissions
|
||||
$configuration['modules'] = [];
|
||||
$browserContext = new BrowserModuleContext(
|
||||
$this->tenantContext->requireIdentifier(),
|
||||
$this->identityContext->requireIdentifier(),
|
||||
);
|
||||
|
||||
foreach ($this->moduleManager->list(true, true) as $module) {
|
||||
// Check if user has permission to view this module
|
||||
// Allow access if user has: {module_handle}, {module_handle}.*, or * permission
|
||||
@@ -39,12 +44,12 @@ class InitController extends ControllerAbstract
|
||||
continue;
|
||||
}
|
||||
|
||||
$integrations = $module->registerBI();
|
||||
if ($integrations !== null) {
|
||||
$configuration['modules'][$handle] = $integrations;
|
||||
}
|
||||
$module->configure($browserContext);
|
||||
}
|
||||
|
||||
$configuration['modules'] = $browserContext->modules();
|
||||
$configuration = array_merge($configuration, $browserContext->configuration());
|
||||
|
||||
// localization
|
||||
$configuration['l10n'] = [
|
||||
'locale' => $this->localeResolver->resolve($request),
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KTXC\Module\Configuration;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use KTXF\Module\Configuration\BrowserModuleContextInterface;
|
||||
use KTXF\Module\Configuration\ModuleContextType;
|
||||
use KTXF\Module\ModuleInstanceInterface;
|
||||
|
||||
final class BrowserModuleContext implements BrowserModuleContextInterface
|
||||
{
|
||||
private const RESERVED_KEYS = ['modules', 'tenant', 'user', 'l10n'];
|
||||
|
||||
/** @var array<string,array<string,mixed>> */
|
||||
private array $modules = [];
|
||||
|
||||
/** @var array<string,mixed> */
|
||||
private array $configuration = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly string $tenantIdentifier,
|
||||
private readonly string $identityIdentifier,
|
||||
) {
|
||||
}
|
||||
|
||||
public function type(): ModuleContextType
|
||||
{
|
||||
return ModuleContextType::Browser;
|
||||
}
|
||||
|
||||
public function registerModule(
|
||||
ModuleInstanceInterface $module,
|
||||
string $namespace,
|
||||
?string $boot = null,
|
||||
): void {
|
||||
if (trim($namespace) === '' || ($boot !== null && trim($boot) === '')) {
|
||||
throw new InvalidArgumentException('Browser namespace must not be empty and boot path must be null or non-empty');
|
||||
}
|
||||
$handle = $module->handle();
|
||||
if (isset($this->modules[$handle])) {
|
||||
throw new LogicException("Browser module '{$handle}' is already registered");
|
||||
}
|
||||
|
||||
$entry = [
|
||||
'handle' => $handle,
|
||||
'namespace' => $namespace,
|
||||
'version' => $module->version(),
|
||||
'label' => $module->label(),
|
||||
'author' => $module->author(),
|
||||
'description' => $module->description(),
|
||||
];
|
||||
if ($boot !== null) {
|
||||
$entry['boot'] = $boot;
|
||||
}
|
||||
|
||||
$this->modules[$handle] = $entry;
|
||||
}
|
||||
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
if (trim($key) === '') {
|
||||
throw new InvalidArgumentException('Browser configuration key must not be empty');
|
||||
}
|
||||
if (in_array($key, self::RESERVED_KEYS, true) || array_key_exists($key, $this->configuration)) {
|
||||
throw new LogicException("Browser configuration '{$key}' is already reserved or registered");
|
||||
}
|
||||
|
||||
$this->configuration[$key] = $value;
|
||||
}
|
||||
|
||||
public function tenantIdentifier(): string
|
||||
{
|
||||
return $this->tenantIdentifier;
|
||||
}
|
||||
|
||||
public function identityIdentifier(): string
|
||||
{
|
||||
return $this->identityIdentifier;
|
||||
}
|
||||
|
||||
public function modules(): array
|
||||
{
|
||||
return $this->modules;
|
||||
}
|
||||
|
||||
public function configuration(): array
|
||||
{
|
||||
return $this->configuration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KTXC\Module\Configuration;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use KTXF\Module\Configuration\ConsoleModuleContextInterface;
|
||||
use KTXF\Module\Configuration\ModuleContextType;
|
||||
|
||||
final class ConsoleModuleContext implements ConsoleModuleContextInterface
|
||||
{
|
||||
/** @var array<class-string,true> */
|
||||
private array $commands = [];
|
||||
|
||||
public function type(): ModuleContextType
|
||||
{
|
||||
return ModuleContextType::Console;
|
||||
}
|
||||
|
||||
public function registerCommand(string $command): void
|
||||
{
|
||||
if (trim($command) === '') {
|
||||
throw new InvalidArgumentException('Console command class must not be empty');
|
||||
}
|
||||
|
||||
$this->commands[$command] = true;
|
||||
}
|
||||
|
||||
public function commands(): array
|
||||
{
|
||||
return array_keys($this->commands);
|
||||
}
|
||||
}
|
||||
+22
-11
@@ -4,6 +4,7 @@ namespace KTXC\Module;
|
||||
|
||||
use KTXC\Console\Firewall\FirewallMaintenanceCommand;
|
||||
use KTXC\Console\Firewall\FirewallSetupCommand;
|
||||
use KTXC\Preview\PreviewManager;
|
||||
use KTXC\Service\FirewallService;
|
||||
use KTXC\Service\SystemFirewallLogService;
|
||||
use KTXC\Service\SystemFirewallRuleService;
|
||||
@@ -25,8 +26,9 @@ use KTXC\Security\Event\RateLimitExceededEvent;
|
||||
use KTXC\Security\Event\SuspiciousActivityEvent;
|
||||
use KTXF\Event\DeliveryMode;
|
||||
use KTXF\Event\EventListenerRegistrarInterface;
|
||||
use KTXF\Module\ModuleBrowserInterface;
|
||||
use KTXF\Module\ModuleConsoleInterface;
|
||||
use KTXF\Module\Configuration\BrowserModuleContextInterface;
|
||||
use KTXF\Module\Configuration\ConsoleModuleContextInterface;
|
||||
use KTXF\Module\Configuration\ModuleContextInterface;
|
||||
use KTXF\Module\ModuleInstanceAbstract;
|
||||
|
||||
/**
|
||||
@@ -34,10 +36,11 @@ use KTXF\Module\ModuleInstanceAbstract;
|
||||
*
|
||||
* Provides core system functionality and permissions
|
||||
*/
|
||||
class Module extends ModuleInstanceAbstract implements ModuleConsoleInterface, ModuleBrowserInterface
|
||||
class Module extends ModuleInstanceAbstract
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EventListenerRegistrarInterface $events,
|
||||
private readonly PreviewManager $previews,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -213,9 +216,20 @@ class Module extends ModuleInstanceAbstract implements ModuleConsoleInterface, M
|
||||
];
|
||||
}
|
||||
|
||||
public function registerCI(): array
|
||||
public function configure(ModuleContextInterface $context): void
|
||||
{
|
||||
return [
|
||||
if ($context instanceof BrowserModuleContextInterface) {
|
||||
$context->set(
|
||||
'preview',
|
||||
$this->previews->availability($context->tenantIdentifier()),
|
||||
);
|
||||
}
|
||||
|
||||
if (!$context instanceof ConsoleModuleContextInterface) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ([
|
||||
FirewallSetupCommand::class,
|
||||
FirewallMaintenanceCommand::class,
|
||||
\KTXC\Console\Event\EventsDebugCommand::class,
|
||||
@@ -240,11 +254,8 @@ class Module extends ModuleInstanceAbstract implements ModuleConsoleInterface, M
|
||||
\KTXC\Console\Role\RoleDeleteCommand::class,
|
||||
\KTXC\Console\Role\RoleAssignCommand::class,
|
||||
\KTXC\Console\Role\RoleRevokeCommand::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function registerBI(): array
|
||||
{
|
||||
return [];
|
||||
] as $command) {
|
||||
$context->registerCommand($command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ namespace KTXC\Module;
|
||||
|
||||
use JsonSerializable;
|
||||
use KTXC\Module\Store\ModuleEntry;
|
||||
use KTXF\Module\ModuleBrowserInterface;
|
||||
use KTXF\Module\ModuleConsoleInterface;
|
||||
use KTXF\Module\Configuration\ModuleContextInterface;
|
||||
use KTXF\Module\ModuleInstanceInterface;
|
||||
|
||||
/**
|
||||
@@ -175,20 +174,9 @@ class ModuleObject implements JsonSerializable
|
||||
$this->instance?->upgrade();
|
||||
}
|
||||
|
||||
public function registerBI(): array | null
|
||||
public function configure(ModuleContextInterface $context): void
|
||||
{
|
||||
if ($this->instance instanceof ModuleBrowserInterface) {
|
||||
return $this->instance->registerBI();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function registerCI(): array | null
|
||||
{
|
||||
if ($this->instance instanceof ModuleConsoleInterface) {
|
||||
return $this->instance->registerCI();
|
||||
}
|
||||
return null;
|
||||
$this->instance?->configure($context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace KTXC\Runtime\Console;
|
||||
use KTXC\Application\Execution\ExecutionDescriptor;
|
||||
use KTXC\Kernel;
|
||||
use KTXC\KernelInterface;
|
||||
use KTXC\Module\Configuration\ConsoleModuleContext;
|
||||
use KTXC\Module\ModuleManager;
|
||||
use KTXF\Module\ModuleConsoleInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Console\Application as ConsoleApplication;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
@@ -34,15 +34,13 @@ final class ConsoleRuntime
|
||||
|
||||
/** @var ModuleManager $moduleManager */
|
||||
$moduleManager = $container->get(ModuleManager::class);
|
||||
$moduleContext = new ConsoleModuleContext();
|
||||
foreach ($moduleManager->list() as $module) {
|
||||
$instance = $module->instance();
|
||||
if (!$instance instanceof ModuleConsoleInterface) {
|
||||
continue;
|
||||
}
|
||||
$module->configure($moduleContext);
|
||||
}
|
||||
|
||||
foreach ($instance->registerCI() as $commandClass) {
|
||||
$this->registerCommand($console, $container, $commandClass);
|
||||
}
|
||||
foreach ($moduleContext->commands() as $commandClass) {
|
||||
$this->registerCommand($console, $container, $commandClass);
|
||||
}
|
||||
|
||||
return $console->run($input, $output);
|
||||
|
||||
Reference in New Issue
Block a user