Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Release Notes

Support Policy

Sukarix is currently supported for PHP 8.4+.

Released versions

Unreleased

Nothing yet.

v0.5.0

🚀 Features & Improvements

  • Version Number: 0.5.0
  • Release Date: 2026-09-14
  • General Overview: Adds JSON API building blocks (stateless routes, ApiAction, CORS, health probes, capability tokens), request correlation with structured JSON logging, encryption at rest for stored secrets, AMQP messaging, a session contract applications can implement themselves, environment-variable configuration overrides, and privilege discovery from the action directory — alongside CSRF, database, mail and PHP 8.5 compatibility fixes. The release is additive — no existing API changed, so upgrading from v0.4.0 requires no application changes.

🐛 Bug Fixes

  • CSRF Validation: Could not succeed for PUT, DELETE and PATCH requests, nor for any request sending a JSON body. See CSRF.
  • Records blank after an insert (sukarix): Model::insert() now reads the record back when the insert left it blank. PostgreSQL identity columns carry no nextval default, so Fat-Free does not recognise them as auto increment; the reload Cortex runs itself then filters on the identifier the record held before the insert, matches nothing, and leaves the whole record empty in memory — defaults and timestamps included. Any schema created for PostgreSQL 10 or later is affected. See Databases & Cortex.
  • smtpSend() return type (sukarix): The method declared bool and returned the message id on success, which under strict_types throws a TypeError in any caller that reaches a successful send. It returns a boolean, as send() already promised. The framework’s own suite never caught it because no test reached the success path; one was added.
  • Stateless prefixes could not be turned off (sukarix): SECURITY.stateless.prefixes fell back to the /api default whenever it was declared empty, because an .ini entry with nothing after the equals sign reads as null and the lookup used ?:. An application whose API relies on the session — one authenticating with a JWT session, for instance — had no way to say so. A declared key now wins even when empty. See Session.
  • Test suite aborted part-way (sukarix): The test bootstrap registered no injector aliases, so the first scenario constructing an Action died resolving access and took the rest of the run with it. Two of the three test groups never executed: the suite reported 71 passing tests where 165 existed.
  • MailSender date format (sukarix): The date template variable used strftime()-style specifiers, which date() doesn’t support, so emails rendered literal %A/%d/%B instead of a date. Fixed.
  • Pluggable session at boot (sukarix): Boot::$session was typed against the concrete Session class, so an application registering its own SessionInterface implementation failed with a TypeError before the first request. It is typed against the interface now.
  • Error pages (sukarix): The default ONERROR handler included templates/error/*.phtml relative to the working directory; it now resolves them through the UI search paths, so error pages render whatever directory the process was started from.

Changes

  • CSRF Token Transport (sukarix): The token is now read from the X-Csrf-Token header, then from REQUEST, and compared with hash_equals(). It was read from the verb hive, which Fat-Free populates for GET, POST and COOKIE only, so the other verbs Action::beforeroute() enforces were always rejected.
  • CSRF Token Lifetime (sukarix): The token stays valid until csrf.expiry instead of being consumed on first use, and generateToken() reuses a live one, so pages holding several forms or issuing successive writes keep working. The csrf_used session key is gone.
  • CSRF Exemptions (sukarix): New $csrfExempt property on Sukarix\Actions\Action for endpoints reached by external systems, which hold no session and must authenticate their caller by their own means.
  • Data & Filesystem Helpers (sukarix): New Sukarix\Utils\DataUtils, Sukarix\Utils\FileSystemUtils and Sukarix\Utils\CommandExecutor, extracted from duplicated code in bbb-lb and BBBAnalytiX. See Data & Filesystem Helpers.
  • Session Contract (sukarix): New Sukarix\Core\SessionInterface, declaring what the framework itself requires of a session — cleanupOldSessions(), set(), get(), isLoggedIn(), getRole() and validateToken(). Sukarix\Core\Session implements it and HasSession types its property against it, so an application can register its own implementation under the session alias without inheriting the database-backed one, and without its own static analysis reporting every call as undefined. The contract is deliberately the framework’s requirement rather than the full surface of the shipped session; a test asserts that every method Sukarix calls on a session is declared in it, so the two cannot drift. See Session.
  • Uniqueness Checks (sukarix): New Model::excludeId(), adding an identifier exclusion to a filter and dropping the clause when there is no identifier to exclude. Written by hand, ... and id != ? with a null identifier evaluates to NULL in SQL, which makes the whole condition unsatisfiable — so the uniqueness check passes for every record while one is being created, and duplicates are accepted. See Databases & Cortex.
  • Query Return Type (sukarix): Model::find() declares DB\CortexCollection|false. Cortex documents an array, so castAll() and the other collection methods read as errors in static analysis and in an editor.
  • Sender Identity (sukarix): The configured mailer.from_name is now put on the message. A relay such as Postal authenticates as one identity and sends as another, so the account, the address and the name beside it are three separate settings; without the name the mail arrived showing a bare address. See Emails.
  • Unreachable SMTP Servers (sukarix): MailSender checks that the server accepts a connection before handing the message to the transport, logs the failure and returns false. The transport aborts the whole request when the server cannot be reached — not an exception the application can catch — so a mail server outage took the request with it. The wait is configurable with mailer.smtp.timeout, two seconds by default.
  • Exception Reports (sukarix): Reports are sent under mailer.debugger_name, which defaults to Application Debugger, so an inbox receiving reports from several applications can tell them apart. The snooze marker moved from md5 to xxh128 and no longer relies on suppressed filesystem calls.
  • Environment Variables (sukarix): New [environment] configuration section mapping a variable name to the setting it stands in for, applied after the configuration is loaded. A setting that differs per host — and especially a secret — no longer has to live in a committed file. A variable that is unset or empty leaves the configured value alone. See Configuration.
  • Declared Privileges (sukarix): New Sukarix\Utils\PrivilegeUtils, reading the privileges an application declares from the action classes that carry them. A privilege is the first two namespace segments below the root, so classes nested deeper share the privilege of the group above them. It reads the directory rather than the composer class map, where an action added after the autoloader was dumped is missing — and its privilege then silently disappears from the role matrix, leaving a route nobody can be granted. See Authorisation System.
  • ORM Deprecations (sukarix): ikkez/f3-cortex still calls ReflectionProperty::setAccessible(), which PHP 8.5 deprecates and Tracy escalates into a fatal error on every ORM query. The bootstrap now drops E_DEPRECATED from the forced error level after Fat-Free and Tracy have set theirs. Set orm.mask_deprecations = false once Cortex is fixed.
  • Staging Environment (sukarix): Added Environment::STAGING, recognised alongside development and production. See Framework Variables.
  • Request Correlation & JSON Logging (sukarix): Boot mints or forwards an X-Request-Id header and stamps every log line with it. log.json switches LogWriter to structured JSON output. See Logging.
  • Building JSON APIs (sukarix): New ApiAction base class, Cors helper and Health\Probe endpoints, plus Bearer auth and form-encoded body support on Action. See Building JSON APIs.
  • Capability Tokens (sukarix): New Sukarix\Security\CapabilityToken::issue()/verify() for HMAC-signed, short-lived Bearer tokens. See Building JSON APIs.
  • CSRF Bounce Message (sukarix): A failed CSRF check now also sets a csrf_bounce session message. See CSRF.
  • Secrets at Rest (sukarix): New Sukarix\Security\SecretBox, a libsodium secretbox wrapper for encrypting credentials before they’re stored. See Encrypting Secrets at Rest.
  • Mail Tracking Hooks (sukarix): New Sukarix\Mail\Track, the on.failure/on.ping/on.jump callbacks smtp.ini wires into delivery-failure and open/click tracking. See Emails.
  • AMQP Messaging (sukarix): New Sukarix\Messaging\CommandPublisher interface with an AmqpPublisher (RabbitMQ) and a RecordingPublisher for tests. See Messaging.
  • Uploads & Locale Negotiation (sukarix): New Receiver::uploadImageBase64() and Receiver::upload() with MIME sniffing and size limits, and I18n::negotiateLocale() for Accept-Language headers. See File Upload and Translation / i18n.
  • Tooling (sukarix, statera): PHPStan 2, Rector 2 and PHPInsights 2.14 with a clean composer check; Statera runs on php-code-coverage 14 and declares it as a runtime requirement, so composer coverage works out of the box. The unused respect/validation and the retired phpdd are gone.
  • CLI Toolbox (cli): sukarix.sh follows APP_ENV and staging, detects the installed PHP-FPM service, and cleans sessions through the framework’s SessionsClean action. See CLI toolbox.
  • Skeleton Application (application): The landing page shows the 0.5.0 features, gradient titles and a comparison with Fat-Free, Slim, Laravel and Symfony, in all 16 languages.
  • Documentation: Rewrote the CSRF page. Added Data & Filesystem Helpers, Building JSON APIs, Encrypting Secrets at Rest and Messaging. Expanded Databases & Cortex with the insert read-back, uniqueness checks and the query return type; Session with the session contract and session-free routes; Emails with sender identity, unreachable servers and exception reports; Configuration with the [environment] section and the new settings; Authorisation System with privilege discovery; Logging with request correlation and structured JSON logging; File Upload with the new receiver methods; and Translation / i18n with locale negotiation. Refreshed the feature list, the CLI toolbox page and the stale claims a release audit turned up.

v0.4.0

🚀 Features & Improvements

  • Version Number: 0.4.0
  • Release Date: 2026-08-16
  • General Overview: Adds a Redis-backed queue service for pipeline workloads, a HasQueue behaviour to consume it, and optional coloured console logging. The release is additive — no existing API changed, so upgrading from v0.3.2 requires no application changes.

Changes

  • Queue Service (sukarix): New Sukarix\Queue namespace providing QueueService, a Redis-backed FIFO queue for passing work between pipeline stages. It adds membership-based deduplication (pushing an already-queued payload is a no-op) and per-item attempt counters on top of a Redis list. Enqueue and dequeue are executed as Redis Lua scripts, so a worker terminated mid-operation can never leave the list and the membership set disagreeing — an item is either fully queued and tracked, or neither. The queue counts attempts but intentionally owns no retry policy: deciding when a failing item is retried or parked stays with the application. See Queues.
  • Queue Logging (sukarix): New QueueProgressLogger emitting structured queue events (start, progress, completion, throughput, batch progress, per-item add/remove, warnings and errors) with a machine-parsable context array. Item previews are generic by design — an array is reported as array[3], never with its values — so payload contents never leak into logs. Applications can route queue telemetry elsewhere by registering a subclass under the queue.progress_logger Injector alias; a service that does not extend QueueProgressLogger is rejected with an \UnexpectedValueException.
  • HasQueue Behaviour (sukarix): New behaviour trait exposing the resolved queue service as a typed $queueService property. Resolution is strict by design: constructing a consumer without a registered queue service throws a \LogicException naming the class, and a service that does not extend QueueService is rejected with an \UnexpectedValueException. This surfaces a misconfiguration at boot rather than at the first queue call, where a null member access would point at the wrong place.
  • Console Logging (sukarix): LogWriter gained an optional standard-output handler enabled with log.console = true, intended for CLI applications. When bramus/monolog-colored-line-formatter is installed the output is coloured per level, otherwise a plain stream is used. The file handler remains active, so console output is added rather than substituted. See Logging.
  • Redis Connection Timeout (sukarix): The queue honours redis.timeout (default 2 seconds) and throws \RedisException when the connection cannot be established, so a misconfigured worker fails immediately instead of part-way through a run.
  • Documentation: Added a Queues page. Rewrote the Behaviours page to list every available trait with the property it injects and its visibility, documenting that HasAccess and HasEvents expose a private property that subclasses cannot read. Corrected its example, which called a non-existent $this->log->write() instead of the $this->logger Monolog instance the LogWriter trait actually provides. Expanded Logging with the logger API, log.level and the new log.console setting. Added Queues to the feature list.

v0.3.2

🐛 Bug Fixes

  • Version Number: 0.3.2
  • Release Date: 2026-08-04
  • General Overview: Bug-fix release addressing cache, JSON encoding, and documentation accuracy issues found via static analysis.

Changes

  • HasCache::remember() (sukarix): Cache::get() returns false both on a cache miss and when the stored value is legitimately false, so remember() could never recognise a cached falsy value as a hit and recomputed it on every call. Switched to Cache::exists() to distinguish a real hit from a miss. The accompanying ResponseTest was rewritten to exercise the trait directly (the previous test asserted hardcoded literals against themselves) and a regression test for the falsy-value case was added.
  • Model::__construct() PHPDoc (sukarix): Corrected the @param tags, which inaccurately claimed $db, $table and $fluid must always be null. They mirror Cortex’s constructor and accept object, string and bool respectively; the wrong annotations caused PHPStan to flag the subsequent null-check as dead code.
  • TestScenario::postJsonData() (statera): The method declared a string return type but json_encode() can return false on failure, which under strict_types would throw a TypeError instead of a clear JSON error. Now passes JSON_THROW_ON_ERROR, matching the convention already used elsewhere in the class.
  • TestScenario::run() cleanup (statera): Removed an orphaned @var CodeCoverage $coverage docblock and its accompanying use statement left over from a prior refactor; they no longer corresponded to any variable in the method.

v0.3.1

🚀 Features & Improvements

  • Version Number: 0.3.1
  • Release Date: 2026-07-18
  • General Overview: Statera migration, trait initialization refactor, cursor-based pagination, cache helpers, and open-source readiness.

Changes

  • PHPUnit Removal: Dropped phpunit/phpunit and phpunit/php-code-coverage from require-dev and removed phpunit.xml.dist. The framework’s InjectorTest was converted from a PHPUnit TestCase to a Statera TestScenario using expect() assertions. Code coverage is now provided transitively by Statera’s own phpunit/php-code-coverage dependency.
  • Statera Dependency: Added sukarix/statera to require-dev so the framework uses its own testing kit for its test suite. Statera remains an optional, standalone package for applications.
  • Test Runner: Added tools/statera.php and test infrastructure (tests/src/Test/, tests/src/Suite/) to run the framework’s tests via Statera.
  • Statera Package: Declared the previously-undeclared sukarix/sukarix runtime dependency in sukarix/statera’s composer.json (Statera uses Sukarix\Utils\CliUtils and Sukarix\Utils\Time).
  • Trait Initialization: Moved Processor::initialize() from Tailored::instance() to class constructors. Each Tailored subclass must now call Processor::instance()->initialize($this) in its constructor. The Helper base class does this automatically.
  • LogWriter: Added initLogger() backward-compatible alias for initLogWriter().
  • TestCase: Removed final keyword to allow subclassing in application test suites.
  • Action: Added Processor import. Made $view, $argv, $headerAuthorization, and $templatesDir nullable to prevent uninitialized typed property errors.
  • MailSender: smtpSend() and generateId() changed from private to protected for extensibility.
  • Assets: Constructor now calls parent::__construct() for proper trait initialization.
  • TestScenario: loadResult() handles missing template files gracefully.
  • Cursor Pagination: Added Response::cursor() for cursor-based API pagination — stable under concurrent inserts, efficient on large datasets. Returns { field, limit, has_more, next } structure.
  • Cache Remember: Added HasCache::remember() for get-or-set cache pattern and HasCache::forget() for invalidation.
  • Paginate Fix: Response::paginate() now casts pages to int (was float from ceil()).
  • Open Source: Added AGENTS.md with contribution guidelines and AI usage transparency across all repositories.

v0.2.0

🚀 Features

  • Version Number: 0.2.0
  • Release Date: 2025-01-20
  • General Overview: Added CSRF protection, enhanced session management, and improved validation.

v0.1.0

🚀 Introduction

  • Version Number: 0.1.0
  • Release Date: 2024-06-14
  • General Overview: First version of the Sukarix Framework.