Upgrading to CakePHP 3.0

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
  1. git clone git://github.com/cakephp/upgrade.git
  2. cd upgrade
  3. composer install
  4. 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 files to Admin/action.ctp. There is no task to handle this.
  • Run upgrade locations, commit the results.
  • Run upgrade namespaces commit the results.
  • Run upgrade app_uses commit the results.
  • Run upgrade app_uses commit the results.
  • Run upgrade rename_classes commit the results.
  • Run 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.
  • Run upgrade tests commit the results.
  • Run upgrade rename_collections, upgrade method_names, and upgrade method_signatures committing the results after each command.

With the automated updates done, I created new app.php, 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.

ORM upgrade

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 formatResults() calls.
  • 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.

Webservice integrations

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.

Replacing requestAction()

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.

Prefix Actions

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.

Looking Back

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.

Comments

Only one thing I noticed:
- upgrade method_names (without update_)
- upgrade method_signatures (without update_)

mark on 1/1/15

Don’t you have to download cakephp3 or use composer to install it? The upgrade tool does this for you?

Nice article. Extremely usefull. Do you suggest we can start upgrading our smallest least significant (if there is such a thing!) sites to v3?

Harris on 1/2/15

Well, considering it took you 5-6 hours for a smallish project, and recalling how long it took me to move a big project from 1.3.x to 2.x, I think I’m going to pass on upgrading to 3.x, at least in a single go. I might look into slowly moving parts of the application to a fresh 3.x install, and abstract it away through an internal API. That might let me move it part by part, but it still sounds like a maintenance nightmare.

How good are the performance increases? Are there any benchmarks for 3.x yet?(compared to 2.x)

Nick on 1/2/15

Harris: You do have to install CakePHP 3.0 into your application using composer. But the upgrade tool, will download all of its dependencies when you run @composer update@.

Nick: You can also ‘migrate’ to Cake3 by replacing 2.x packages with 3.x ones piecemeal. For a large application I would recommend including the new ORM, and updating one group of models at a time. This will allow you to incrementally do the hardest part of the 2.x to 3.x migration.

I did some early benchmarks against the alpha releases and the performance was the same or better across the board for 3.x, I’ve not done any recent benchmarks though.

mark story on 1/2/15

Hi Mark

Could you explain this a little further?

“You can also ‘migrate’ to Cake3 by replacing 2.x packages with 3.x ones piecemeal. For a large application I would recommend including the new ORM, and updating one group of models at a time. This will allow you to incrementally do the hardest part of the 2.x to 3.x migration.”

Does this mean we could use the orm part from 3.x on individual models in 2.x?

Could you provide an example on how to do this?

Thanks,
Frank

Frank on 1/3/15

Frank: One could do that. I don’t really have a good example of it handy, but I was hoping to cover that approach in a future blog post.

mark story on 1/4/15

Great read. This week I’m planning to upgrade to 2.6 but now with the 3.0RC1 I might start a branch to transition to 3. I was planning to do it all by hand but will give the upgrade tool a try. During the 1.3 to 2 transition I tried the upgrade shell but it didn’t work for me (though I was very new to Cake back then). Seems the ORM update is what will take the most time, so reading yours steps will be really helpful.

I’m more worried about ACL (I basically transformed the ACL shell to MVC) and the Blowfish hasher (I use my own implementation to make the original one more configurable and generate the salt).

Anyway thanks for all the tips.

Manuel on 1/4/15

Manuel: The DefaultHasher in 3.0 is fully compatible with the old Blowfish hasher, you should see no difference. I suggest, though, migrating your passwords to the new hasher as it is more secure.

Jose Lorenzo on 1/5/15

Hi.

I want to upgrade from CakePhp 1.2 to 2.6, is there a tool that you recommend me or I have to do that on my own?

I don’t know if the upgrade shell works for me too.

Thanks.

Emiliano on 1/30/15

Ugh, not looking forward to upgrading to 3.0 is the person mostly responsible for cake 3.0 took that long to convert a simple site.

Clint on 2/6/15

Hi mark, and about the behaviors, what i need do to keep your functionallity?

Waldemar on 3/11/15

Do you have to run app_uses twice? Or is that a typo?

David Yell on 3/23/15

Can you give (or point me to) a detailed explanation of how to upgrade Cake 3 AROUND a given app? In other words, if I’m developing an app in CakePHP 3.0.0-RC1, how do I go about upgrading the framework to the latest version?

Steve on 3/28/15

Hey Mark, I’ve been a Cake devotee since 2008 (inherited a couple 1.1 apps). But it’s a very sad day for me. You guys have lost me by breaking backward compatibility.

Cake v3 should not be called Cake v3. It should be called something totally new because it is totally new. My huge 2.x apps are now stuck and will not receive any core or plugin improvements because of the breaking changes. Upgrading will cost mid 5 figures (that’s just the apps I maintain for myself and my clients — imagine what it would cost large orgs?)

Why would I upgrade to 3 when you can’t be trusted to maintain compatibility? You’ll break it again in v4 and cost me several thousands of dollars to “upgrade”. I’m not going to make that mistake again.

I never really considered any other frameworks because of the “equity” I’ve already sunk into my and my employers’ apps. But now you’re forcing us to learn a totally new API, a new ORM, etc — why shouldn’t I evaluate better supported and more popular frameworks? You’ve made the choice too easy for me by reducing my Cake “equity” too aggressively. Either choice entails that same loss of “value”.

Here’s an analogy: Mysql 7 comes out and the API is totally changed and all SQL written for Mysql 6 and below no longer works and all work on Mysql v6 stops (other than security fixes). Does it still make sense to call it Mysql? Would anyone continue trusting Mysql if they can’t be sure every major version might break compatibility? (and also imagine a bizarro universe where Mysql had a huge ecosystem of plugins that were rendered obsolete with the release of v7)

Cake has gone several steps back in the framework wars and the marginal lead you had over other frameworks is now totally gone. This was a huge strategic error and it will take years for Cake to recover from it.

The saddest part is that you did not learn from others’ mistakes, i.e. Python. Version 2 vs version 3 is still a debate a full 7 years after the release of v3. Why? Because v3 was incompatible with v2. Google has still not switched to Python v3 — 7 years after it’s release. http://blog.thezerobit.com/2014/05/25/python-3-is-killing-python.html

Sigh. I’m reluctantly off to google “php frameworks”…

Costa on 3/29/15

Harris: You should use composer to install CakePHP 3.0. The upgrade tool does install a copy of CakePHP for its own use, but your application will also need a copy for your upgrade.

mark story on 4/3/15

Hi Mark,

Is there any tips how to upgrade apps with CakePHP 3.0.0 to CakePHP 3.0.1?

Thanks :)

Jang on 4/12/15

Steve: You should be able to just update the version number in your @composer.json@ file and run @composer update@

Costa: We still plan on maintaining CakePHP 2.x for many years to come. We are still planning on doing a 2.7 release and possibly a 2.8 release if the community is interested.

I totally understand that upgrading may not be a feasible option for many people, and I don’t think that the 3.0 release makes all your existing code obsolete in any way. If you are considering moving to other frameworks, how are you going to handle that upgrade? I would think that would be equally expensive in time and money, perhaps more as nothing is the same.

Breaking changes are never fun. But we were in a tight spot. The current Model layer had been a proven weakness in CakePHP 2 and the reason that many people won’t even consider using CakePHP. Given that we could no longer grow the community because of the current design/features, and any breaking change would upset existing users. We felt it was best to plan for the future, and continue to maintain the existing releases to support people who cannot make the switch.

mark story on 4/23/15

Mark:

Upgrading: Switching framework won’t help upgrading, but the breaking changes has made me lose trust in Cake. So now I’ll consider other frameworks for all new projects. Before v3 I never questioned other frameworks because I thought backwards-compatibility was priority for the Cake maintainers. I don’t want to repeat this a few years from now.

“plan on maintaining CakePHP 2.x for many years to come”:
Security fixes, sure, but we both know the maintainers will only be adding interesting new features to Cake3. Cake2 is dead just like PHP4 is.

“current Model layer had been a proven weakness”:
Look, if PHP itself could go from v4 to v5 and add tons of cool OOP features without breaking the majority of old code, I’m sure you guys could have figured something out. How about a new Model layer that is optional? Imagine if a Cake app could use both the 2 AND the 3 model layers?

All you had to do is make “rolling” improvements and deprecate the old methods a few at a time instead of spending 3 years in alpha and then just dropping a house on everyone’s heads. Heck, you could have released a major version per year each with a few breaking changes that were easy to fix/upgrade.
Isn’t that the main advantage of agile development? Cake3 was waterfall and it shows.

Cake does not have the reverence to sustain this kind of change. IMO, this is the beginning of the death of Cake.

Costa on 5/3/15

Costa: I’ll reply to the individual points.

I thought backwards-compatibility was priority for the Cake maintainers. I don’t want to repeat this a few years from now.

The larger part of CakePHP and the Model layer has been backwards compatible for almost 9 years. Many other frameworks never get to that age, let alone without major API changes.

Cake2 is dead just like PHP4 is.

I feel that is an unfair comparison. PHP4 was has been end-of-life since 2007. While Cake 2 has a planned feature release for later this year.

Imagine if a Cake app could use both the 2 AND the 3 model layers?

You can use the 3.x ORM in a 2.x application. Having both the old model layer and new ORM would be pretty confusing and hard to maintain though which is why we elected to only have one implementation going forward.

All you had to do is make “rolling” improvements and deprecate the old methods a few at a time instead of spending 3 years in alpha and then just dropping a house on everyone’s heads. Heck, you could have released a major version per year each with a few breaking changes that were easy to fix/upgrade.
Isn’t that the main advantage of agile development? Cake3 was waterfall and it shows

I completely agree that the development cycle around 3.0 was way too long. I don’t think a major release each year with breaking changes would have made people much happier. Instead of one big break, they would be dealing with ‘constant’ breakage. From what I’ve witnessed around other projects this is received just as poorly as the approach we have taken.

I’m sorry that you’re not happy with the work we put into CakePHP 3.0. As I said earlier, we’re going to continue supporting 2.x for quite sometime with more than just security releases. It sounds like you are going to move on though, and I wish you all the best in finding a framework that can provide the kind of stability you are looking for.

mark story on 5/4/15

Ok what I have done is copied my Cake2.0 app into a new directory, installed Cake3.0 into that same directory and ran the “upgrade all” command over it and when it’s done nothing much changed except the namespaces and the uses calls.

I tried the same steps and called “upgrade locations” instead of all and still nothing changed here. I got stuff similar to:

Processing /home/aymanrb/Dev/……/app/Controller/QuestionsController.php
no change

What am I missing here, I expected my controllers to be moved to the src/ directory and have the code updated there. Am I wrong on this ?

Ayman Bedair on 5/7/15

Have your say: