5.18.0 (2026-07-31)
Tools
- Zephir 1.2.0 (83d8f68)
Changed
- Changed
Phalcon\ADR\Applicationinto a self-contained composition root: it owns (or accepts) aPhalcon\Container\Containerand exposes a small registration surface -bind(),define(),factory(),set(),extend()andgetContainer()- plussetBaseNamespace()andsecureWith()for convention-router and namespace-prefix guard configuration.Phalcon\ADR\Front\AbstractHttpFrontgained a protectedgetApplication()hook returningPhalcon\Contracts\ADR\Application, so a front controller can configure the application or wire a different implementation. #17389 [doc] - Replaced fully-qualified class-name strings with
::classreferences (anduseimports) across factories, service providers and DI containers #17380 - Changed
Phalcon\Mvc\Model::getRelated()andPhalcon\Mvc\Model::isRelationshipLoaded()to test the relation cache witharray_key_exists()instead ofisset(), so a to-one relation that resolves to no record is no longer re-queried on every access #17331 [doc] - Changed
Phalcon\Mvc\Model\Manager::mergeFindParameters()fromfinal protectedtofinal public static#17331 - Changed
Phalcon\ADR\Router\Routerfrom a candidate chain to a namespace descent: a path segment becomes a namespace segment only if the matching directory exists, after which at most two Action classes are probed instead of five. An Action can no longer be silently shadowed by an earlier candidate. RequiressetActionDirectory(). #17405 [doc] - Changed
Phalcon\ADR\Router\Routerto derive exactly one Action class per path: the class name is the verb followed by every static segment concatenated. #17410 [doc] - Changed
Phalcon\Mvc\Model\Resultset::refresh()to reset the cursor - position, current row, buffered rows and active row - after replaying the statement. #17399 [doc] - Changed
Phalcon\Events\Manager::getEventTypes()togetListenerMap(), which now returns each event type mapped to its listeners. #17416 [doc] - Changed the distribution tarball that Composer and PIE download to ship only the files needed to build the extension; tests, Zephir sources, tooling and the Docker development setup are now excluded through
.gitattributes. #17419
Added
- Added the Action-Domain-Responder (ADR) HTTP stack under
Phalcon\ADR, an alternative to MVC that splits request handling into three focused roles: an Action (one invokable class per route) drives a Domain (your business logic, which returns aPhalcon\ADR\Payload\Payloadand never touches HTTP) and hands the result to a Responder that turns it into a response.Phalcon\ADR\Container: registrations for thePhalcon\Container\ContainerPhalcon\ADR\Emitter:SapiEmitterto emit response dataPhalcon\ADR\Events: events wired to the Events ManagerPhalcon\ADR\Exceptions: granular exceptions the namespace throwsPhalcon\ADR\Front: One-command class wiring the application and executing itPhalcon\ADR\Input: Bag of request data to be passed to the domainPhalcon\ADR\Middleware: Onion based middleware stackPhalcon\ADR\Payload: VO for transferring data from the domain and the responderPhalcon\ADR\Responder: Chainable responders, handling redirect, json, text, error etc.Phalcon\ADR\Router: Router for the application. #17341 [doc]
- Added
Phalcon\ADR\Responder\ViewResponder, which renders a.phtmltemplate and returns it as an HTML response. The action picks the template withwithTemplate(), and the view receivesresult,messagesandstatus. Any renderer implementing the newPhalcon\Contracts\View\Renderercan be used -Phalcon\Mvc\View\Simplenow does. #17379 [doc] - Added request attributes support to
Phalcon\Http\Request.Phalcon\Http\Request::getAttributes()returns aPhalcon\Http\Request\Bag\AttributeBag, a mutable, string-keyed bag of arbitrary application-defined values attached to the request during its lifecycle (router, dispatcher, security components etc.). Writing with anullkey (the$bag[] = ...append form) throws the newPhalcon\Http\Request\Exceptions\NullKeyException, since bag elements are always string-keyed. #17367 [doc] - Added opt-in route-parameter pre-filtering to the ADR convention router via the new
Phalcon\ADR\Router\AttributeFilter. An Action that declares a staticparams()method has its positional route segments validated against a regex, cast to a scalar type (int,float,string) and optionally passed through a converter closure, then written to the request as named attributes - all before the Action runs. A regex miss is treated as a route miss (404). #17393 [doc] - Added eager loading of model relations:
Phalcon\Mvc\Model::find()accepts aneagerparameter - an array of dot-delimited relation paths, optionallypath => options- which pre-loads the named relations with one query per relation instead of one per record.Phalcon\Mvc\Model\Criteria::eager()exposes the same on the criteria surface. #17331 [doc] - Added
candidatesFor()to thePhalcon\Contracts\ADR\Router\Routercontract and toPhalcon\ADR\Router\Router. It returns every Action class the convention router would try for a given HTTP method and path, in the order it tries them. #17403 [doc] - Added
pathFor(),setActionDirectory()andsetWordSeparator()to thePhalcon\Contracts\ADR\Router\Routercontract and toPhalcon\ADR\Router\Router; the two setters are also onPhalcon\ADR\Application.pathFor()is the inverse of the routing convention, returning the canonical path an Action answers ornull. AddedPhalcon\ADR\Exceptions\ActionDirectoryNotSet. #17405 [doc] - Added
Phalcon\Container\Container::getServiceNames(), returning the names of every registered service definition. #17406 [doc] AddedPhalcon\Events\Manager::getEventTypes(), returning the event types that currently have at least one listener attached, including those contributed by subscribers. #17406 [doc]- Added
classFor()to thePhalcon\Contracts\ADR\Router\Routercontract and toPhalcon\ADR\Router\Router. It names the Action class the convention would use for a static path. #17410 [doc] - Added
Phalcon\ADR\Front\AbstractHttpFront::boot(), which builds the container, loads the environment and registers the providers, then returns the container - for consumers that need it before, or instead of,run(). The container is built once and cached, soboot()andrun()share the same instance. A bootstrap file can now bereturn (new AppFront(dirname(__DIR__)))->boot();. #17413 [doc] - Added
Phalcon\Contracts\Container\Service\Enumerableimplemented inPhalcon\Container\Container. #17416 [doc] - Added
Phalcon\Contracts\Events\Enumerable, implemented inPhalcon\Events\Manager. #17416 [doc] - Added
methodFor()to thePhalcon\Contracts\ADR\Router\Routercontract and toPhalcon\ADR\Router\Router. It names the HTTP method an Action class answers, the counterpart topathFor(). #17416 [doc]
Fixed
- Fixed
Phalcon\Container\Definition\ServiceDefinition::resolveArgs()treating any constructor-argument object that merely exposes aresolve()method as a lazy value, usingmethod_exists(). BecausePhalcon\Container\Containerdefines a privateresolve(), autowiring a service whose constructor receives the container - i.e.__construct(?Container $container)- mistook the injected container for a lazy resolvable. The lazy check is now guarded for non-object arguments. #17391 - Fixed
Phalcon\Http\Response\Cookies::delete()not deleting a cookie that was not set in the same request; it now falls back to the$_COOKIEsuperglobal.Phalcon\Http\Cookie::delete()expires the cookie with its storedpathanddomaininstead of the defaults. #17395 [doc] - Fixed
Phalcon\Mvc\Modelignoring attributes registered withskipAttributes(),skipAttributesOnCreate()andskipAttributesOnUpdate(), so a skipped column was emitted in the generatedINSERT/UPDATE(breaking, for instance, inserts into a table with a MySQL generated column). The skip list is keyed withnullvalues, andisset()on an array offset now follows PHP semantics (key present and value notnull), which made every skipped attribute read as not registered; the checks indoLowInsert(),doLowUpdate()and the not-null validation now usearray_key_exists(). #17382 [doc] - Fixed
Phalcon\Mvc\Modelinserting a literalnullfor a column the database can supply a value for, instead of theDEFAULTkeyword (or omitting the column on an adapter withoutDEFAULTsupport, such as SQLite). This restores inserts against a MySQLGENERATED ALWAYS AS (...) STOREDcolumn, which rejects an explicitnullwithSQLSTATE[HY000]: General error: 3105but acceptsDEFAULT. #17382 [doc] - Fixed
Phalcon\ADR\Router\Routertreating-and_as the same delimiter, so/forgot-passwordand/forgot_passwordresolved to the same Action and the path-to-class map had no inverse. A single separator now applies in both directions, default-and settable withsetWordSeparator();_is literal. #17405 [doc] - Fixed
Phalcon\Mvc\Model::find()andPhalcon\Mvc\Model::findFirst()raising an errorCall to undefined method static::getpreparedquery(). Usingselfvs. 'static` for the internal calls. #17409 [doc] - Fixed
Phalcon\Mvc\Model\Resultsetcosting two statements for every resultset on SQLite. #17399 [doc] - Fixed
Phalcon\Db\Result\PdoResult::numRows()failing on multi-line statements. #17399 - Fixed
Phalcon\Mvc\Model\Resultset::seek()leaving the previous row in place as the current one when seeking past the end of a resultset held in memory. #17399 [doc] - Fixed
Phalcon\Db\Adapter\Pdo\Mysql::describeColumns()returning string, date and time defaults still wrapped in quotes on MariaDB, e.g.'fi'instead offi. MariaDB reportsCOLUMN_DEFAULTas the DDL source rather than the resolved literal. Expression defaults are unaffected. Note that on MariaDB this changes whatPhalcon\Db\Column::getDefault()returns and what the model layer writes into an unsetNOT NULLcolumn on save; if you were stripping the quotes yourself, remove that workaround. MySQL is unaffected. #17417 [doc]
Removed
- Removed
.php_cs.dist, superseded byresources/php-cs-fixer.php. #17419