5.3 Migration Guide
The 5.3.0 release is a backwards compatible with 5.0. It adds new functionality and introduces new deprecations. Any functionality deprecated in 5.x will be removed in 6.0.0.
Upgrade Tool
The upgrade tool provides rector rules for automating some of the migration work. Run rector before updating your composer.json dependencies:
bin/cake upgrade rector --rules cakephp53 <path/to/app/src>Upgrade to PHP 8.2
If you are not running on PHP 8.2 or higher, you will need to upgrade PHP before updating CakePHP.
NOTE
CakePHP 5.3 requires a minimum of PHP 8.2.
Behavior Changes
Core
InstanceConfigTrait::deleteConfig()was added. For classes using this trait, you can now use$this->deleteConfig('key')instead of$this->setConfig('key', null)
Database
Query::with()now accepts an array of expressions to align with other query clauses. This also allows clearing the expressions with an empty array.
ORM
joinWith()now asserts when the association conflicts with an existing join and will overwrite it. Because existing code might harmlessly ignore the join or accidentally rely on that behavior, this change is not breaking in production for CakePHP 5.
Validation
- The signature of
Validator::validate(array $data, bool $newRecord = true, array $context = [])has now a additional third parameter$context. It can be used to pass necessary context into the validation when marshalling.
View
- The
format()andcurrency()methods ofNumberHelpernow accept also null as input and can return any default string here. This allows for easier templates, in particular baked ones. Make sure to adjust any extending helper (plugin or app level) by adding that type.
Deprecations
Database
Query::newExpr()is deprecated. UseQuery::expr()instead.
Form
Form::_execute()is deprecated. You should rename your_executemethods toprocess()which accepts the same parameters and has the same return type.
Http
- Using
$request->getParam('?')to get the query params is deprecated. Use$request->getQueryParams()instead.
ORM
- Calling behavior methods on table instances is now deprecated. To call a method of an attached behavior you need to use
$table->getBehavior('Sluggable')->slugify()instead of$table->slugify(). EntityTrait::isEmpty()is deprecated. UsehasValue()instead.
Plugin
- Loading of plugins without a plugin class is deprecated. For your existing plugins which don't have one, you can use the
bin/cake bake plugin MyPlugin --class-onlycommand, which will create the fileplugins/MyPlugin/src/MyPlugin.php.
View
- Passing an array as the first argument to
BreadcrumbsHelper::add()andBreadcrumbsHelper::prepend()is deprecated. UseaddMany()andprependMany()instead.
New Features
Cache
- Added Redis Cluster support to
RedisEngine. Configure theclusteroption with an array of server addresses to enable cluster mode. - Several Cache Events were added to allow monitoring the caching behavior.
Collection
Collection::any()was added to replaceCollection::some()with a more familiar name.
Command
cake plugin assets symlinkcommand now supports a--relativeoption to create relative path symlinks. This is useful when creating symlinks within containers that use volume mounts.cake servernow supports a--frankenphpoption that will start the development server with FrankenPHP.
Console
- Added
TreeHelperwhich outputs an array as a tree such as an array of filesystem directories as array keys and files as lists under each directory. - Commands can now implement
getGroup()to customize how commands are grouped inbin/cake -houtput. CommandCollection::replace()was added. This method allows you to replace an existing command in the collection without needing to remove and re-add it. This is particularly useful when usingautoDiscoverand you want to replace a command with a customized version.
Core
- Added
Configureattribute to support injectingConfigurevalues into constructor arguments. See ref:`configure-dependency-injection`.
Database
- Added support for Entra authentication to SqlServer driver.
- Added
Query::optimizerHint()which accepts engine-specific optimizer hints. - Added
Query::getDriver()helper which returns theDriverfor the current connection role by default. - Added support for
yearcolumn types in MySQL. - Added support for
inet,cidrandmacaddrnetwork column types to postgres driver. - Added
TypeFactory::getMapped()to retrieve the mapped class name for a specific type. This provides a cleaner API compared to usingTypeFactory::getMap()with a type argument.
Error
Debuggernow replacesROOTwith theDebugger.editorBasePathConfigure value if defined. This improves debugging workflows within containerized environments.
Http
- The new
RateLimitMiddlewareprovides configurable rate limiting for your application to protect against abuse and ensure fair usage of resources. It supports multiple identification strategies (IP, user, route, API key), different rate limiting algorithms (sliding window, fixed window, token bucket), and advanced features like custom identifiers, request costs, and dynamic limits. UnprocessableContentExceptionwas added.
I18n
- Added
DateTimePeriodwhich wraps a phpDatePeriodand returnsDateTimeinstances when iterating. - Added
DatePeriodwhich wraps a phpDatePeriodand returnsDateinstances when iterating. - Added
toQuarterRange()method toDateTimeandFrozenTimeclasses which returns an array containing the start and end dates of the quarter for the given date. - Added
Date::getTimestamp(). This method returns an int of the date's timestamp.
Mailer
- Added
Message::addAttachment()for adding attachments to a message. Like other message methods, it can be accessed via theMailerinstance as$mailer->addAttachment().
ORM
Table::patchEntity(),Table::newEntity(),Marshaller::one()andMarshaller::many()now accept astrictFieldsoption that only applies validation to the fields listed in thefieldsoption.- Added
TableContainerthat you can register in yourApplication::services()to add dependency injection for your Tables. - Added
SelectQuery::projectAs()for projecting query results into Data Transfer Objects (DTOs) instead of Entity objects. DTOs provide a memory-efficient alternative (approximately 3x less memory than entities) for read-only data access. See Dto Projection. - Added the
#[CollectionOf]attribute for declaring the element type of array properties in DTOs. This enables proper hydration of nested associations into DTOs.
Pagination
- Added
SortableFieldsBuilderclass enabling fluent configuration of sortable fields with advanced features. ThesortableFieldsoption now accepts a callable that receives aSortableFieldsBuilderinstance, allowing you to map friendly sort keys to database fields with multi-column sorting and direction control. - Added
SortFieldclass for defining sort field configurations with customizable default directions and locked directions (e.g.,SortField::asc('price')orSortField::desc('created', locked: true)). - Added support for combined sorting keys in URLs (e.g.,
?sort=title-ascor?sort=price-desc) in addition to the traditional?sort=field&direction=ascformat.
Routing
- Added
RouteBuilder::setOptions()method to set default route options at the scope level. This allows you to apply options like_host,_https, and_portto all routes within a scope without repeating them on each route. Options set at the scope level are inherited by nested scopes and can be overridden on individual routes. EntityRoutenow handles enum value conversions. This enables you to use enum backed properties as route parameters. When an enum backed property is used in routing, the enum'svalueornamewill be used.- Added
RedirectTrait. This trait can be used to create custom redirect route classes.
TestSuite
assertRedirectBack()added to assert a successful redirect has been made to the same previous URL.assertRedirectBackToReferer()added to assert a successful redirect has been made to the referer URL.assertFlashMessageContains()andassertFlashMessageContainsAt()were added. These methods enable substring matching of flash message content.TestFixture::$tableAliaswas added. This property lets you define the table alias that will be used to load anORM\Tableinstance for a fixture. This improves compatibility for schemas that do not closely follow naming conventions.
Utility
Text::uuid()now supports configurable UUID generation. You can set a custom UUID generator usingConfigure::write('Text.uuidGenerator', $closure)to integrate your own UUID generation strategy or third-party libraries.
Validation
ipOrRange()validation has has been added to check for an IP or a range (subnet).- When validating within CakePHP marshalling context, the entity will be passed into the
contextargument for use inside custom validation rules. This can be useful when patching partially and then needing to get that data from the entity instead of the passed data. existsInNullable()rule has been added. This rule allowsnullvalues in nullable composite foreign keys, which is semantically correct for optional relationships. Use$rules->existsInNullable(['author_id', 'site_id'], 'SiteAuthors')instead ofexistsIn()when you want to permit null values in foreign keys.
View
HtmlHelper::scriptStart()andscriptEnd()now allow simple wrapping script tags (<script>...</script>) around inline JavaScript. This enables syntax highlighting in many editors to work. The wrapping script tag will be removed and replaced with a script tag generated by the helper.FormHelpernow supports a new optionnestedCheckboxAndRadio. By default, the helper generates inputs of type checkbox and radio nested inside their label. Setting thenestedCheckboxAndRadiooption tofalsewill turn off the nesting.ViewBuilder::setConfigMergeStrategy()was added to control how view options are merged with the View class's default configuration. Available strategies areViewBuilder::MERGE_DEEP(recursive merge, default) andViewBuilder::MERGE_SHALLOW(simple array merge). This is useful when you want to replace array values in view options rather than deep merging them.ViewBuilder::getConfigMergeStrategy()was added to retrieve the current merge strategy setting.PaginatorHelper::limitControl()now automatically respects themaxLimitconfiguration from the paginator, filtering out any limit options that exceed it. A newstepsoption was added to automatically generate limit options in multiples of a specific value (e.g.,['steps' => 10]generates 10, 20, 30... up to maxLimit).BreadcrumbsHelper::addMany()andBreadcrumbsHelper::prependMany()were added. These methods allow adding multiple breadcrumbs at once with support for shared options that apply to all crumbs.