3.5 Migration Guide

CakePHP 3.5 is an API compatible upgrade from 3.4. This page outlines the changes and improvements made in 3.5.

To upgrade to 3.5.x run the following composer command:

php composer.phar require --update-with-dependencies "cakephp/cakephp:3.5.*"


The following is a list of deprecated methods, properties and behaviors. These features will continue to function until 4.0.0 after which they will be removed.

  • Cake\Http\Client\CookieCollection is deprecated. Use Cake\Http\Cookie\CookieCollection instead.
  • Cake\View\Helper\RssHelper is deprecated. Due to infrequent use the RssHelper is deprecated.
  • Cake\Controller\Component\CsrfComponent is deprecated. Use Cross Site Request Forgery (CSRF) Middleware instead.
  • Cake\Datasource\TableSchemaInterface is deprecated. Use Cake\Database\TableSchemaAwareInterface instead.
  • Cake\Console\ShellDispatcher is deprecated. Applications should update to use Cake\Console\CommandRunner instead.
  • Cake\Database\Schema\TableSchema::column() is deprecated. Use Cake\Database\Schema\TableSchema::getColumn() instead.
  • Cake\Database\Schema\TableSchema::constraint() is deprecated. Use Cake\Database\Schema\TableSchema::getConstraint() instead.
  • Cake\Database\Schema\TableSchema::index() is deprecated. Use Cake\Database\Schema\TableSchema::getIndex() instead.

Deprecated Combined Get/Set Methods

In the past CakePHP has leveraged ‘modal’ methods that provide both a get and set mode. These methods complicate IDE autocompletion and our ability to add stricter return types in the future. For these reasons, combined get/set methods are being split into separate get and set methods.

The following is a list of methods that are deprecated and replaced with getX() and setX() methods:

  • config()
  • registry()
  • io()
  • outputAs()
  • outputAs()
  • logger()
  • returnType()
  • returnType()
  • logger()
  • modelType()
  • getter part of valueBinder() (now getValueBinder())
  • columnType()
  • getter part of eagerLoaded() (now isEagerLoaded())
  • eventManager()
  • eventManager()
  • outputAs() (now getOutputFormat() / setOutputFormat())
  • env() (now getEnv() / withEnv())
  • charset() (now getCharset() / withCharset())
  • locale()
  • translator()
  • defaultLocale()
  • defaultFormatter()
  • sort()
  • tableLocator()
  • invalid() (now getInvalid(), setInvalid(), setInvalidField(), and getInvalidField())
  • validator()
  • extensions()
  • routeClass()
  • extensions()
  • schema()
  • salt()
  • template()
  • layout()
  • theme()
  • templatePath()
  • layoutPath()
  • autoLayout() (now isAutoLayoutEnabled() / enableAutoLayout())

Behavior Changes

While these changes are API compatible, they represent minor variances in behavior that may affect your application:

  • BehaviorRegistry, HelperRegistry and ComponentRegistry will now raise exceptions when unload() is called with an unknown object name. This change should help find errors easier by making possible typos more visible.
  • HasMany associations now gracefully handle empty values set for the association property, similar to BelongsToMany associations - that is they treat false, null, and empty strings the same way as empty arrays. For HasMany associations this now results in all associated records to be deleted/unlinked when the replace save strategy is being used. As a result this allows you to use forms to delete/unlink all associated records by passing an empty string. Previously this would have required custom marshalling logic.
  • ORM\Table::newEntity() now only marks association properties dirty if the marshalled association record is dirty. In scenarios where an association entity is created that contains no properties the empty record will not be flagged for persistence.
  • Http\Client no longer uses the cookie() method results when building requests. Instead the Cookie header and internal CookieCollection are used. This should only effect applications that have a custom HTTP adapter in their clients.
  • Multi-word subcommand names previouly required camelBacked names to be used when invoking shells. Now subcommands can be invoked with underscored_names. For example: cake tool initMyDb can now be called with cake tool init_my_db. If your shells previously bound two subcommands with different inflections, only the last bound command will function.
  • SecurityComponent will blackhole post requests that have no request data now. This change helps protect actions that create records using database defaults alone.
  • Cake\ORM\Table::addBehavior() and removeBehavior() now return $this to assist in defining table objects in a fluent fashion.
  • Cache engines no longer throw an exception when they fail or are misconfigured, but instead fall back to the noop NullEngine. Fallbacks can also be configured on a per-engine basis.
  • Cake\Database\Type\DateTimeType will now marshal ISO-8859-1 formatted datetime strings (e.g. 2017-07-09T12:33:00+00:02) in addition to the previously accepted format. If you have a subclass of DateTimeType you may need to update your code.

New Features

Scoped Middleware

Middleware can now be conditionally applied to routes in specific URL scopes. This allows you to build specific stacks of middleware for different parts of your application without having to write URL checking code in your middleware. See the Connecting Scoped Middleware section for more information.

New Console Runner

3.5.0 adds Cake\Console\CommandRunner. This class alongside Cake\Console\CommandCollection integrate the CLI environment with the new Application class. Application classes can now implement a console() hook that allows them to have full control over which CLI commands are exposed, how they are named and how the shells get their dependencies. Adopting this new class requires replacing the contents of your bin/cake.php file with the following file.

Cache Engine Fallbacks

Cache engines can now be configured with a fallback key that defines a cache configuration to fall back to if the engine is misconfigured (or unavailable). See Configuring Cache Fallbacks for more information on configuring fallbacks.

dotenv Support added to Application Skeleton

The application skeleton now features a ‘dotenv’ integration making it easier to use environment variables to configure your application. See the Environment Variables section for more information.

Console Integration Testing

The Cake\TestSuite\ConsoleIntegrationTestCase class was added to make integration testing console applications easier. For more information, visit the Testing Commands section. This test class is fully compatible with the current Cake\Console\ShellDispatcher as well as the new Cake\Console\CommandRunner.


  • Cake\Collection\Collection::avg() was added.
  • Cake\Collection\Collection::median() was added.


  • Cake\Core\Configure::read() now supports default values if the desired key does not exist.
  • Cake\Core\ObjectRegistry now implements the Countable and IteratorAggregate interfaces.


  • Cake\Console\ConsoleOptionParser::setHelpAlias() was added. This method allows you to set the command name used when generating help output. Defaults to cake.
  • Cake\Console\CommandRunnner was added replacing Cake\Console\ShellDispatcher.
  • Cake\Console\CommandCollection was added to provide an interface for applications to define the command line tools they offer.


  • SQLite driver had the mask option added. This option lets you set the file permissions on the SQLite database file when it is created.


  • Cake\Datasource\SchemaInterface was added.
  • New abstract types were added for smallinteger and tinyinteger. Existing SMALLINT and TINYINT columns will now be reflected as these new abstract types. TINYINT(1) columns will continue to be treated as boolean columns in MySQL.
  • Cake\Datasource\PaginatorInterface was added. The PaginatorComponent now uses this interface to interact with paginators. This allows other ORM-like implementations to be paginated by the component.
  • Cake\Datasource\Paginator was added to paginate ORM/Database Query instances.


  • Cake\Event\EventManager::on() and off() methods are now chainable making it simpler to set multiple events at once.


  • New Cookie & CookieCollection classes have been added. These classes allow you to work with cookies in an object-orientated way, and are available on Cake\Http\ServerRequest, Cake\Http\Response, and Cake\Http\Client\Response. See the Cookies and Setting Cookies for more information.
  • New middleware has been added to make applying security headers easier. See Security Header Middleware for more information.
  • New middleware has been added to transparently encrypt cookie data. See Encrypted Cookie Middleware for more information.
  • New middleware has been added to make protecting against CSRF easier. See Cross Site Request Forgery (CSRF) Middleware for more information.
  • Cake\Http\Client::addCookie() was added to make it easy to add cookies to a client instance.


  • InstanceConfigTrait::getConfig() now takes a 2nd parameter $default. If no value is available for the specified $key, the $default value will be returned.


  • Cake\ORM\Query::contain() now allows you to call it without the wrapping array when containing a single association. contain('Comments', function () { ... }); will now work. This makes contain() consistent with other eagerloading related methods like leftJoinWith() and matching().


  • Cake\Routing\Router::reverseToArray() was added. This method allow you to convert a request object into an array that can be used to generate URL strings.
  • Cake\Routing\RouteBuilder::resources() had the path option added. This option lets you make the resource path and controller name not match.
  • Cake\Routing\RouteBuilder now has methods to create routes for specific HTTP methods. e.g get() and post().
  • Cake\Routing\RouteBuilder::loadPlugin() was added.
  • Cake\Routing\Route now has fluent methods for defining options.


  • TestCase::loadFixtures() will now load all fixtures when no arguments are provided.
  • IntegrationTestCase::head() was added.
  • IntegrationTestCase::options() was added.
  • IntegrationTestCase::disableErrorHandlerMiddleware() was added to make debugging errors easier in integration tests.


  • Cake\Validation\Validator::scalar() was added to ensure that fields do not get non-scalar data.
  • Cake\Validation\Validator::regex() was added for a more convenient way to validate data against a regex pattern.
  • Cake\Validation\Validator::addDefaultProvider() was added. This method lets you inject validation providers into all the validators created in your application.
  • Cake\Validation\ValidatorAwareInterface was added to define the methods implemented by Cake\Validation\ValidatorAwareTrait.


  • Cake\View\Helper\PaginatorHelper::limitControl() was added. This method lets you create a form with a select box for updating the limit value on a paginated result set.