This page summarizes the changes from CakePHP 1.3 that will assist in a project
migration to 2.0, as well as for a developer reference to get up to date with
the changes made to the core since the CakePHP 1.3 branch. Be sure to read the
other pages in this guide for all the new features and API changes.

Tip

Be sure to checkout the Upgrade shell included in the 2.0 core to help you
migrate your 1.3 code to 2.0.

CakePHP 2.x supports PHP Version 5.2.8 and above. PHP4 support has been dropped.
For developers that are still working with production PHP4 environments, the
CakePHP 1.x versions continue to support PHP4 for the lifetime of their
development and support lifetime.

The move to PHP 5 means all methods and properties have been updated with
visibility keywords. If your code is attempting access to private or protected
methods from a public scope, you will encounter errors.

While this does not really constitute a large framework change, it means that
access to tighter visibility methods and variables is now not possible.

In CakePHP 2.0 we rethought the way we are structuring our files and folders.
Given that PHP 5.3 is supporting namespaces we decided to prepare our code base
for adopting in a near future this PHP version, so we adopted the
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md. At first
we glanced at the internal structure of CakePHP 1.3 and realized that after all
these years there was no clear organization in the files, nor did the directory
structure really hint where each file should be located. With this change we
would be allowed to experiment a little with (almost) automatic class loading
for increasing the overall framework performance.

Biggest roadblock for achieving this was maintaining some sort of backwards
compatibility in the way the classes are loaded right now, and we definitely did
not want to become a framework of huge class prefixes, having class names like
My_Huge_Class_Name_In_Package. We decided adopting a strategy of keeping simple
class names while offering a very intuitive way of declaring class locations and
clear migration path for future PHP 5.3 version of CakePHP. First let’s
highlight the main changes in file naming standard we adopted:

Most folders should be also CamelCased, especially when containing classes.
Think of namespaces, each folder represents a level in the namespacing
hierarchy, folders that do not contain classes, or do not constitute a
namespace on themselves, should be lowercased.

This new class encapsulates the parameters and functions related to an incoming
request. It replaces many features inside Dispatcher,
RequestHandlerComponent and Controller. It also replaces
$this->params array in all places. CakeRequest implements
ArrayAccess so many interactions with the old params array do not need to
change. See the CakeRequest new features for more information.

CakePHP no longer uses $_GET['url'] for handling application request paths.
Instead it uses $_SERVER['PATH_INFO']. This provides a more uniform way of
handling requests between servers with URL rewriting and those without. Because
of these changes, you’ll need to update your .htaccess files and
app/webroot/index.php, as these files were changed to accommodate the
changes. Additionally $this->params['url']['url'] no longer exists. Instead
you should be using $this->request->url to access the same value.
This attribute now contains the url without the leading slash / prepended.

Note: For the homepage itself (http://domain/) $this->request->url now returns
boolean false instead of /. Make sure you check on that accordingly:

As with helpers it is important to call parent::__construct() in components with
overridden constructors. Settings for a component are also passed into the
constructor now, and not the initialize() callback. This makes getting well
constructed objects easier, and allows the base class to handle setting the
properties up.

Since settings have been moved to the component constructor, the
initialize() callback no longer receives $settings as its 2nd parameter.
You should update your components to use the following method signature:

publicfunctioninitialize(Controller$controller){}

Additionally, the initialize() method is only called on components that are
enabled. This usually means components that are directly attached to the
controller object.

All the deprecated callbacks in Component have not been transferred to
ComponentCollection. Instead you should use the trigger() method to interact
with callbacks. If you need to trigger a callback you could do so by calling:

In the past you were able to disable components via $this->Auth->enabled =
false; for example. In CakePHP 2.0 you should use the ComponentCollection’s
disable method, $this->Components->disable(‘Auth’);. Using the enabled
property will not work.

The AuthComponent was entirely re-factored for 2.0, this was done to help reduce
developer confusion and frustration. In addition, AuthComponent was made more
flexible and extensible. You can find out more in
the Authentication guide.

The cakeError() method has been removed. It’s recommended that you switch all
uses of cakeError to use exceptions. cakeError was removed because it
was simulating exceptions. Instead of simulation, real exceptions are used in
CakePHP 2.0.

The error handling implementation has dramatically changed in 2.0. Exceptions
have been introduced throughout the framework, and error handling has been
updated to offer more control and flexibility. You can read more in the
Exceptions and Error Handling section.

The API for App::build() has changed to App::build($paths,$mode). It
now allows you to either append, prepend or reset/replace existing paths. The
$mode param can take any of the following 3 values: App::APPEND,
App::PREPEND, App::RESET. The default behavior of the function remains the
same (ie. Prepending new paths to existing list).

Although there has been a huge refactoring in how the classes are loaded, in very
few occasions you will need to change your application code to respect the way you were
used to doing it. The biggest change is the introduction of a new method:

App::uses('AuthComponent','Controller/Component');

We decided the function name should emulate PHP 5.3’s use keyword, just as a way
of declaring where a class name should be located. The first parameter of
App::uses() is the complete name of the class you intend to load,
and the second one, the package name (or namespace) where it belongs to. The
main difference with CakePHP 1.3’s App::import() is that the former
won’t actually import the class, it will just setup the system so when the class
is used for the first time it will be located.

All classes that were loaded in the past using App::import('Core',$class);
will need to be loaded using App::uses() referring to the correct package.
See the API to locate the classes in their new folders. Some examples:

In contrast to how App::import() worked in the past, the new class
loader will not locate classes recursively. This led to an impressive
performance gain even on develop mode, at the cost of some seldom used features
that always caused side effects. To be clear again, the class loader will only
fetch the class in the exact package in which you told it to find it.

CacheEngine is now an abstract class. You cannot directly create instances of
it anymore.

CacheEngine implementations must extend CacheEngine, exceptions will be
raised if a configured class does not.

FileCache now requires trailing slashes to be added to the path setting when
you are modifying a cache configuration.

Cache no longer retains the name of the last configured cache engine. This
means that operations you want to occur on a specific engine need to have the
$config parameter equal to the config name you want the operation to occur
on.

Cache::config('something');Cache::write('key',$value);// would becomeCache::write('key',$value,'something');

You can no longer modify named parameter settings with
Router::setRequestInfo(). You should use Router::connectNamed() to
configure how named parameters are handled.

Router no longer has a getInstance() method. It is a static class, call
its methods and properties statically.

Router::getNamedExpressions() is deprecated. Use the new router
constants. Router::ACTION, Router::YEAR, Router::MONTH,
Router::DAY, Router::ID, and Router::UUID instead.

Router::defaults() has been removed. Delete the core routes file
inclusion from your applications routes.php file to disable default routing.
Conversely if you want default routing, you will have to add an include to
Cake/Config/routes.php in your routes file.

When using Router::parseExtensions() the extension parameter is no longer
under $this->params['url']['ext']. Instead it is available at
$this->request->params['ext'].

Default plugin routes have changed. Plugin short routes are no longer built
in for any actions other than index. Previously /users and /users/add
would map to the UsersController in the Users plugin. In 2.0, only the
index action is given a short route. If you wish to continue using short
routes, you can add a route like:

Your app/Config/routes.php file needs to be updated adding this line at the bottom of the file:

requireCAKE.'Config'.DS.'routes.php';

This is needed in order to generate the default routes for your application. If you do not wish to have such routes,
or want to implement your own standard you can include your own file with custom router rules.

CakeSession is now a fully static class, both SessionHelper and
SessionComponent are wrappers and sugar for it. It can now easily be used
in models or other contexts. All of its methods are called statically.

HttpSocket doesn’t change the header keys. Following other places in core,
the HttpSocket does not change the headers. RFC 2616 says that headers are case
insensitive, and HttpSocket preserves the values the remote host sends.

HttpSocket returns responses as objects now. Instead of arrays, HttpSocket
returns instances of HttpResponse. See the HttpSocket
documentation for more information.

Cookies are stored internally by host, not per instance. This means that, if
you make two requests to different servers, cookies from domain1 won’t be sent
to domain2. This was done to avoid possible security problems.

In order to accommodate View being removed from the ClassRegistry, the signature
of Helper::__construct() was changed. You should update any subclasses to use
the following:

publicfunction__construct(View$View,$settings=array())

When overriding the constructor you should always call parent::__construct as
well. Helper::__construct stores the view instance at $this->_View for
later reference. The settings are not handled by the parent constructor.

After examining the responsibilities of each class involved in the View layer,
it became clear that View was handling much more than a single task. The
responsibility of creating helpers is not central to what View does, and was
moved into HelperCollection. HelperCollection is responsible for loading and
constructing helpers, as well as triggering callbacks on helpers. By default,
View creates a HelperCollection in its constructor, and uses it for subsequent
operations. The HelperCollection for a view can be found at $this->Helpers

The motivations for refactoring this functionality came from a few issues.

View being registered in ClassRegistry could cause registry poisoning issues
when requestAction or the EmailComponent were used.

View being accessible as a global symbol invited abuse.

Helpers were not self contained. After constructing a helper, you had to
manually construct several other objects in order to get a functioning object.

You can read more about HelperCollection in the
Collections documentation.

The following properties on helpers are deprecated, you should use the request
object properties or Helper methods instead of directly accessing these
properties as they will be removed in a future release.

Helper::$webroot is deprecated, use the request object’s webroot
property.

The AjaxHelper and JavascriptHelper have been removed as they were deprecated in
version 1.3. The XmlHelper was removed, as it was made obsolete and redundant
with the improvements to Xml. The Xml class should be used to
replace previous usage of XmlHelper.

The AjaxHelper, and JavascriptHelper are replaced with the JsHelper and HtmlHelper.

The $selected parameter was removed from several methods in FormHelper.
All methods now support a $attributes['value'] key now which should be used
in place of $selected. This change simplifies the FormHelper methods,
reducing the number of arguments, and reduces the duplication that $selected
created. The effected methods are:

The default url for all forms, is now the current url including passed, named,
and querystring parameters. You can override this default by supplying
$options['url'] in the second parameter of $this->Form->create().

CacheHelper has been fully decoupled from View, and uses helper callbacks to
generate caches. You should remember to place CacheHelper after other helpers
that modify content in their afterRender and afterLayout callbacks. If
you don’t some changes will not be part of the cached content.

CacheHelper also no longer uses <cake:nocache> to indicate un-cached
regions. Instead it uses special HTML/XML comments. <!--nocache--> and
<!--/nocache-->. This helps CacheHelper generate valid markup and still
perform the same functions as before. You can read more CacheHelper and View
changes.

Helper::_attributeFormat: how attributes will be generated (ie:
%s="%s");

Helper::_minimizedAttributeFormat: how minimized attributes will be
generated: (ie %s="%s")

By default the values used in CakePHP 1.3 were not changed. But now you can
use boolean attributes from HTML, like <inputtype="checkbox"checked/>. To
this, just change $_minimizedAttributeFormat in your AppHelper to %s.

Controller’s constructor now takes two parameters. A CakeRequest, and
CakeResponse objects. These objects are used to populate several deprecated
properties and will be set to $request and $response inside the controller.

Controller::$webroot is deprecated, use the request object’s webroot
property.

Controller::$base is deprecated, use the request object’s base property.

Controller::$here is deprecated, use the request object’s here property.

Controller::$data is deprecated, use the request object’s data property.

Controller::$params is deprecated, use the $this->request instead.

Controller::$Component has been moved to Controller::$Components. See
the Collections documentation for more information.

Controller::$view has been renamed to Controller::$viewClass.
Controller::$view is now used to change which view file is rendered.

Controller::render() now returns a CakeResponse object.

The deprecated properties on Controller will be accessible through a __get()
method. This method will be removed in future versions, so it’s recommended that
you update your application.

Controller now defines a maxLimit for pagination. This maximum limit is set to
100, but can be overridden in the $paginate options.

Pagination has traditionally been a single method in Controller, this created a
number of problems though. Pagination was hard to extend, replace, or modify. For
2.0 pagination has been extracted into a component. Controller::paginate() still
exists, and serves as a convenience method for loading and using the
PaginatorComponent.

For more information on the new features offered by pagination in 2.0, see the
Pagination documentation.

The view being registered ClassRegistry invited abuse and affectively created a
global symbol. In 2.0 each Helper receives the current View instance in its
constructor. This allows helpers access to the view in a similar fashion as in
the past, without creating global symbols. You can access the view instance at
$this->_View in any helper.

beforeLayout used to fire after scripts_for_layout and content_for_layout were
prepared. In 2.0, beforeLayout is fired before any of the special variables are
prepared, allowing you to manipulate them before they are passed to the layout.
The same was done for beforeRender. It is now fired well before any view
variables are manipulated. In addition to these changes, helper callbacks always
receive the name of the file about to be rendered. This combined with helpers
being able to access the view through $this->_View and the current view
content through $this->_View->output gives you more power than ever before.

Helper callbacks now always get one argument passed in. For beforeRender and
afterRender it is the view file being rendered. For beforeLayout and afterLayout
it is the layout file being rendered. Your helpers function signatures should
look like:

In previous versions there was a tight coupling between CacheHelper
and View. For 2.0 this coupling has been removed and CacheHelper
just uses callbacks like other helpers to generate full page caches.

In previous versions, CacheHelper used a special <cake:nocache> tag as
markers for output that should not be part of the full page cache. These tags
were not part of any XML schema, and were not possible to validate in HTML or
XML documents. For 2.0, these tags have been replaced with HTML/XML comments:

MediaView::render() now forces download of unknown file types
instead of just returning false. If you want you provide an alternate download
filename you now specify the full name including extension using key ‘name’ in
the array parameter passed to the function.

All of the core test cases and supporting infrastructure have been ported to use
PHPUnit 3.7. Of course you can continue to use SimpleTest in your application by
replacing the related files. No further support will be given for SimpleTest and
it is recommended that you migrate to PHPUnit as well. For some additional
information on how to migrate your tests see PHPUnit migration hints.

PHPUnit does not differentiate between group tests and single test cases in the
runner. Because of this, the group test options, and support for old style group
tests has been removed. It is recommended that GroupTests be ported to
PHPUnit_Framework_Testsuite subclasses. You can find several examples of this
in CakePHP’s test suite. Group test related methods on TestManager have also
been removed.

The testsuite shell has had its invocation simplified and expanded. You no
longer need to differentiate between case and group. It is assumed that
all tests are cases. In the past you would have done
caketestsuiteappcasemodels/post you can now do caketestsuiteappModel/Post.

The testsuite shell has been refactored to use the PHPUnit CLI tool. It now
supports all the command line options supported by PHPUnit.
caketestsuitehelp will show you a list of all possible modifiers.

CakePHP 2.0 introduces some changes to Database objects that should not greatly
affect backwards compatibility. The biggest one is the adoption of PDO for
handling database connections. If you are using a vanilla installation of PHP 5
you will already have installed the needed extensions, but you may need to
activate individual extensions for each driver you wish to use.

Using PDO across all DBOs let us homogenize the code for each one and provide
more reliable and predictable behavior for all drivers. It also allowed us to
write more portable and accurate tests for database related code.

The first thing users will probably miss is the “affected rows” and “total rows”
statistics, as they are not reported due to the more performant and lazy design
of PDO, there are ways to overcome this issue but very specific to each
database. Those statistics are not gone, though, but could be missing or even
inaccurate for some drivers.

A nice feature added after the PDO adoption is the ability to use prepared
statements with query placeholders using the native driver if available.

Database statistics are collected only if the “fullDebug” property of the
corresponding DBO is set to true.

New method DboSource::getConnection() will return the PDO object in case you
need to talk to the driver directly.

Treatment of boolean values changed a bit to make it more cross-database
friendly, you may need to change your test cases.

PostgreSQL support was immensely improved, it now correctly creates schemas,
truncate tables, and is easier to write tests using it.

DboSource::insertMulti() will no longer accept sql string, just pass an array
of fields and a nested array of values to insert them all at once

TranslateBehavior was refactored to use model virtualFields, this makes the
implementation more portable.

All tests cases with MySQL related stuff were moved to the corresponding
driver test case. This left the DboSourceTest file a bit skinny.

Transaction nesting support. Now it is possible to start a transaction several
times. It will only be committed if the commit method is called the same
amount of times.

SQLite support was greatly improved. The major difference with cake 1.3 is
that it will only support SQLite 3.x . It is a great alternative for
development apps, and quick at running test cases.

Boolean column values will be casted to PHP native boolean type automatically,
so make sure you update your test cases and code if you were expecting the
returned value to be a string or an integer: If you had a “published” column in
the past using MySQL all values returned from a find would be numeric in the
past, now they are strict boolean values.

Shell no longer has an AppModel instance. This AppModel instance
was not correctly built and was problematic.

Shell::_loadDbConfig() has been removed. It was not generic enough to
stay in Shell. You can use the DbConfigTask if you need to ask the user
to create a db config.

Shells no longer use $this->Dispatcher to access stdin, stdout, and
stderr. They have ConsoleOutput and ConsoleInput objects to handle
that now.

Shells lazy load tasks, and use TaskCollection to provide an interface
similar to that used for Helpers, Components, and Behaviors for on the fly
loading of tasks.

Shell::$shell has been removed.

Shell::_checkArgs() has been removed. Configure a ConsoleOptionParser

Shells no longer have direct access to ShellDispatcher. You should use
the ConsoleInput, and ConsoleOutput objects instead. If you need to
dispatch other shells, see the section on ‘Invoking other shells from your
shell’.

Bake’s ControllerTask no longer takes public and admin as passed
arguments. They are now options, indicated like --admin and --public.

It’s recommended that you use the help on shells you use to see what if any
parameters have changed. It’s also recommended that you read the console new
features for more information on new APIs that are available.

The debug() function now defaults to outputting HTML safe strings. This is
disabled if being used in the console. The $showHtml option for debug()
can be set to false to disable HTML-safe output from debug.

ConnectionManager::enumConnectionObjects() will now return the current
configuration for each connection created, instead of an array with filename,
class name and plugin, which wasn’t really useful.

When defining database connections you will need to make some changes to the way
configs were defined in the past. Basically in the database configuration class,
the key “driver” is not accepted anymore, only “datasource”, in order to make it
more consistent. Also, as the datasources have been moved to packages you will
need to pass the package they are located in. Example: