CakePHP 2.x: Migrate from 1.3

The CakePHP 1.3 to 2.0 migration guide does probably cover most of what we have found below…but it appears to be written by and for the developers of CakePHP rather than for people who use CakePHP to develop their own applications. So here are some of the things we are doing during our 1.3 to 2.4 migration (although I can’t guarantee that they were all actually necessary), in case they help others. Please note that this is a work in progress 🙂

Upgrade Shell

Upgrade Shell – this promised considerably more than it delivered but did at least rename the controllers and changed the case of some of the folders under app. The rest were corrected using the Folder Names section of the migration guide, including the Views sub-folders and renaming ‘helpers’ to ‘Helper’

Files to copy from 2.x code

Copy the following from your download to the same place in \app:

  • \app\webroot\index.php
  • \app\View\Helper\AppHelper.php
  • \app\Config\core.php (contains a new error handling config. info)
  • \app\Config\routes.php (contains a couple of new setting to load plgin routes and ‘default’ CakePHP routes.

Update Paginator code

In view:

echo $this->Paginator->counter(array(
    'format' => __('Page %page% of %pages%, showing %current% courses out of %count% total', true)
    ));

changes to:

echo $this->Paginator->counter(
    'Page {:page} of {:pages}, showing {:current} records out of
     {:count} total'
);

In controller, this syntax:

$this->paginate['Event'] = array(
            'order'=>array(
                ..
                ),
             'conditions'=>array(
                ..
                 )
             );

$this->set('events', $this->paginate());

changes to:

$this->paginate = array(
                'order'=>array(
                     ..
                    ),
                 'conditions'=>array(
                    ..
                     )
                 );
$this->set('events', $this->paginate('Event'));

Change all ‘action’ functions in ctp files from:

function index(){}

to

public function index(){}

Auth Component

Now required to explicitly log users in – not done automagically any more. Where we use WebAuth to authenticate and manually log users in:

if($this->Auth->login($user_id))
     {
     $this->Session->setFlash('Logged in');
     }

becomes:

$this->request->data['User'] = array_merge($this->request->data['User'], array('id' => $user_id));
if($this->Auth->login($this->request->data['User']))
     {
     $this->Session->setFlash('Logged in');
     }

Form2Helper

Although, some of this is specific to the Form2Helper (to make MySQL enum fields show enumerated values rather than a number), some of these points will apply to all helpers:

  1. Change name of helper to Form2Helper.php, instead of Form2.php;
  2. Change App::import(‘Form’) to App::uses(‘FormHelper’, ‘View/Helper’) above class definition (replacement of App::import in 2.x with App::uses)
  3. $this->_introspectModel($modelKey, ‘fields’, $fieldKey) instead of $this->_introspectModel($modelKey) (changes to _introspectModel)
  4. After an hour or two of trying to work out why the first enum input in a form was being output as a standard text box while subsequent inputs for the same field in the db, were coming out correctly as selects, I realised that:
    isset($this->fieldset[$modelKey])

    was not returning false when:

    $this->fieldset[$modelKey]['fields']

    was returning ‘null’ so I have replaced it with:

    if (!isset($this->fieldset[$modelKey]['fields'][$fieldKey]))

    and it’s all working nicely now.

Request Object

Use $this->request->data instead of $this->data

FormHelper

FormHelper::select(string $fieldName, array $options, mixed $selected, array $attributes)

becomes

FormHelper::select(string $fieldName, array $optionsarray $attributes)

and

$html->link

becomes

$this->Html-link()

Migrating Cordova/JQuery Mobile app from Android to iOS

Some notes on this process in case they are useful to others:

Back button

Android specifically prohibits back buttons due to the presence of a physical Back button on all Android mobiles. However, in iOS, it’s the norm. JQuery mobile does provide an easy to insert header back button :

<a href="#" data-role="button" data-rel="back" data-icon="arrow-l">Back</a>

but it uses the JQuery theme. If you want to make it look like an iOS back button, this article makes it relatively easy.

Navigation

In Android,with Cordova, we have to use absolute URLs for navigation:

navigator.app.loadUrl("file:///android_asset/www/mypage.html");

In iOS, we can use the much simpler form:

location.href = "mypage.html";

Seemingly random clicks firing intermittently

It seems that using JQuery Mobile’s ‘vclick’ event in iOS can cause problems, although the same code was working fine in Android. I was seeing a page change, followed by another page change as if something in the first page loaded had been clicked. After trying all sorts of event undelegation and unbinding, I finally looked at JQuery’s vclick documentation. This explains that there is a slight delay between the JQuery’s ‘vclick’ event  and the native ‘click’ event. When the content under the clicked point changes (as in this case with a new page load), the click event can actually fire on the changed rather than the original content. In situations like this, the recommendation is to use the ‘click’ rather than ‘vclick’ which solved the problem for me.

External pages

My app opens links to an external site for further information. In Android, simply specifying a full http:// prefix URL was enough to ensure that it loaded in the device’s normal web browser. In iOS, the default to seems to be to load it within the embedded brwoser which is being used to run your Cordova application, which is far from ideal. The workaround seems to simply add:

target = '_blank'

to all external links – they then fire up the iOS device’s Safari browser.