Migrating from CakePHP 1.2 to 1.3: My Story (Part One of… Possibly More than One)

For the past couple of years I’ve been working on a rapidly evolving CMS project called, not-so-creatively, cms34. It’s built on the open source CakePHP framework.

I love CakePHP. I’ve dabbled with a couple of other frameworks (notably, Zend Framework), and while CakePHP certainly isn’t perfect, I’ve found it by far the easiest to jump into and quickly get a powerful and reliable web application running.

When I started cms34 in late 2008, it was using CakePHP 1.2.0. Since then I’ve kept up with most of the minor point releases, upgrading as far as the current version, 1.2.7, as easily as simply swapping out the cake directory. And in that time, cms34 itself has gone through several major and minor revisions, currently up to what I’m calling version 3.2.

In preparation for version 3.3, I’ve decided to take the plunge and upgrade from CakePHP 1.2.x to the newly released CakePHP 1.3.0. Version 1.3 offers a number of improvements, but it also includes the kinds of changes typical of a major point release that mean an upgrade is not such a simple task. I’ve run into a few issues with the migration from 1.2.x to 1.3.x, many of which are not covered in the project’s official migration documentation, partly due to the incompleteness of the documentation, and partly due to some idiosyncrasies of my application that I wouldn’t expect the documentation to cover. But since I’m probably not in this boat alone, I thought I’d share some of the problems I encountered, and the solutions I found.

Getting started: RTFM

First things first. Download CakePHP 1.3.0. Be sure to get the release version (the one in the list with no hyphenated qualifiers after “1.3.0”). Unzip it and then follow the migration instructions to get started. For the most part this means swapping out the cake directory along with a couple of other files, and then going through all of the notes and making any necessary changes to your application.

In my own experience, I didn’t have to change much: I’ve been trying to keep up with the recommendations in the version 1.2 docs, so I haven’t been using any functionality that got dropped or deprecated. The writing has been on the wall for some time with most of these features and unless your application started with version 1.1 or 1.0, you’re probably not using any of these dead methods anyway.

A few specific issues I did need to address:

  1. Unlike with minor 1.2.x updates, there are a few files outside of the cake directory that need to be replaced. I found it best to just go through the entire release package and replace all files (except those I had modified) with their new versions.
  2. Update your config/core.php file, using the new version as a model. Mine had lots of changes, and I had stripped out all of the instructional comments to make the file less cumbersome to deal with. I wanted to keep those comments stripped out, so I just updated my file with what I needed, and then I kept the distribution’s version of the file in config as core.dist.php so I can refer back to it in the future if I run into any issues.
  3. There are some mixed messages in the documentation regarding the deprecation of AjaxHelper: the migration appendix says it’s deprecated but the main documentation doesn’t indicate that. I’m using it a fair amount and don’t want to have to rework all of that code, so for now I’m leaving it alone.
  4. JavascriptHelper is another matter, but since it appears there are perfect replacements for its functions now in HtmlHelper, I just did a straight-up find-and-replace, changing all instances of $javascript->link() to $html->script() and $javascript->codeBlock() to $html->scriptBlock(). I should note that so far I haven’t really tested any of this functionality to ensure that it’s still working, but no obvious errors have cropped up.

But wait, there’s more!

After following the migration docs, I was overly optimistic that things would just work. They didn’t. First up, I encountered this:

Notice (8): Undefined property: PagesController::$Session
[APP/controllers/app_controller.php, line 383]

Your line number will probably be different, but if you’re using sessions at all (and why wouldn’t you be?), you’ll get this error somewhere. It’s not mentioned in the migration docs, but I found out here that the Session component and helper are not instantiated automatically anymore. The solution is quite easy though. In app_controller.php just make sure that you add 'Session' to the arrays defined for var $components and var $helpers.

That was the biggest and most obvious problem I encountered. Once I had fixed that, I could at least get (some) pages to load, albeit with a few other issues. Namely, my theme was not being applied to the site. I’ll get to that in a minute though, because the problem I decided to fix next came in my CMS admin interface.

Pagination (even if you don’t want it)

I use the PaginatorHelper a lot, especially in the CMS admin. My CMS is modular: there’s a “module” (my term for any model-view-controller group) for pages, a module for blog posts, a module for uploaded files, a module for project porfolios, a module for the event calendar, etc. Each module is represented in the admin interface by a navigation tab, which when clicked takes the user to an index page with a paginated, tabular list of all of the records in the database for that module. In practice (on my own site — yes, I use my CMS to run my own site, of course!), it looks like this:

Unfortunately, the pagination was mysteriously hosed, with the following error:

Unsupported operand types in CAKE/libs/view/helpers/paginator.php
on line 616

What the…? Well, as it turns out, the methods $paginator->prev(), $paginator->next() and $paginator->numbers() have had changes to their input parameters that are currently not very well documented, in that the documentation doesn’t mention that they exist. They are mentioned in the API, but as usually happens when I refer to the API, I found it wanting, to the point that I resorted to digging into the source code directly to try to make sense of what these methods actually do.

In short, where you could previously pass these methods a URL as a string (as the second parameter for prev() and next() and the first for numbers()), now they expect arrays. And numbers(), in particular, really doesn’t like that parameter to be a string (because at one point it uses the += operator to merge two arrays, one of which is the first input parameter), resulting in the Unsupported operand type error.

Fortunately, in my case at least, I found that I didn’t need to pass the URL into any of these methods at all, and that just removing them altogether from the calls fixed the problem.

There was an ancillary problem once I got past the PHP error: inactive “Previous” and “Next” links were appearing on the page when there was no pagination. This was an unwanted addition, but I quickly realized this was an intentional change, and is well-documented. I was able quite easily to make them go away with a little CSS:

span.prev, span.next { display: none; }

With that minor crisis resolved, I could move back to the matter of the theme not showing up.

Changing themes

First, some background on my CMS: I’ve built the application so that I can have a single “core” system that works for numerous client websites, organized in a way that it’s easy to deploy updates across a number of separate sites. The system is also built to support multiple sites running on a single installation (by way of a Site model, with every piece of data in every other model having a site_id field keying the content to the proper site).

There are two key features of CakePHP that I rely on to make this all work: the look-and-feel (and site-specific view functionality) of each site is managed using Themes, and any site-specific controllers and views are handled with Plugins.

It is documented, unfortunately not in the migration appendix, that version 1.3 of CakePHP has changed how theme assets (static files like images, JavaScript and CSS) are organized. Now, instead of placing these in a directory under app/webroot/themed, you create a webroot directory inside the appropriate theme folder in app/views/themed. This is nice, in that now all of the files for a theme are in one location. It can cause a performance hit though, as these files are now being processed through PHP. You can still put the files under app/webroot to avoid this performance hit, but, annoyingly, the path has changed, as noted in the documentation. I decided to go with the new approach under app/views, as performance is not a major issue with the current implementations of my CMS, and the benefit of a single, consolidated directory for each theme is worth the trade-off. If performance does become an issue, though, at least now I know what to do about it.

More to come…?

After completing the above changes, I spent some time exploring my test application, both the user-facing site and the CMS admin interface, and so far I haven’t come across any other problems. Which is not to say I’m ready to roll this out to all of my clients tomorrow morning. I want to make the switch soon, as maintaining two separate code bases is a cumbersome task for a solo freelancer. But while things look good for now, this kind of major upgrade requires some solid testing and troubleshooting. If I run across any other issues, I’ll post them in Part Two.

Apple vs. Adobe: This is fargin’ war!

I’m sure I’m not the only child of the ’80s who watched Johnny Dangerously several (hundred) times as a kid. One of my favorite characters was Roman Moronie, whose command of the English language — well, more specifically, English profanities — was tenuous at best. I’m sure he would be highly offensive to a particular nationality or ethnic group, if it were possible to tell where he was actually from. (That mystery itself being a joke in the movie; at one point a newspaper headline reads: “Roman Moronie deported to Sweden — claims he’s not from there.”) Yes, I was a big fan of ’80s Michael Keaton movies that, in retrospect, are somewhat problematic. Johnny Dangerously, Mr. Mom. I think I partly liked him because I thought maybe he was related to the characters on Family Ties. OK, I was old enough to know better than that.

What does this have to do with Apple vs. Adobe, or anything for that matter? I’m not sure, but I do know that their battle has escalated to fargin’ war!

Steve Jobs fired the first metaphorical salvo last month with his Thoughts on Flash. I thought he nailed it, as expected. Of course Adobe can’t let him win, so yesterday Adobe retaliated with their “We [heart] Apple” / “We [heart] Choice” ad campaign and an open letter of their own.

The idea that Flash is somehow open — or that Apple is somehow trying to “close” the web — is both disingenuous and misguided. My natural inclination is to blather on ad nauseum about such things, but as I’m home with a sick kid today (which is to say, there’s enough nauseum in this house already), I’ll let some more pithy writers say it for me.

First, an excellent and concise response from Jim Whimpey in Brisbane, Australia (by way of John Gruber in Philadelphia):

Adobe: not open, claim to be.
Apple: not open, don’t claim to be, contribute heavily to that which is truly open.

If that’s not pithy enough for you, a picture is worth a thousand words. Via Jeffrey Zeldman in NYC:

Update: Over on the Macworld website, the Macalope has some choice words on this topic. It’s worth reading in its entirety, but here’s my favorite bit, dissecting excerpts from the Adobe open letter:

If the web fragments into closed systems, if companies put content and applications behind walls…

You mean like the wall of a lousy runtime environment that would just as soon crash the Macalope’s browser as play back a Daily Show clip? The wall of a development environment controlled by one company that makes some pretty good coin off the deal?

Oh, no. That’s not the wall you were talking about. Sorry. Go on.

…some indeed may thrive — but their success will come at the expense of the very creativity and innovation that has made the Internet a revolutionary force.

The Internet is an open range where anyone can compete in any way they like. But Adobe didn’t make the Internet. In fact, they tried to wall off a section of it. Apple, on the other hand, made its own walled garden with a scenic view of the Internet.

iPad: Son of Newton

There’s some buzz going around concerning Apple’s new iPad commercial and its similarity to one Apple produced for the Newton two decades ago. Though I’m not the first to comment on this, I have a few thoughts of my own, so here goes…

First, let’s watch both commercials. I did not remember this (apparently) “classic” (in John Gruber’s words) ad for the Newton:

Now, watch Apple’s new iPad ad:

Wow. Homage indeed. I doubt very many people remember the Newton commercial, but the iPad commercial is stunningly similar. This had to be deliberate, but I’m wondering what exactly that deliberateness is supposed to mean.

Well, I’ll tell you this: watching the two ads back-to-back, I’m left feeling that a) the Newton really was way ahead of its time, and b) the Newton ad seems like one of those futuristic concept videos Apple (among other computer makers) seemed to love producing in the 1980s.

Newton was a vision of the future. iPad is the reality. That Newton actually became a shipping product says a lot about Apple’s ability to realize its vision (compared to the long line of never-to-be-made concepts that have come from Microsoft over the years, most recently… well… this). But the Newton was too far ahead of its time. Then again, it ushered in the PDA era, which ushered in the “smartphone” era, which led to the iPhone and now the iPad. So maybe Apple was really seeding (if you’ll pardon the pun) its own future with the Newton.

There are two key lines that for me define the difference between the two ads:

“Newton can receive a page and sends faxes and, soon, electronic mail.”

“(iPad is) 200,000 apps and counting. All the world’s websites in your hands.”

Granted, paging and faxing were still relevant technologies when the Newton was released, but they were already doomed, and the best Apple could say was that “soon” Newton could handle “electronic mail” (even then, using a soon-to-be-antiquated term). In contrast, the iPad hits the ground running, leveraging the existing success of the iPhone, and with forward momentum for future technologies. Newton was about what could be, but iPad is.

TinyMCE and the relative URLs SNAFU

My CMS, cms34, uses a few third-party tools for certain complex features. One of the most useful is TinyMCE, a JavaScript/DOM-based drop-in WYSIWYG text editor. If that doesn’t mean anything to you, you probably want to stop here, but in case you’re a glutton for punishment, it is, in short, a way to produce HTML-formatted text with a word processor-like interface. Think Microsoft Word in a web browser, with the results being formatted for display on a web page. Slick.

Anyway, there’s been one nagging problem: When users paste in URLs for links, TinyMCE converts any on-site links into “relative URLs” — it strips out the domain name. This is not necessarily bad; in fact, for the most part I would want it to do that. But for some reason the nature of my CakePHP-based CMS seems to confound TinyMCE’s ability to properly determine the relative URL. And what’s worse, the CMS includes an enewsletter editor which has to have absolute URLs, but TinyMCE was converting them to relative URLs even if the user pasted in an absolute URL.

A little research led me to a handy explanation in the TinyMCE Wiki. Basically, if you want your URLs to always be absolute, make sure your TinyMCE configuration includes the following:

relative_urls : false,
remove_script_host : false,
document_base_url : “http://www.site.com/path1/”

Of course, you’ll want to change the value of document_base_url to be the actual base URL of your website. As it happens, my CMS has a global JavaScript file that creates a variable called baseUrl that I can use anywhere in JavaScript to substitute for the full base URL of the website. So, in my case, I set the value for document_base_url equal to baseUrl.

And, voilà, it seems to work!

Chaos Rings: an iPhone game review

I’m not a super hardcore gamer. I don’t spend any time in MMORPGs, I’m not on any XBOX Live leaderboards, and I’m able to balance my interest in playing video games with other things like work and family. (When something’s gotta give, that something is, invariably and rightly, playing video games.)

And yet, I guess I’m a pretty serious gamer. I’ve been into video games since I first got an Atari 2600 in 1982. I’ve been collecting both vintage and modern games since I had a resurgence of interest in 2002, and I now count among the game systems I own: Panasonic Tournament 2000 (a mid-’70s Pong-style console), Atari 2600, Atari 5200, Atari 7800, Intellivision, NES, GameCube, XBOX, Wii, XBOX 360, Sega Game Gear, Game Boy Advance and Nintendo DS. And all told, across those systems I own a total of around 500 games. And, oh yeah, there’s the iPhone. But… is the iPhone a game system or not?

I’ve explored this issue before, and come to the conclusion that not only is it a game system, but it’s arguably superior to the Nintendo DS, at least in two key ways: 1) its technical capabilities, and 2) its portability. To paraphrase Chase Jarvis, the best game system is the one you have with you.

The iPhone’s technical capabilities far outshine those of the Nintendo DS (the main strength the DS has working in its favor is its physical controls), and it also has the big advantage of the fact that I’m far more likely to have it with me at any given time than my DS, even considering how much more often I carried the DS with me before I had an iPhone.

Since I got the iPhone, I’ve spent far more time playing games on the iPhone than on all other systems put together. And yet I’ve mostly played casual games like solitaire, Scrabble, or, when I’m feeling particularly… erm… risky, Strategery. But the deeper, more engaging adventure style games I really like, especially games like the ones in Nintendo’s Metroid and Zelda franchises, or Konami’s recent Metroid-esque entries in the Castlevania series, just aren’t there.

Why not?

It’s pretty clear that we’ll never see a Metroid or Zelda game on the iPhone. Frankly I’m a bit surprised Konami hasn’t released a Castlevania game for the iPhone yet — they’ve made a few other iPhone games — although one may be in development and I just don’t know about it.

For the most part the iPhone seems to have become a magnet for casual games. It’s easy to understand why, to some extent. The iPhone is owned by a lot of “non-gamers” and casual games are most appealing to them. I think the iPhone as a gaming platform shares a lot of its audience with the Wii. But the Wii does have Metroid and Zelda and other “hardcore” titles.

To be fair, the types of adventure and action RPG games I enjoy on other systems do exist on the iPhone, but in my experience so far… well… they all kinda suck. I’ve been lured in many times by the promise of “Zelda-like gameplay” and impressive-looking graphics, but although I’ve found a few to be of passable quality, almost all of them are so buggy, or so riddled with grammatical or spelling errors, or just so ill-conceived and sloppily-executed, that I play them once and then delete them off my iPhone, consoling myself in the fact that I only wasted $3 instead of $30 (the going price on new Nintendo DS titles).

As for the big question — why this particular genre of games has never delivered a satisfying experience on the iPhone, that’s the big mystery. There are plenty of casual games on the iPhone that demonstrate a tremendous amount of polish and great execution: apart from the aforementioned Strategery, there’s quite possibly the best casual game ever — Plants vs. Zombies, and of course an assortment of popular card, board and word games.

Up to now, the best 3D adventure game for the iPhone was the Halo-meets-Metroid-Prime clone N.O.V.A. It’s pretty good, but there’s still something I just can’t pinpoint about it that just makes it seem a little rough and just not totally engaging. Still, it’s been the most promising game I’ve seen yet for the platform. Until…

And now, on to the review…

Chaos Rings is a new Japanese-style RPG from Square Enix, developed specifically for the iPhone. It’s not the first Square Enix game for the iPhone — a few of the early Final Fantasy games have been ported, for instance — but it’s their first full-blown, brand new all-out effort on the platform.

It’s the most expensive game I’ve ever bought for the iPhone. But at $12.99, it’s still less than half the price of a standard new Nintendo DS game. (Most Square Enix games for the DS retail for $39.99.) But there’s a reason for the extra price: the depth, quality and polish is unmatched by anything I’ve yet seen for the iPhone.

The game looks fantastic: the art is highly detailed and is consistent with the established and popular Square Enix style, and it’s technically impressive — the iPhone’s 3D graphics capabilities are stunning. The musical score and sound effects are great, too. Gameplay-wise, Chaos Rings is a traditional 3D RPG dungeon crawl: you explore a diverse variety of worlds, battling monsters with both attacks and magic, and there are also a number of puzzle rooms. The puzzle rooms feel a bit tacked on, although they’re a fun diversion from the level grinding characteristic of the game style.

Something that cannot be underestimated in terms of what makes the gameplay in Chaos Rings engaging in a way that so many other, otherwise good iPhone games (Hero of Sparta and Dungeon Hunter come to mind) lack is the control mechanism. It’s become standard practice for iPhone games that require “traditional” movement schemes to employ a “virtual” (on-screen) direction pad and buttons. Typically, mimicking the controls on traditional handhelds, the D-pad is placed in the lower left corner of the screen, and the buttons in the lower right. The big problem with this approach is that you don’t want to have to look at where you’re placing your fingers: when the D-pad and buttons are physical objects, there’s a tactile experience. You don’t have to look, because you can feel that your thumbs are in the right place. Not so with virtual controls on a glass screen.

But somewhere along the way — N.O.V.A. is the first game I encountered with it — an important advance was made: the D-pad only appears when you touch your finger to the screen, and it appears wherever you touch. So you no longer have to worry about putting your thumb in the right place — just put it down, and it’s always centered on the D-pad. Likewise, there may be “buttons” on screen, but usually just one, and a tap anywhere counts as a button press. This change makes a huge difference in playability and delivering a satisfying experience. As I said, N.O.V.A. uses this kind of control scheme, but that game had other problems that have kept me from really getting into it. But Chaos Rings offers a near-perfect execution of this evolved virtual control scheme, and it may be the single most important factor in my enjoyment of the game.

Chaos Rings is not a masterpiece — it’s not the kind of seamless, immersive world I loved so much in Metroid Prime (my favorite video game of all time), but it’s so far beyond every other iPhone game I’ve seen, in every imaginable way, that it seems to be an introduction to a new era in iPhone gaming… real iPhone gaming. It’s the first adventure/RPG game I’ve seen on the iPhone that I genuinely can’t put down. I’m sure there will be better iPhone games in the future — especially as the platform evolves with the iPad — but I truly believe this game will stand as a milestone in that evolution.