I recently finished upgrading this site to CakePHP 3.0.0-dev from 2.5.5. I thought I’d share my experiences, as they might be helpful to other people attempting to update a CakePHP 2.x application to 3.0.
In terms of scale & size, this site is pretty small and simple. It has a mere 12 tables, and ~5000 lines of code including HTML, and uses 3 plugins. Overall, the work took me 5 or 6 hours spread out over a few evenings.
The Upgrade Tool
I would suggest anyone attempting to do an upgrade to give the upgrade shell a serious look. It helps automate many of the tedious parts of upgrading an application and is continuously getting better as dereuromark tirelessly adds more tasks to the tool. To install and use the tool, do the following:Show Plain Text
- git clone git://github.com/cakephp/upgrade.git
- cd upgrade
- composer install
- bin/cake upgrade —help
You should be able to see the help for the upgrade tool now. You can now use the commands to apply each of the various changes that need to be made. I would recommend the following process for using the upgrade tool:
- Clean up any stray empty files. The upgrade tool does not handle these.
- Rename your admin views. E.g.
Admin/action.ctp. There is no task to handle this.
upgrade locations, commit the results.
upgrade namespacescommit the results.
upgrade app_usescommit the results.
upgrade app_usescommit the results.
upgrade rename_classescommit the results.
upgrade fixtures. There were a few problems with my fixtures, as I hadn’t updated them since the 1.2 era. However, after I updated them to 2.x standards the upgrade tool worked great.
upgrade testscommit the results.
upgrade method_names, and
upgrade method_signaturescommitting the results after each command.
With the automated updates done, I created new
bootstrap.php and other configuration files. I used the ones in cakephp/app as a starting point. Since I completed my upgrade a few weeks back, the
upgrade skeleton task has been added which copies all the important files out of a clean application skeleton into your app. When running the upgrade tool, you can always use the
--dry-run --verbose option to preview what will happen.
The changes around the Model/ORM were the most time consuming, and represented most of the work I had to do. Because there is no easy way to migrate these classes, it was ‘just work’. My approach to updating models was:
- Move and rename all the Model classes into Table classes.
- Create entities using
bin/cake bake model comments --no-table
- Convert before/afterfind logic into custom finders, and or
- Find code that used
saveField()or other row mode methods and convert those to work with entities.
- Update all the conditions used in finds to use the plural table aliases.
- Work through my behaviors, and models one by one and get tests passing. Where I didn’t have tests, I used a controller action as a ‘test’.
While the ORM upgrades were a pile of work, I ended up with considerably fewer lines of code in my table classes. I feel that most of this was due to the query builder and new finder implementations being simpler to use and the ORM being more expressive.
I use a few webservices – last.fm, twitter, and akismet – and in the past these were implemented as ‘models’. That approach always felt like using a square peg in a round hole, but it worked. In 3.0, that odd fit was really uncomfortable. I ended up re-implementing each of the webservice wrappers I use as ‘service’ classes that used a few core traits. I used
Cake\Core\InstanceConfigTrait in all the services. The
InstanceConfigTrait gives a nice API for handling configuration on each of the service instances. The
Cake\Log\LogTrait makes it easy to add logging to services. Outside of these traits, my webservice integrations ended up being very basic classes that use
Cake\Network\Http\HttpClient to do external API calls.
My site leaned on requestAction pretty heavily, and that was something I wanted to replace as well. Each of the panels in the sidebar, as well as all the panels in the footer were implemented with cached
requestAction calls. These use cases were a natural fit for view cells . I moved each panel into a View Cell that called the relevant custom finder method(s). This slimmed down my controllers considerably, as I had re-factored the code into a more fitting place.
Prefixed controller actions are implemented as separate namespaced controllers in CakePHP 3.0. I had previously used prefix routing to build my admin interface. Because I hadn’t customized the output from bake much after creating it, I was able to quickly regenerate a new admin interface with
bake again. I then copy and pasted over the unique or special methods/templates that I had made to restore the non-crud features my site has.
My site has shamefully low test coverage, and I feel that if I had better coverage, I would have been able to avoid most of the tedious browser debugging. While this site is pretty basic, I found the upgrade to be pretty reasonable. However, I’m very familiar with the internals of CakePHP, and your mileage may vary.