3.4 Migration Guide
CakePHP 3.4 is an API compatible upgrade from 3.3. This page outlines the changes and improvements made in 3.4.
Minimum PHP 5.6 Required
CakePHP 3.4 requires at least PHP 5.6.0 as PHP 5.5 is no longer supported and won't receive any security fixes anymore.
Deprecations
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.
Request & Response Deprecations
The bulk of deprecations for 3.4 are in the Request and Response objects. The existing methods that modify objects in-place are now deprecated, and superseded by methods that follow the immutable object patterns described in the PSR-7 standard.
Several properties on Cake\Network\Request have been deprecated:
Request::$paramsis deprecated. UseRequest::getAttribute('params')instead.Request::$datais deprecated. UseRequest::getData()instead.Request::$queryis deprecated. UseRequest::getQueryParams()instead.Request::$cookiesis deprecated. UseRequest::getCookie()instead.Request::$baseis deprecated. UseRequest::getAttribute('base')instead.Request::$webrootis deprecated. UseRequest::getAttribute('webroot')instead.Request::$hereis deprecated. UseRequest::getAttribute('here')instead.Request::$_sessionwas renamed toRequest::$session.
A number of methods on Cake\Network\Request have been deprecated:
__get()&__isset()methods are deprecated. UsegetParam()instead.method()is deprecated. UsegetMethod()instead.setInput()is deprecated. UsewithBody()instead.- The
ArrayAccessmethods have all been deprecated. Request::param()is deprecated. UseRequest::getParam()instead.Request::data()is deprecated. UseRequest::getData()instead.Request::query()is deprecated. UseRequest::getQuery()instead.Request::cookie()is deprecated. UseRequest::getCookie()instead.
Several methods on Cake\Network\Response have been deprecated because they either overlap the PSR-7 methods, or are made obsolete by the PSR-7 stack:
Response::header()is deprecated. UsegetHeaderLine(),hasHeader()orResponse::getHeader()instead.Response::body()is deprecated. UseResponse::withStringBody()instead.Response::statusCode()is deprecated. UseResponse::getStatusCode()instead.Response::httpCodes()This method should no longer be used. CakePHP now supports all standards recommended status codes.Response::protocol()is deprecated. UseResponse::getProtocolVersion()instead.send(),sendHeaders(),_sendHeader(),_sendContent(),_setCookies(),_setContentType(), andstop()are deprecated and made obsolete by the PSR-7 HTTP stack.
With responses heading towards immutable object patterns as recommended by the PSR-7 standards, a number of 'helper' methods in Response have been deprecated and immutable variants are now recommended:
Response::location()would becomeResponse::withLocation()Response::disableCache()would becomeResponse::withDisabledCache()Response::type()would becomeResponse::withType()Response::charset()would becomeResponse::withCharset()Response::cache()would becomeResponse::withCache()Response::modified()would becomeResponse::withModified()Response::expires()would becomeResponse::withExpires()Response::sharable()would becomeResponse::withSharable()Response::maxAge()would becomeResponse::withMaxAge()Response::vary()would becomeResponse::withVary()Response::etag()would becomeResponse::withEtag()Response::compress()would becomeResponse::withCompression()Response::length()would becomeResponse::withLength()Response::mustRevalidate()would becomeResponse::withMustRevalidate()Response::notModified()would becomeResponse::withNotModified()Response::cookie()would becomeResponse::withCookie()Response::file()would becomeResponse::withFile()Response::download()would becomeResponse::withDownload()
Please see the Adopting Immutable Responses section for more information before updating your code as using responses through the immutable methods will require additional changes.
Other Deprecations
- The public properties on
Cake\Event\Eventare deprecated, new methods have been added to read/write the relevant properties. Event::name()is deprecated. UseEvent::getName()instead.Event::subject()is deprecated. UseEvent::getSubject()instead.Event::result()is deprecated. UseEvent::getResult()instead.Event::data()is deprecated. UseEvent::getData()instead.- The
Auth.redirectsession variable is no longer used. Instead a query string parameter is used to store the redirect URL. This has the additional effect of removing the ability to store a redirect URL in the session outside of login scenarios. AuthComponentno longer stores redirect URLs when the unauthorized URL is not aGETaction.- The
ajaxLoginoption forAuthComponentis deprecated. You should use the403status code to trigger the correct behavior in clientside code now. - The
beforeRedirectmethod ofRequestHandlerComponentis now deprecated. - The
306status code inCake\Network\Responseis now deprecated and has its status phrase changed to 'Unused' as this status code is non-standard. Cake\Database\Schema\Tablehas been renamed toCake\Database\Schema\TableSchema. The previous name was confusing to a number of users.- The
fieldListoption forCake\ORM\Table::newEntity()andpatchEntity()has been renamed tofieldsto be more consistent with other parts of the ORM. Router::parse()is deprecated.Router::parseRequest()should be used instead as it accepts a request and gives more control/flexibility in handling incoming requests.Route::parse()is deprecated.Route::parseRequest()should be used instead as it accepts a request and gives more control/flexibility in handling incoming requests.FormHelper::input()is deprecated. UseFormHelper::control()instead.FormHelper::inputs()is deprecated. UseFormHelper::controls()instead.FormHelper::allInputs()is deprecated. UseFormHelper::allControls()instead.Mailer::layout()is deprecated. UseMailer::setLayout()provided byMailer::__call()instead.
Deprecated Combined Get/Set Methods
In the past CakePHP has leveraged 'modal' methods that provide both a get/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:
Cake\Core\InstanceConfigTrait
config()
Cake\Core\StaticConfigTrait
config()dsnClassMap()
Cake\Console\ConsoleOptionParser
command()description()epilog()
Cake\Database\Connection
driver()schemaCollection()useSavePoints()(nowenableSavePoints()/isSavePointsEnabled())
Cake\Database\Driver
autoQuoting(nowenableAutoQuoting()/isAutoQuotingEnabled())
Cake\Database\Expression\FunctionExpression
name()
Cake\Database\Expression\QueryExpression
tieWith()(nowsetConjunction()/getConjunction())
Cake\Database\Expression\ValuesExpression
columns()values()query()
Cake\Database\Query
connection()selectTypeMap()bufferResults()(nowenableBufferedResults()/isBufferedResultsEnabled())
Cake\Database\Schema\CachedCollection
cacheMetadata()
Cake\Database\Schema\TableSchema
options()temporary()(nowsetTemporary()/isTemporary())
Cake\Database\TypeMap
defaults()types()
Cake\Database\TypeMapTrait
typeMap()defaultTypes()
Cake\ORM\Association
name()cascadeCallbacks()source()target()conditions()bindingKey()foreignKey()dependent()joinType()property()strategy()finder()
Cake\ORM\Association\BelongsToMany
targetForeignKey()saveStrategy()conditions()
Cake\ORM\Association\HasMany
saveStrategy()foreignKey()sort()
Cake\ORM\Association\HasOne
foreignKey()
Cake\ORM\EagerLoadable
config()- setter part of
canBeJoined()(nowsetCanBeJoined())
Cake\ORM\EagerLoader
matching()(getMatching()will have to be called aftersetMatching()to keep the old behavior)autoFields()(nowenableAutoFields()/isAutoFieldsEnabled())
Cake\ORM\Locator\TableLocator
config()
Cake\ORM\Query
eagerLoader()hydrate()(nowenableHydration()/isHydrationEnabled())autoFields()(nowenableAutoFields()/isAutoFieldsEnabled())
Cake\ORM\Table
table()alias()registryAlias()connection()schema()primaryKey()displayField()entityClass()
Cake\Mailer\Email
from()sender()replyTo()readReceipt()returnPath()to()cc()bcc()charset()headerCharset()emailPattern()subject()template()(nowsetTemplate()/getTemplate()andsetLayout()/getLayout())viewRender()(nowsetViewRenderer()/getViewRenderer())viewVars()theme()helpers()emailFormat()transport()messageId()domain()attachments()configTransport()profile()
Cake\Validation\Validator
provider()
Cake\View\StringTemplateTrait
templates()
Cake\View\ViewBuilder
templatePath()layoutPath()plugin()helpers()theme()template()layout()options()name()className()autoLayout()(nowenableAutoLayout()/isAutoLayoutEnabled())
Adopting Immutable Responses
Before you migrate your code to use the new response methods you should be aware of the conceptual differences the new methods have. The immutable methods are generally indicated using a with prefix. For example, withLocation(). Because these methods operate in an immutable context, they return new instances which you need to assign to variables or properties. If you had controller code that looked like:
$response = $this->response;
$response->location('/login')
$response->header('X-something', 'a value');If you were to simply find & replace method names your code would break. Instead you must now use code that looks like:
$this->response = $this->response
->withLocation('/login')
->withHeader('X-something', 'a value');There are a few key differences:
- The result of your changes is re-assigned to
$this->response. This is critical to preserving the intent of the above code. - The setter methods can all be chained together. This allows you to skip storing all the intermediate objects.
Component Migration Tips
In previous versions of CakePHP, Components often held onto references to both the request and response, in order to make changes later. Before you adopt the immutable methods you should use the response attached to the Controller:
// In a component method (not a callback)
$this->response->header('X-Rate-Limit', $this->remaining);
// Should become
$controller = $this->getController();
$controller->response = $controller->response->withHeader('X-Rate-Limit', $this->remaining);In component callbacks you can use the event object to access the response/controller:
public function beforeRender($event)
{
$controller = $event->getSubject();
$controller->response = $controller->response->withHeader('X-Teapot', 1);
}TIP
Instead of holding onto references of Responses, always get the current response from the controller, and re-assign the response property when you are done.
Behavior Changes
While these changes are API compatible, they represent minor variances in behavior that may affect your application:
ORM\Queryresults will not typecast aliased columns based on the original column's type. For example if you aliascreatedtocreated_timeyou will now get aTimeobject back instead of a string.- Internal ORM traits used to build Association classes have been removed and replaced with new internal APIs. This shouldn't impact your applications, but may if you have created custom association types.
AuthComponentnow uses a query string to store the redirect URL when an unauthenticated user is redirected to the login page. Previously, this redirect was stored in the session. Using the query string allows for better multi-browser experience.- Database Schema reflection now treats unknown column types as
stringand nottext. A visible impact of this is thatFormHelperwill generate text inputs instead of textarea elements for unknown column types. AuthComponentno longer stores the flash messages it creates under the 'auth' key. They are now rendered with the 'error' template under the 'default' flash message key. This simplifies usingAuthComponent.Mailer\Emailwill now autodetect attachment content types usingmime_content_typeif a content-type is not provided. Previously attachments would have defaulted to 'application/octet-stream'.- CakePHP now uses the
...operator in place ofcall_user_func_array(). If you are passing associative arrays, you should update your code to pass a numerically indexed array usingarray_values()for the following methods:Cake\Mailer\Mailer::send()Cake\Controller\Controller::setAction()Cake\Http\ServerRequest::is()
Visibility Changes
MailerAwareTrait::getMailer()will now become protected.CellTrait::cell()will now become protected.
If the above traits are used in controllers, their public methods could be accessed by default routing as actions. These changes help protect your controllers. If you need the methods to remain public you will need to update your use statement to look like:
use CellTrait {
cell as public;
}
use MailerAwareTrait {
getMailer as public;
}Collection
CollectionInterface::chunkWithKeys()was added. User land implementations of theCollectionInterfacewill need to implement this method now.Collection::chunkWithKeys()was added.
Error
Debugger::setOutputMask()andDebugger::outputMask()were added. These methods allow you to configure properties/array keys that should be masked from output generated by Debugger (for instance, when callingdebug()).
Event
Event::getName()was added.Event::getSubject()was added.Event::getData()was added.Event::setData()was added.Event::getResult()was added.Event::setResult()was added.
I18n
- You can now customize the behavior of the fallback message loader. See Creating Generic Translators for more information.
Routing
RouteBuilder::prefix()now accepts an array of defaults to add to each connected route.- Routes can now match only specific hosts through the
_hostoption.
Email
Email::setPriority()/Email::getPriority()have been added.
HtmlHelper
HtmlHelper::scriptBlock()no longer wraps the JavaScript code in<![CDATA[ ]]tag by default. Thesafeoption which controls this behavior now defaults tofalse. Using<![CDATA[ ]]tag was only required for XHTML which is no longer the dominant doctype used for HTML pages.
BreadcrumbsHelper
BreadcrumbsHelper::reset()was added. This method lets you clear out existing crumbs.
PaginatorHelper
PaginatorHelper::numbers()now uses an HTML elipsis instead of '...' in the default templates.PaginatorHelper::total()was added to enable reading the total number of pages for the currently paginated results.PaginatorHelper::generateUrlParams()was added as a lower level URL building method.PaginatorHelper::meta()can now create links for 'first', 'last'.
FormHelper
- You can now configure the sources which FormHelper reads from. This makes creating GET forms simpler. See Form Values From Query String for more information.
FormHelper::control()was added.FormHelper::controls()was added.FormHelper::allControls()was added.
Validation
Validation::falsey()andValidation::truthy()were added.
TranslateBehavior
TranslateBehavior::translationField()was added.
PluginShell
cake plugin loadandcake plugin unloadnow support a--clioption, which updates thebootstrap_cli.phpinstead.
TestSuite
- Support to
PHPUnit 6was added. With this framework version requiring PHP 5.6.0 as a minimum version, the supported version of PHPUnit are now^5.7|^6.0