spiral / framework

High-Performance PHP Framework
https://spiral.dev
MIT License
1.8k stars 87 forks source link

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

Closed msmakouz closed 10 months ago

msmakouz commented 10 months ago

Spiral continues to evolve, offering more flexibility and efficiency in its latest update. Developers now have enhanced control over the configuration of bootloaders. This update is particularly beneficial for tailoring applications to different environments, such as HTTP, CLI, or gRPC, by enabling or disabling specific bootloaders as needed. It allows for a more nuanced and environment-specific configuration of bootloaders. This feature is particularly useful in scenarios where certain bootloaders are only relevant in specific contexts. For instance, in an HTTP environment, bootloaders like HTTPBootloader and RoutesBootloader are essential, whereas they might be unnecessary in CLI or gRPC environments. By enabling the selective enabling or disabling of bootloaders, it helps in optimizing resource usage and improving application performance.

BootloadConfig

There is a new DTO class Spiral\Boot\Attribute\BootloadConfig which enables the inclusion or exclusion of bootloaders, passing parameters that will be forwarded to the init and boot methods of the bootloader, and dynamically adjusting the bootloader loading based on environment variables. It can be used within the Kernel as a value in the array of bootloaders. Alternatively, it can be used as an attribute that needs to be added to the bootloader class.

The BootloadConfig class constructor accepts the following parameters:

Usage in Kernel

To use it in the Kernel, you should employ the full class name of the bootloader as the key in the array of bootloaders, with the corresponding value being a Spiral\Boot\Attribute\BootloadConfig object.

namespace App\Application;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Prototype\Bootloader\PrototypeBootloader;

class Kernel extends \Spiral\Framework\Kernel
{
    // ...
    public function defineBootloaders(): array
    {
        return [
            // ...
            PrototypeBootloader::class => new BootloadConfig(allowEnv: ['APP_ENV' => ['local', 'dev']]),
            // ...
        ];
    }

    // ...
}

In this example, we specified that the PrototypeBootloader should be loaded only if the environment variable APP_ENV is defined and has a value of local or dev.

Instead of creating a BootloadConfig object directly, you can define a function that returns a BootloadConfig object. This function can take arguments, which might be obtained from the container.

namespace App\Application;

use Spiral\Boot\Attribute\BootloadConfig;
use Spiral\Boot\Environment\AppEnvironment;
use Spiral\Prototype\Bootloader\PrototypeBootloader;

class Kernel extends \Spiral\Framework\Kernel
{
    // ...
    public function defineBootloaders(): array
    {
        return [
            // ...
            PrototypeBootloader::class => fn (AppEnvironment $env) => new BootloadConfig(enabled: $env->isLocal()),
            // ...
        ];
    }

    // ...
}

Using Attributes for Bootloader Configuration

You can also use Spiral\Boot\Attribute\BootloadConfig class as an attribute to control how a bootloader behaves. This method is particularly useful because it allows you to set up the configuration directly in the bootloader's class, making it more straightforward and easier to understand.

Here's a simple example of how you can use an attribute to configure a bootloader:

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

#[BootloadConfig(allowEnv: ['APP_ENV' => 'local'])]
final class SomeBootloader extends Bootloader
{
}

Attributes are a great choice when you want to keep the configuration close to the bootloader's code. It's a more intuitive way to set up bootloaders, especially in cases where the configuration is straightforward and doesn't require complex logic. By using attributes, you can easily see and understand the conditions under which a particular bootloader will be active, all in one place.

Extending for Custom Preconditions

By extending BootloadConfig, you can create custom classes that encapsulate specific conditions under which bootloaders should operate. This approach simplifies the usage of bootloaders by abstracting the configuration details into these custom classes.

Here's an example

class TargetRRWorker extends BootloadConfig {
    public function __construct(array $modes)
    {
        parent::__construct(
            env: ['RR_MODE' => $modes],
        );
    }
}

Now you can use it in your bootloaders

use Spiral\Boot\Bootloader\Bootloader;

#[TargetRRWorker(['http'])]
final class HttpBootloader extends Bootloader
{
    // Bootloader code goes here
}

or use in Kernel:

namespace App\Application;

use Spiral\Framework\Kernel;

class Kernel extends Kernel
{
    public function defineBootloaders(): array
    {
        return [
            HttpBootloader::class => new TargetRRWorker(['http']),
            RoutesBootloader::class => new TargetRRWorker(['http']),
            // Other bootloaders...
        ];
    }
}

The ability to extend BootloadConfig opens up a world of possibilities for customizing the behavior of bootloaders.

codecov[bot] commented 10 months ago

Codecov Report

Attention: 1 lines in your changes are missing coverage. Please review.

Comparison is base (c618ac7) 89.19% compared to head (2d2886f) 89.23%. Report is 5 commits behind head on master.

Files Patch % Lines
src/Boot/src/BootloadManager/Initializer.php 97.82% 1 Missing :warning:
Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #1017 +/- ## ============================================ + Coverage 89.19% 89.23% +0.03% - Complexity 6138 6188 +50 ============================================ Files 809 816 +7 Lines 17338 17447 +109 ============================================ + Hits 15464 15568 +104 - Misses 1874 1879 +5 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.