Changelog
All XPSR packages share one version number. See docs/VERSIONING.md for what each kind of release promises.
Unreleased
0.3.0 (2026-10-28)
Nothing breaks; upgrade steps are in UPGRADE.md.
Added
crystoline/xpsr-log-monolog: an optional package that makes Monolog the application logger, writing to stderr, a file, daily files, or syslog (LOG_CHANNEL), as lines or JSON (LOG_FORMAT, JSON by default in production), with a request ID on every line fromRequestIdMiddleware, which also echoes it inX-Request-Id. See its README.- Rate limiting in
crystoline/xpsr-cache: named sliding-window limits inconfig/rate_limit.php, attached with->middleware(RateLimit::named('login'))or throughapp.middleware. Clients are counted by address through the trusted proxies, or by a custom key resolver. Over the limit, 429 withRetry-After;X-RateLimit-LimitandX-RateLimit-Remainingon every response. See its README. - Request validation. The framework defines
Crystoline\Xpsr\Validation\ValidatorInterface,ValidationException(422 with field errors, shown in every environment), andInputMapper, which maps the body, query string, or route parameters onto input classes: field names from#[Field]and#[Input(naming: 'snake')], filters (Trim,Lowercase,Uppercase,EmptyToNull,Replace, custom#[Filter]), and type conversion reported as field errors. The newcrystoline/xpsr-validationpackage implements the rules with Symfony Validator and registersmake:input. See its README. Crystoline\Xpsr\Http\Exception\PublicErrorInterface: an error whose message and details the exception handler shows to clients in every environment.Crystoline\Xpsr\Http\ClientIp: the client address of a request, read through the trusted proxies'X-Forwarded-Forchain.
0.2.0 (2026-10-28)
Upgrade steps are in UPGRADE.md.
Breaking
- Every class moves from
Crystoline\toCrystoline\Xpsr\, for exampleCrystoline\ApplicationtoCrystoline\Xpsr\Application,Crystoline\Cache\CacheServiceRegistrytoCrystoline\Xpsr\Cache\CacheServiceRegistry, andCrystoline\Router\FastRoute\FastRouteRoutertoCrystoline\Xpsr\Router\FastRoute\FastRouteRouter. The vendor namespace is no longer taken by one product, and it matches thecrystoline/xpsr-*package names. There are no aliases for the old names;UPGRADE.mdhas a command that rewrites them. - The
database_path()helper is removed. It pointed at adatabase/directory XPSR does not use; migrations live inmigrations/. The 0.1 skeleton'sconfig/database.phpcalls it, so replace or delete that file when upgrading.
Added
- PSR-14 events:
Crystoline\Xpsr\Events\EventDispatcher,ListenerProvider, and the optionalStoppableEventbase class, registered byCrystoline\Xpsr\Registry\EventServiceRegistry. Listeners are listed inconfig/events.phpor added by providers with a priority. See docs/EVENTS.md. php xpsr event:list,make:event, andmake:listener.- New projects list
EventServiceRegistryinapp.registryand includeconfig/events.php. Existing projects can add both to use events. crystoline/xpsr-http-client: an optional package providing a configured PSR-18 client, named clients (http_client.<name>) with their own base URL and headers, Symfony'sHttpClientInterface, andTesting\FakeClientfor tests. Options live inconfig/http_client.php. See its README.swap($id, $replacement)in the applicationtests/TestCase.php, to replace a service in a test.crystoline/xpsr-database: an optional package providing Doctrine DBAL connections configured inconfig/database.php, and migrations withmigrate,migrate:rollback,migrate:status, andmake:migration. In production, migrations need--forceor a confirmation. See its README.- Database extension points: the migrate commands use
MigratorInterface, chosen withdatabase.migrations.runner, so another runner can replace XPSR's;Testing\MigratorContractTestCasechecks a runner;Testing\DatabaseTransactionsrolls back each test's database writes. crystoline/xpsr-orm-doctrine: an optional Doctrine ORM 3 adapter. TheEntityManagerruns on XPSR's connection, with attribute-mapped entities inapp/Entity, snake-case columns, PHP 8.4 native lazy objects instead of proxy classes, and the application cache for metadata in production. Includes Doctrine's read-only and cache commands, an XPSRorm:validate-schema, andClearEntityManagerMiddlewarefor worker servers. See its README.php xpsr make:migration <name> --diffwrites a migration from the difference between the database and an expected schema, such as Doctrine's entity mapping. Only tables the schema names are compared.Schema\SchemaProviderInterfacelets an ORM adapter supply the schema;Testing\OrmAdapterContractTestCasechecks ORM adapters.- CORS:
Crystoline\Xpsr\Http\Middleware\CorsMiddleware, configured inconfig/cors.phpandCORS_ALLOWED_ORIGINS. It answers preflight requests, adds the headers to every response from an allowed origin, error responses included, and supports subdomain patterns. New projects list it first inapp.middleware; it is inactive until an origin is allowed. See docs/HTTP.md. - PSR-20 clock:
Psr\Clock\ClockInterfaceis registered as asymfony/clockNativeClockinapp.timezone. The applicationTestCasegainsfreezeTime().
Changed
- The skeleton's
config/database.phpis replaced: the previous file was unused and came from another framework. The new one configures SQLite, MySQL, and PostgreSQL connections forcrystoline/xpsr-database.
Fixed
- Route building is 18 to 48 times faster. Route patterns were parsed again on every use, and constraints re-validated each time, so 300 routes took about 276 ms per request; they now take about 6 ms.
RouteCollection::named()and URL generation no longer scan every route.
0.1.1 (2026-10-28)
Fixed
php xpsr aboutandphp xpsr --versionreport the installed framework version, such as0.1.1, instead of always sayingdevelopment.
Deprecated
Crystoline\Console\ConsoleKernel::VERSION. UseConsoleKernel::version(). The constant still exists and still equalsdevelopment.
0.1.0 (2026-10-28)
First release of the rebuilt framework. It replaces the earlier prototype, which was published as crystoline/xpsr v1.0.0; there is no upgrade path from it. Start a new project and move application code across.
Added
- Packages:
crystoline/xpsr(skeleton),crystoline/xpsr-framework,crystoline/xpsr-router-fastroute, andcrystoline/xpsr-router-sunrise. - Application bootstrap with
.envloading and per-environment configuration overrides (config/{APP_ENV}/). - PSR-11 container with explicit bindings, autowiring, aliases, and eager or deferred service providers with register/boot stages.
- PSR-15 HTTP kernel, global and route middleware, body parsing for JSON and non-POST forms, and a response emitter.
- Portable route definitions with groups, names, constraints, defaults, and URL generation, served by the FastRoute or Sunrise adapter. HEAD, OPTIONS, 404, and 405 are handled.
- JSON or HTML error rendering by content negotiation; exception details only with
APP_DEBUG=true. Server errors are logged through PSR-3 (error_log()by default). - Forwarding headers trusted only from
TRUSTED_PROXIES. xpsrconsole withabout,route:list,serve,setup, and themake:controller,make:middleware,make:command, andmake:providergenerators.- Application test scaffold (
tests/TestCase.php) with request and console helpers. - Router contract test suite for adapter authors (
Crystoline\Testing\RouterContractTestCase). - Documentation: getting started, deployment, HTTP, routing, container, console, packages, and versioning.
Cache
crystoline/xpsr-cache: an optional package providing the application cache as PSR-16 and PSR-6, backed by Symfony Cache, withfile,array,null, andservicedrivers and acache:clearcommand.
HTTP exceptions
Crystoline\Http\Exception\*:HttpException,HttpExceptionInterface, and classes for 400, 401, 403, 404, 405, 409, 413, 415, 422, 429, and 503. The framework no longer depends onsymfony/http-kernelorsymfony/http-foundation. Symfony's HttpKernel exceptions are still rendered with their status when that package is installed.
Optional dependencies
twig/twig(views) andfilp/whoops(debug error pages) are suggestions of the framework, not requirements. The skeleton requires Twig for its web example and installs Whoops for development only. Without Whoops, debug mode shows a plain built-in error page.
Requirements
- PHP 8.4 or 8.5.