johnnyxlemonade / framework
Modular PHP 8.3+ framework with PSR-based HTTP runtime, PSR-11 compatible DI container, provider-based bootstrap and CLI kernel.
Requires
- php: >=8.3 <8.6
- composer-runtime-api: ^2.2
- ext-fileinfo: *
- ext-mbstring: *
- ext-xmlwriter: *
- nyholm/psr7: ^1.8
- nyholm/psr7-server: ^1.1
- psr/cache: ^3.0
- psr/container: ^2.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^3.0
- symfony/yaml: ^6.4 || ^7.0
Requires (Dev)
- code-lts/doctum: ^5.6
- friendsofphp/php-cs-fixer: ^v3.94
- giorgiosironi/eris: ^1.1.0
- guzzlehttp/guzzle: ^7.10 || ^8.0
- infection/infection: 0.35.6
- phpstan/phpstan: ^2.3
- phpstan/phpstan-strict-rules: ^2.1
- phpunit/phpunit: ^10.5 || ^11.0
Suggests
- ext-curl: Required by selected HTTP client implementations when using cURL transport.
- ext-gd: Required for bitmap image decoding, transformation, and encoding.
- ext-mysqli: Required for the MySQLi database driver.
- ext-odbc: Required for the ODBC database driver.
- ext-pdo: Required for the PDO database driver.
- guzzlehttp/guzzle: Required when using the built-in Guzzle PSR-18 HTTP client provider.
- php-http/curl-client: Required when using the built-in PHP-HTTP cURL PSR-18 client provider.
- php-http/discovery: Required when using automatic PSR-18 HTTP client discovery.
- symfony/http-client: Required when using the built-in Symfony PSR-18 HTTP client provider.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-13 15:09:16 UTC
README
Lemonade Framework is a modular PHP 8.3+ application framework for maintainable web applications, administration systems, CMS projects and integration-oriented services.
It combines a PSR-based HTTP runtime, a PSR-11 compatible service container, provider-based bootstrap, routing, a CLI kernel and reusable infrastructure for long-lived application development.
It is an application framework rather than a micro-framework layer. Its architecture keeps application flow explicit: a request enters the kernel, configuration is loaded, services are registered through providers, middleware is executed, the router resolves a controller action and the result is normalized into a PSR response.
The framework is intended for projects where predictable control flow and maintainable composition matter: internal tools, administration systems, CMS applications, backend integrations, cron-driven workflows and legacy-friendly modernization projects.
Status
This package is in pre-release development. Public APIs may still change before the first stable release.
Design Goals
Lemonade Framework favors visible application flow over hidden lifecycle magic.
The framework focuses on:
- explicit service registration through providers
- PSR-compatible HTTP primitives
- predictable synchronous request lifecycle
- shared HTTP and CLI composition model
- conservative dependency injection
- pragmatic controller ergonomics
- modular infrastructure services composed through providers
- CLI and cron-friendly execution
- strict typing and static-analysis-friendly APIs
Runtime Model
Lemonade Framework is designed for the traditional synchronous PHP runtime model:
- PHP-FPM
- Apache mod_php
- built-in PHP development server
- standard CLI execution
- cron jobs
It is not designed as a long-running worker framework. Environments such as Swoole or RoadRunner require stricter control over shared state, request-scoped services and service lifetimes.
An HTTP request is expected to run in an isolated PHP request lifecycle.
Installation
composer require johnnyxlemonade/framework
For local framework development:
composer install
Requirements
Required platform requirements:
- PHP
>= 8.3 < 8.6 ext-fileinfoext-mbstringext-xmlwriter
Official support covers PHP 8.3, 8.4 and 8.5. The syntax and runtime target is PHP 8.3: new framework source and generated PHP source must remain PHP 8.3 compatible, even when development or CI runs on PHP 8.4 or 8.5. Framework source does not use PHP 8.4+ syntax.
Composer installs the required PSR and Nyholm packages automatically.
Optional dependencies depend on selected modules and integrations:
ext-gdfor image upload re-encodingext-pdofor the PDO database driverext-mysqlifor the MySQLi database driverext-odbcfor the ODBC database driverext-curlfor selected HTTP client implementations using cURL transportguzzlehttp/guzzlefor the built-in Guzzle PSR-18 HTTP client providersymfony/http-clientfor the built-in Symfony PSR-18 HTTP client providerphp-http/curl-clientfor the built-in PHP-HTTP cURL PSR-18 client providerphp-http/discoveryfor automatic PSR-18 HTTP client discovery
What the Framework Provides
The framework source is organized into focused modules under src/. Applications compose them through service providers, so configured services remain the integration boundary instead of manually wired framework internals.
Runtime, HTTP and Routing
Core— application context, HTTP and CLI kernels, provider bootstrap, controller dispatch and response normalization; each HTTP run uses an isolated Request scopeHttp— PSR-7 request and response handling, PSR-15 middleware pipeline, response emitting,HttpStatusenum and Nyholm PSR-17 integration- HTTP middleware for errors, CORS,
OPTIONS, request logging, benchmarks, HTML minification and response headers Routing— explicit controller actions, normalized route paths, route collections, named routes and URL generation, route groups and localized routesApi— configurable endpoint registry, health endpoint, OpenAPI and HTML documentation, Problem Details responses, and bearer-token scope authorization
Container, Providers and Configuration
Container— PSR-11 runtime resolution with a separate frozen definition builder; transient, singleton and scoped lifetimes; aliases, decorators, contextual bindings and conservative autowiringServiceProviderInterface— explicit registration and composition of framework, application and integration services, with bootstrap-safe provider constructor DI and dependency orderingConfig— YAML application configuration mapped to typed definitions and runtime DTOs, environment values and production config caching- package extension points for application providers, API endpoint providers, event listeners, sitemap providers, views and components
CLI and Operations
Cliandbin/lemonade— lazy command definitions, command registry and a CLI kernel; a selected command runs in its own Command scope withCommandContext,CommandInputandCommandOutput- command-driven operations such as migrations, queue installation and workers, and sitemap generation; suitable for cron-driven tasks
Discovery— configurablerobots.txt, sitemap and sitemap-index generation
Data, State and Integration
Database— PDO, MySQLi and ODBC drivers, schema tools, migrations and explicit migration-directory discovery; no ORM is requiredCache— PSR-6 cache pools with file, array and null storesFilesystemandSession— storage and session servicesEvent— scoped event dispatch with immutable listener definitions, class listeners and prioritiesQueue— synchronous and database-backed transports, message serialization, delayed jobs and worker commands; class-string handlers run in isolated Job scopes- optional PSR-18 HTTP client providers for Guzzle, Symfony HTTP Client and PHP-HTTP cURL transport
Application Building Blocks
LocalizationandValidation— file-backed translation catalogs, locale-aware routing support and validation rulesSecurity— CSRF token management, middleware and view helpersUpload— profile-based file and image uploads, MIME and dimension validation, storage, and optional GD re-encodingViewandComponent— view resources and helpers plus reusable pagination, breadcrumb and metadata componentsLogging,DebugandObservability— PSR-3 logging, diagnostics and request/database benchmark data
Support Utilities
Lemonade\Framework\Support\Slug\Slugger— a URLify-inspired best-effort ASCII slug generator with curated transliteration maps; it is intended for URL slugs, not as a general Unicode transliterator- environment and base-URL helpers, escaping and formatting helpers, clock abstractions and XML stream writing
Basic Usage
HTTP entrypoint
A typical HTTP entrypoint creates an application context, creates the kernel and lets the kernel handle the current request.
<?php use Lemonade\Framework\Core\Context\ApplicationContextFactory; use Lemonade\Framework\Core\KernelFactory; require __DIR__ . '/../vendor/autoload.php'; $context = (new ApplicationContextFactory())->fromGlobals( dirname(__DIR__), ); $kernel = (new KernelFactory())->create($context); $kernel->handle();
Routes
Routes are usually defined in app/Config/Routing.php.
<?php use Lemonade\Framework\Routing\Router; use Lemonade\Framework\Routing\ControllerAction; return static function (Router $router): void { $router->getNamed('home', '/', ControllerAction::for(HomeController::class, 'index')); $router ->get('/articles/{id}', ControllerAction::for(ArticleController::class, 'detail')) ->name('article.detail'); };
Controller
New controllers are plain final classes with explicit constructor dependencies. The
framework resolves them in the active Request scope, and action methods must be public.
<?php namespace App\Controllers; final class HomeController { public function __construct( private readonly HomePage $homePage, ) {} public function index(): string { return $this->homePage->render(); } }
Controller actions may return a PSR response directly. Scalar, stringable and null return values are normalized into HTML responses.
Controllers use constructor injection for services and action arguments for request and route data. See the controller documentation.
Service Provider
Application services are registered through providers.
New providers register definitions through ServiceProviderInterface::register(). Providers that need
runtime initialization additionally implement BootableServiceProviderInterface for boot(). See service provider documentation.
<?php namespace App\Providers; use App\Services\InvoiceImporter; use Lemonade\Framework\Container\ContainerBuilderInterface; use Lemonade\Framework\Core\ServiceProviderInterface; final class AppServiceProvider implements ServiceProviderInterface { public function register(ContainerBuilderInterface $builder): void { $builder->singleton(InvoiceImportRegistry::class, InvoiceImportRegistry::class); } }
Application providers are configured in app/Config/Providers.yaml.
module: providers config: providers: - App\Providers\AppServiceProvider
Configuration
Application config uses YAML as the primary app-level format, but the framework still loads typed config definitions internally.
app/Config/Config.yaml declares the shared and entrypoint-specific config files:
shared: - App - Providers - Api http: - HtmlMinify cli: - Commands
Each YAML file is only an input adapter. It is mapped to a concrete *ConfigDefinition class, then resolved through the existing typed resolvers and runtime DTOs. YAML is not the internal core config model.
module: api config: enabled: true prefix: /api framework: docs: enabled: true
Environment-backed values use explicit YAML directives:
module: app config: base_url: $env: APP_BASE_URL type: string default: http://localhost
If an application needs a custom config definition that is not covered by the built-in registry, app/Config/ConfigMap.php can be used as an advanced extension point to map YAML file aliases to ConfigDefinitionInterface classes. This is not part of the primary happy-path application setup.
In production, application config definitions are compiled automatically into entrypoint-specific generated PHP cache files under storage/cache/framework/config/. Development and testing load YAML or explicit PHP sources returning ConfigDefinitionInterface directly; raw PHP arrays are not supported. See docs/configuration.md for cache lifecycle, invalidation, and deployment workflow details.
CLI Command
CLI commands implement CommandInterface and are configured in app/Config/Commands.yaml.
<?php namespace App\Console; use Lemonade\Framework\Cli\CommandInterface; final class ImportProductsCommand implements CommandInterface { public function name(): string { return 'products:import'; } public function description(): string { return 'Import products from the configured source.'; } /** * @param list<string> $args */ public function run(array $args): int { // ... return 0; } }
module: commands config: commands: - App\Console\ImportProductsCommand
Run commands through:
vendor/bin/lemonade vendor/bin/lemonade list vendor/bin/lemonade products:import
Documentation
Detailed documentation lives in docs/index.md.
For lifecycle details, see HTTP flow, CLI flow, service container, service providers, database migrations and infrastructure modules.
ORM Integration
Lemonade does not include or require an ORM. The live Doctrine ORM example is an optional application-level integration registered through an application service provider and the container.
It demonstrates Doctrine ORM with SQLite, ManyToMany relations, author and tag filtering with faceted counts, pagination, and toIterable() for the main article feed.
Testing
The framework uses complementary testing techniques:
- Property-based testing (Eris) generates varied input datasets and verifies invariants across a broader input space than example-based tests alone.
- Mutation testing (Infection) applies small changes to production code and checks whether the test suite detects the resulting behavioral changes. Manual local suites cover the routing core, container invariants and the
Sluggerutility.
Run the standard quality suite with:
composer qa
Property-based tests can also run separately:
composer test:property
Run routing mutation tests with:
composer test:mutation:routing
Run container mutation tests, including tagged-service collection invariants, with:
composer test:mutation:container
Run manual Slugger mutation tests with Xdebug coverage enabled:
composer test:mutation:slugger
Regenerate local API documentation with Doctum:
composer docs:api
Code Quality
The project is designed to be static-analysis friendly.
Development scripts:
composer lint composer stan composer stan:ci composer cs:check composer cs:fix composer qa composer check
composer check runs full validation including Composer validation, platform checks, syntax linting, coding standards, PHPStan and tests.
Development Server
The framework package does not provide a standalone HTTP application entrypoint or public scaffold. Run its HTTP runtime through a consuming application's own public entrypoint and document root.
License
MIT License. See LICENSE for details.