Core

Application Core

ApplicationContext, kernels, runtime lifecycle, načítání konfigurace a orchestrace service providerů.

Runtime model

Application Core is composed from ApplicationContext, Framework, HTTP Kernel, CliKernel, typed config definitions/runtime DTOs, ControllerResolver, service providers and container services. HTTP and CLI share the same context/config/provider model, but use different entry kernels.

ApplicationContext

ApplicationContext stores environment (Environment), debug mode (DebugMode) and resolved paths (Path). It is shared by HTTP and CLI runtimes and exposes helpers such as environment(), debug(), basePath(), path(), appPath(), configPath(), storagePath(), resolveWritablePath(), resolveLogPath(), resolveUploadPath() and resolveCachePath().

example.php
use Lemonade\Framework\Core\Context\ApplicationContextFactory;

$context = (new ApplicationContextFactory())->fromGlobals(__DIR__);

$context->environment();
$context->debug();
$context->basePath();
$context->configPath('Routing.php');

Context factory

ApplicationContextFactory::fromGlobals($basePath) normalizes the base path, loads .env, then reads APP_ENV, APP_DEBUG and optional APP_BASE_PATH from $_ENV, $_SERVER or getenv(). APP_ENV maps to dev, test or prod; debug defaults to enabled outside production unless APP_DEBUG overrides it.

Kernel roles

Kernel is the HTTP runtime: it loads HTTP app config, bootstraps providers, loads routes from app/Config/Routing.php, runs the framework request pipeline and emits responses through handle(). CliKernel is the CLI runtime: it loads CLI app config, bootstraps providers, builds CommandRegistry, runs CommandInterface::run() and returns an exit code.

Bootstrap internals

KernelBootstrapTrait is an internal shared implementation detail used by both kernels. It resolves typed runtime config DTOs, registers core diagnostic providers, registers configured framework providers from FrameworkConfig, and then registers application providers from ProvidersConfig.

Config loading

Framework creates a typed config registry during construction and loads framework defaults. ConfigLoader then reads app/Config/Config.yaml, combines shared with the current entrypoint section (http or cli), and loads each listed YAML config file through Framework::configFromFile(). YAML is only an app-level input layer: each file is mapped to a concrete ConfigDefinitionInterface implementation and then resolved through the existing typed resolvers and runtime DTOs. Internal framework config architecture stays typed; YAML is not the core config model.

example.php
app/Config/Config.yaml
shared:
  - App
  - Queue
http: []
cli: []

app/Config/App.yaml
module: app
config:
  base_url: https://example.test
  timezone: Europe/Prague

Providers

Providers implement ServiceProviderInterface and register container bindings. Core diagnostic providers (CoreServiceProvider, filesystem, cache and logging) are registered first, HTTP or console provider is registered by the matching kernel, common framework providers come from framework.providers, and application providers come from providers.

example.php
use Lemonade\Framework\Container\ContainerInterface;
use Lemonade\Framework\Core\ServiceProviderInterface;

final class ExampleProvider implements ServiceProviderInterface
{
    public function register(ContainerInterface $container): void
    {
        $container->singleton(ExampleService::class, ExampleService::class);
    }
}

Container

ContainerInterface extends PSR-11 Psr\Container\ContainerInterface and adds set(), singleton(), isBound() and diagnostic logger support. Container can autowire concrete classes by constructor types as a fallback, but stable framework bootstrapping relies on explicit provider bindings, especially for interfaces.

Controller dispatch

ControllerResolver::handle(RouteMatch $match, ServerRequestInterface $request) binds the live request for dispatch, resolves the controller from the container, validates the action method, maps route params to action arguments, injects ServerRequestInterface when requested and normalizes scalar/stringable/null action results to a PSR-7 HTML response.

example.php
$response = $resolver->handle($match, $request);

// Action return values may be ResponseInterface, scalar, stringable or null.

HTTP flow

HTTP entrypoints create context through ApplicationContextFactory, create a kernel through KernelFactory and call Kernel::handle(). Kernel::handle() creates a request from globals when needed, calls Kernel::run(), then emits through ResponseEmitter. Framework::run() builds the global PSR-15 middleware pipeline and falls back to DispatchRequestHandler, which matches a route, applies route middleware and dispatches the controller.

example.php
public/index.php
-> ApplicationContextFactory::fromGlobals()
-> KernelFactory::create()
-> Kernel::handle()
-> Kernel::bootstrap()
-> Framework::run()
-> MiddlewarePipeline
-> DispatchRequestHandler
-> ControllerResolver
-> ResponseEmitter

CLI flow

The Composer binary vendor/bin/lemonade proxies to the framework CLI entrypoint. It resolves the application base path, builds ApplicationContext, creates CliKernel through CliKernelFactory, forwards argv to CliKernel::handle() and exits with the returned code.

example.php
vendor/bin/lemonade
-> CliEnvironmentResolver::resolveBasePath()
-> ApplicationContextFactory::fromGlobals()
-> CliKernelFactory::create()
-> CliKernel::handle($argv)
-> CliKernel::bootstrap()
-> CommandRegistry
-> CommandInterface::run($args)
-> exit code

HTTP entrypoint

A minimal HTTP entrypoint delegates bootstrapping to context and kernel factories.

example.php
<?php

declare(strict_types=1);

use Lemonade\Framework\Core\Context\ApplicationContextFactory;
use Lemonade\Framework\Core\KernelFactory;

require __DIR__ . '/../vendor/autoload.php';

$context = (new ApplicationContextFactory())->fromGlobals(dirname(__DIR__));

(new KernelFactory())
    ->create($context)
    ->handle();

CLI entrypoint

Application code normally runs CLI through vendor/bin/lemonade. If a custom CLI entrypoint is needed, use CliKernelFactory instead of manually wiring container/framework/kernel objects.

example.php
<?php

declare(strict_types=1);

use Lemonade\Framework\Core\CliKernelFactory;
use Lemonade\Framework\Core\Context\ApplicationContextFactory;

require __DIR__ . '/../vendor/autoload.php';

$context = (new ApplicationContextFactory())->fromGlobals(dirname(__DIR__));
$argv = $_SERVER['argv'] ?? [];

exit((new CliKernelFactory())->create($context)->handle(array_values($argv)));

Error boundaries

Kernel::run() catches route-not-found and unexpected exceptions that escape the middleware pipeline, logs them through ExceptionLogger and returns debug-aware 404/500 text responses. ErrorHandlingMiddleware handles normal HTTP pipeline exceptions as HTML responses. CliKernel catches exceptions, logs through ExceptionLogger, writes an error to stderr and returns exit code 1.

Boundary

Core runtime defines bootstrapping, configuration, container wiring and dispatch mechanics. Application routes, controllers, views, domain services and business workflows are intentionally outside this overview and belong to their dedicated documentation pages or application code.