Closed brendt closed 1 month ago
@brendt - Not to beat a dead horse, but I think it makes sense for the kernel to be completely configuration unaware and only accept the root project path and, optionally, a container instance. Then we can determine the absolutely critical items to setup first (e.g., configuration, exception handling, etc.) and pass off to other items (through events 🙈 or other). This lets the kernel only be concerned with the things need to orchestrate handing off to other services.
For example:
final class Kernel
{
private readonly string $basePath;
private ?Container $container;
private EventBus $eventBus;
public function __construct(string $basePath, ?Container $container = null)
{
$this->basePath = rtrim($basePath, '\\/');
$this->container = $container;
}
public function run(): void
{
$this->boot();
$this->container->get(ConsoleCommandHandler::class)->handle();
$this->shutdown();
}
private function boot(): void
{
$this->bootContainer();
$this->bootConfigurationManager();
$this->bootEventBus();
$this->eventBus->dispatch('kernel.booted');
}
private function bootContainer(): void
{
$this->container ??= new GenericContainer();
}
private function bootConfigurationManager(): void
{
$this
->container
->get(ConfigurationManager::class)
->addLocation($this->basePath . DIRECTORY_SEPARATOR . 'config')
->load();
}
private function bootEventBus(): void
{
$this->eventBus = $this->container->get(EventBus::class);
}
private function shutdown(): void
{
// Clear the cache, whatever...
$this->eventBus->dispatch('kernel.shutdown');
}
}
final class DiscoveryInitializer
{
#[EventHandler('kernel.booted')]
public function onKernelBooted()
{
// Cool! Run discovery...
}
}
I'm not disagreeing, and after playing around with my proposed solution, I think it makes sense to pull out as much out of kernel as possible.
What we really need to know up front:
Then, during bootstrap, we're populating discovery locations and discovery classes. These should live outside of appconfig, but this is something the kernel needs to touch.
So, my proposal would be to pull these requirements out of appconfig, and make appconfig normal like any other config. There'll need to be some kind of KernelConfig
object — or something that stores the root path and discovery data — because we need that data in other places as well (think eg. the discovery status command).
What I don't agree on is that the kernel should work without the container.
@brendt - where are you seeing me say the kernel should work without the container?
We don't need to know anything regarding discovery, as that can be dependency injected as long as we are resolving everything through the container. We just need to make loading configurations part of the boot process.
My bad, I misread 😁
What's still problematic to me: in order to boot config, we need to know all discovery locations. Where will those be resolved, and where will we store them? (The currently live in app config, which is why all of this is a mess).
All good. I wondered if that was the case. 🙃
We don't need package configuration files to boot the kernel, right? Just certain config files in the project root.
I'm thinking we want a config service that scans (or restores from cache) configuration classes in a directory when addLocation
is called. The kernel adds the base path and a separate service adds other locations on the boot event. 🙂
Will be fixed by #367
There's a problem with environment variables when you provide an AppConfig in
index.php
ortempest
before the framework is booted: there aren't any loaded environment variables yet. The best solution is for theenv
function to return some kind of proxy object if environment variables aren't loaded yet, and resolve those objects wheneverTempest::boot
is triggered