Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[spiral/boot] Added the ability to configure bootloaders via BootloadConfig #1017

Merged
merged 2 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Boot/src/AbstractKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ public function run(?EnvironmentInterface $environment = null): ?self
function (Container $container): void {
$registry = $container->get(BootloaderRegistryInterface::class);

$this->bootloader->bootload($registry->getSystemBootloaders());
/** @psalm-suppress TooManyArguments */
$this->bootloader->bootload($registry->getSystemBootloaders(), [], [], false);
$this->fireCallbacks($this->runningCallbacks);

$this->bootload($registry->getBootloaders());
Expand Down
20 changes: 20 additions & 0 deletions src/Boot/src/Attribute/BootloadConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\Attribute;

use Spiral\Attributes\NamedArgumentConstructor;

#[\Attribute(\Attribute::TARGET_CLASS), NamedArgumentConstructor]
class BootloadConfig
{
public function __construct(
public array $args = [],
public bool $enabled = true,
public array $allowEnv = [],
public array $denyEnv = [],
public bool $override = true,
) {
}
}
13 changes: 9 additions & 4 deletions src/Boot/src/BootloadManager/AbstractBootloadManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ public function getClasses(): array
return $this->initializer->getRegistry()->getClasses();
}

public function bootload(array $classes, array $bootingCallbacks = [], array $bootedCallbacks = []): void
{
public function bootload(
array $classes,
array $bootingCallbacks = [],
array $bootedCallbacks = [],
bool $useConfig = true
): void {
$this->scope->runScope(
[self::class => $this],
function () use ($classes, $bootingCallbacks, $bootedCallbacks): void {
$this->boot($classes, $bootingCallbacks, $bootedCallbacks);
function () use ($classes, $bootingCallbacks, $bootedCallbacks, $useConfig): void {
/** @psalm-suppress TooManyArguments */
$this->boot($classes, $bootingCallbacks, $bootedCallbacks, $useConfig);
}
);
}
Expand Down
27 changes: 27 additions & 0 deletions src/Boot/src/BootloadManager/Checker/BootloaderChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Boot\Bootloader\BootloaderInterface;

final class BootloaderChecker implements BootloaderCheckerInterface
{
public function __construct(
private readonly CheckerRegistryInterface $registry = new CheckerRegistry(),
) {
}

public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool
{
foreach ($this->registry->getCheckers() as $checker) {
if (!$checker->canInitialize($bootloader, $config)) {
return false;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Boot\Bootloader\BootloaderInterface;

interface BootloaderCheckerInterface
{
/**
* @param class-string<BootloaderInterface>|BootloaderInterface $bootloader
*/
public function canInitialize(string|BootloaderInterface $bootloader, ?BootloadConfig $config = null): bool;
}
27 changes: 27 additions & 0 deletions src/Boot/src/BootloadManager/Checker/CanBootedChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Boot\Bootloader\BootloaderInterface;
use Spiral\Boot\BootloadManager\ClassesRegistry;

final class CanBootedChecker implements BootloaderCheckerInterface
{
public function __construct(
private readonly ClassesRegistry $bootloaders,
) {
}

public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool
{
$ref = new \ReflectionClass($bootloader);

return !$this->bootloaders->isBooted($ref->getName())
&& !$ref->isAbstract()
&& !$ref->isInterface()
&& $ref->implementsInterface(BootloaderInterface::class);
}
}
26 changes: 26 additions & 0 deletions src/Boot/src/BootloadManager/Checker/CheckerRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

final class CheckerRegistry implements CheckerRegistryInterface
{
/**
* @var array<BootloaderCheckerInterface>
*/
private array $checkers = [];

public function register(BootloaderCheckerInterface $checker): void
{
$this->checkers[] = $checker;
}

/**
* @return array<BootloaderCheckerInterface>
*/
public function getCheckers(): array
{
return $this->checkers;
}
}
15 changes: 15 additions & 0 deletions src/Boot/src/BootloadManager/Checker/CheckerRegistryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

interface CheckerRegistryInterface
{
public function register(BootloaderCheckerInterface $checker): void;

/**
* @return array<BootloaderCheckerInterface>
*/
public function getCheckers(): array;
}
28 changes: 28 additions & 0 deletions src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Boot\Bootloader\BootloaderInterface;
use Spiral\Boot\Exception\ClassNotFoundException;

final class ClassExistsChecker implements BootloaderCheckerInterface
{
/**
* @throws ClassNotFoundException
*/
public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool
{
if (!\is_string($bootloader)) {
return true;
}

if (!\class_exists($bootloader)) {
throw new ClassNotFoundException(\sprintf('Bootloader class `%s` is not exist.', $bootloader));
}

return true;
}
}
44 changes: 44 additions & 0 deletions src/Boot/src/BootloadManager/Checker/ConfigChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Spiral\Boot\BootloadManager\Checker;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Boot\Bootloader\BootloaderInterface;
use Spiral\Boot\EnvironmentInterface;

final class ConfigChecker implements BootloaderCheckerInterface
{
public function __construct(
private readonly EnvironmentInterface $environment,
) {
}

public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool
{
if ($config === null) {
return true;
}

if (!$config->enabled) {
return false;
}

foreach ($config->denyEnv as $env => $denyValues) {
$value = $this->environment->get($env);
if ($value !== null && \in_array($value, (array) $denyValues, true)) {
return false;
}
}

foreach ($config->allowEnv as $env => $allowValues) {
$value = $this->environment->get($env);
if ($value === null || !\in_array($value, (array) $allowValues, true)) {
return false;
}
}

return true;
}
}
11 changes: 8 additions & 3 deletions src/Boot/src/BootloadManager/DefaultInvokerStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ public function __construct(
) {
}

public function invokeBootloaders(array $classes, array $bootingCallbacks, array $bootedCallbacks): void
{
$bootloaders = \iterator_to_array($this->initializer->init($classes));
public function invokeBootloaders(
array $classes,
array $bootingCallbacks,
array $bootedCallbacks,
bool $useConfig = true
): void {
/** @psalm-suppress TooManyArguments */
$bootloaders = \iterator_to_array($this->initializer->init($classes, $useConfig));

foreach ($bootloaders as $data) {
$this->invokeBootloader($data['bootloader'], Methods::INIT, $data['options']);
Expand Down
Loading
Loading