What I’ve learnt over the last two months

19 09 2007

The last two months have been pretty hectic for me. I work full-time and also foolishly decided to do a full work load at university this semester as well. I found that the two don’t go togethter so well. Funny that. So I have learn’t the hard way that time managment is a skill and is a very hard skill to master.

Here are just a couple of other random things I have found out over the last few weeks:

  • Outlook Addins are a pain to develop – in managed code at least. I hear using unmanaged Win32 API is actually easier
  • Multiply that by 10 when deploying your addin in a terminal services environment
  • Never “port” an Access “application” to .NET. It is best to start from scratch and do it properly
  • Organising a group university assignment is a project in and of itself
  • Dragging yourself out of bed at 5 in the morning to go for a run eventually gets easier
  • Puppies are the cutest thing, but also the most annoying thing. Although I have taught her to sit

The good news is that I am starting a rather large CakePHP project very soon, so expect to see some more regular Cake posts in the near future.

Oh and dont forget to check out the new CakePHP Podcast “The Show“. Put a voice to those Cake characters we all know. The podcast has a good vibe to it and is actually really informative, e.g. I didn’t know that Cake 1.2 can handle XML natively in models. Jeff does a good job of interviewing Nate and gwoo in the pilot about the new features in the upcoming 1.2 version.


Cracked 100

17 07 2007

Thanks to all the readers yesterday who helped me pass 100 hits in a day – 135 to be exact. This may not impress some, but I think it is alright for a niche blog that has only been running for 40 days.

So cheers to you all. 🙂

All About Validation in CakePHP 1.2 – Part 2

6 07 2007

In my previous article I discussed the new constructs for Model::validate. This article follows on from this and is a run down of the new validation methods and rules available.

First up there are a couple of regular expressions defined, which are the same from CakePHP 1.1 and are pretty self explanatory. These are VALID_NOT_EMPTY, VALID_NUMBER, VALID_EMAIL, and VALID_YEAR (between 1000-2999).

The general format of the following validation methods is

var $validate = array('field' => array('rule' => 'ruleName'));

Where parameters are required, such as between and cc, the format is

var $validate = array('field' => 
        array('rule' => array('ruleName', 'param1', 'param2'));

Allows only digits and a-z or A-Z.

Checks that a strings length is between a min and max value.

Checks if a field is empty and treats whitespace characters as empty.

Credit Card Number validation, includes luhn check and Card Type to number format. Takes one parameter which can be one of :-

  • fast – skips Card Type to number format check
  • all – checks the number against all card types until it finds a match
  • array of card types – like all but limited to a subset of cards.


var $validate = array('field' => 
        array('rule' => array('cc', array('Visa')));

Allows you to compare two numeric values. Takes two parameters:-

  • Operator – one of <, >, <=, >=, == or !=
  • Comparison value to compare against

Allows you to use custom regular expressions. Takes the custom regex as the only parameter.

Validates a string as a date. Can take one parameter;

  • Format – default is ‘ymd’. other options are:
    • dmy
    • mdy
    • ymd
    • dMy – short or long month names
    • Mdy
    • My
    • my

Checks that a number has a decimal point or is scientific notation. Takes the number of decimal places required after the point as the only parameter. If places is null it will check for scientific notation.

Checks for a valid email address. If a parameter of true is passed it will also attempt to verify the host. If the parameter passed is false, or none is passed it behaves the same as VALID_EMAIL.

Checks for IPv4 dot notation. e.g.

Checks a string for a minimum length. Length is passed as the only parameter.

Checks a string for a maximum length. Length is passed as the only parameter.

Checks that a string is numbers, optionally grouped into blocks of 3 separated by a space, comma or period, with an optional block of 2 at the end. Can take a parameter of ‘right’ if you expect the currency symbol at the end, the default is at the start.

Simply calls is_numeric()

Checks for a valid phone format. Takes regex and country as parameters. Currently only supports ‘us’ country option.

Checks for a valid post code format. Takes regex and country as parameters. Currently only supports ‘us’, ‘uk’ and ‘ca’ country options.

Checks for a valid social security number format. Takes regex and country as parameters. Currently only supports ‘us’, ‘dk’ and ‘nl’ country options.

Checks for valid URL format. Supports http(s), ftp(s), file, news and gopher protocols

Calls a userdefined method of the current model passing along any parameters. , the first of which is the method to call. Personally I think this is redundant as you can simply replace userDefined with your method name and it works the same.

There are also some incomplete methods listed below that will be coming soon.

number – checks that a number is within a given range
multiple – will be used for selects and multiple selects
equalTo – direct comparison to another value
file – checks for a file.

All About Validation in CakePHP 1.2

3 07 2007

Validation in v1.1 of CakePHP was quite simple, and many found it lacking in features and flexibility. This is evidenced by the number of alternatives that people have written such as Daniel Hofstetter, Evan Sagge and Adeel Khan‘s ruby-esque approach.

However in CakePHP 1.2 there has been a major rework of the Validation class‘s inner workings, and the way Model::invalidFields() works.

The New $validate

The new $validate can take a number of different constructs now. There are 3 ways to define your validation rules and you can mix and match as needed.

Construct 1: CakePHP 1.1 way
The old CakePHP 1.1 $validate construct will still work

var $validate = array('fieldName' => 'ruleName')

Construct 2: Single Rule per field
You can now define more complex rules using the following construct. (Parameters explained later)

var $validate = array(
  'fieldName' => array(
    'rule' => 'ruleName' // or 'rule' => array('ruleName',  'param1', 'param2' ...)
    'required' => true,'allowEmpty' => false,
    'on' => 'create', // or update
    'message' => 'Your Error Message'

Constrct 3: Multiple Rules per field
Similar to Construct 2, however you can define multiple validation rules for a single field.

var $validate = array(
  'fieldName' => array(
    'rule_index' => array(
      'rule' => 'ruleName' // or 'rule' => array('ruleName',  'param1', 'param2' ...)
      'required' => true,'allowEmpty' => false,
      'on' => 'create', // or update
      'message' => 'Your Error Message'

The new Parameters

The new $validate supports a number of parameters. The only required parameter is ‘rule’.

rule – mixed:
The Rule parameter defines the validation method and takes either a single value or an array. Rule may be (in order of preference) a method of your model, a method of the Validation class or a Regular Expression. If Rule is an array and ‘ruleName’ is a method, all other members of the array will be passed to the method. eg.

var $validate = array('username' => array('rule' => array('between', 6, 20)));

allowEmpty – bool:
This defines the behaviour when an empty value for the field is found. ‘allowEmpty’ => false will cause the validation to fail when the field data is empty. N.B: This rule is only enforced when there is an actual fieldName index in the data array.

Default is false.

required – bool:
‘required’ => true means that an index with fieldName must exist in the data array, i.e. validation will fail if isset($data[‘ModelName’][‘fieldName’]) fails. N.B Required does not care if the value is empty – see allowEmpty above.

Default is false.

on – string (‘create’ or ‘update’):
If on is defined , the validation rule will only be applied on model ‘create’ or ‘update’. If not defined it is applied everytime. This may be useful for situations such as created_by is required on record creation, but on update it must not be defined.

Default is null, i.e. apply rule everytime.

message – string:
Message is the error message that will be stored in validationErrors. If message is not define, it will attempt to use rule_index (in Construct 3) if it is a string, otherwise it will default to ‘This field cannot be left blank’.

There is also another parameter ‘last’ defined in the code but it is not used as yet. Not sure what it’s use will be either.

A Full Example

This is the actual validate variable from my User model. It contains a mixture of the above constructs and techniques.

var $validate = array(
  'username'   => array(
    'alphanumeric' => array(
      'rule' => 'alphanumeric',
      'message' => 'Username may only consist of letter and numbers'), 
    'length' => array(
      'rule' => array('between', 6, 20),
      'message' => 'Username must be between 6 and 20 characters in length')
  'name'     => VALID_NOT_EMPTY,
  'email'   => array(
    'Invalid email format' => VALID_EMAIL, 
  'passwrd'   => array(
    'length' => array(
      'rule' => array('minLength', 6),
      'message' => 'Password must be at least 6 characters in length'),
    'strong' => array(
      'rule' => 'isStrong', 
      'message' => 'Your password is not strong enough')

Disclaimer: My knowledge of the new validation was gained from the Bakery Article Multiple Rules of Validation, CakeBaker’s article Validation with CakePHP 1.2 and mostly from looking at the source code. If I have interpreted something incorrectly, please let me know.

CakePHP Test Suite Shell

24 06 2007

In addition to my changes to the core Test Suite to add support for plugins, I have now created a console shell to run test suites via the command line.

To use the Test Suite Shell simply place testsuite.php in /vendors/shells.

cake testsuite help
this message
cake testsuite run section test_type [case_type] test
– section – app, core or plugin_name
– test_type – case, group or all
– case_type – only with case, one of behaviors, components, controllers, helpers or models
– test – file without (test|group).php

cake testsuite run core all – will run all core tests
cake testsuite run app group models – will exexute /app/tests/groups/models.group.php
cake testsuite run contents case model content – will execute /app/plugins/contents/tests/cases/models/content.test.php

Testing CakePHP Plugins

19 06 2007

With the official Test Suite bundled with CakePHP, it is pretty easy to write unit tests for your models and controllers. The Testing Models with CakePHP Test Suite tutorial on the Bakery is a good introduction to the CakePHP Test Suite.

Now this is great until it comes time to test your plugins. It seems that the official test suite does not like plugins. So I patched my cake install so that I can run plugins test cases and groups that are logically stored in /app/plugins/plugin_name/tests.

Here are the files for those interested. Please leave bugs or issues in the comments for now.

My apologies to those who downloaded 0.1, as it did not contain app/webroot/test.php – instead I had incorrectly included app/webroot/index.php

Plugin tests are exactly the same as those described at Testing Models with CakePHP Test Suite except that the loadModel(‘ModelName’) is left out becomes loadPluginModels(‘plugin’). Here is an example test case for a plugin:


class ContentTest extends Content {
  var $name = 'ContentTest';
  var $useDbConfig = 'test_suite';

class ContentTestCase extends CakeTestCase {
  var $TestObject = null;
  var $fixtures = array( 'content_test' );

  function startTest() {
    $this->TestObject = new ContentTest();

  function endTest() {

  function testSlugBehaviour(){
    $data = ContentTestFixture::$slugTest;
      $data = $this->TestObject->findById($this->TestObject->getInsertID());
      $expected = 'slug-test';
      $this->assertEqual($data['ContentTest']['slug'], $expected);
    } else {
      $this->fail('Could not save the Test Data');

Currently my patch only supports the HtmlManager – web view – and not the TextManager. Also ‘All’ under Test Groups of a plugin will not run the plugin tests, it will run the App Test Cases. I will fix these issues in the next release. The patch supports All under Group Tests and combined with my Test Suite Shell it also supports cli testing

And finally here are some screeshots of Plugin Tests in action.




CakePHP Development on Mac OS X

11 06 2007

I’ve been setting up my Mac OS X development environment lately and I have got the following so far.


For a server I am using the excellent MAMP package. Simple, straight forward and with the added bonus that you can switch between PHP4 and PHP5 at any time by selecting a radio box and restarting the server.


After reading a couple of posts on the CakePHP google groups I have decided to go with Eclipse as my IDE, which comes in a handy all in one package from Zend.

At work I use ZDE on a Win box. I am happy with ZDE – got to love its auto-complete feature – but I wanted to try something new and a little more flexible at home.

After less than an hour with Eclipse I am quite impressed. I have already created an “external tool” for Bake thanks to the short tutorial here, although I had to modify it for 1.2. Now I can bake with a short menu selection, directly in Eclipse rather than typing the whole thing into the terminal.

Another neat feature that I noticed is in the task view it automatically picks out comments with TODO in them and adds them to the list. Very handy for not forgetting what still needs a bit of attention.


There is a nice binary of Subversion avaible from Martin Ott which makes SVN as simple as any package to install. Couple this with Subclipse and code versioning is sorted.

If you need to run a repository locally, the package from Martin Ott is capable of this by running from Terminal:
svnserve -d

Still to Come

I am still looking into a deployment process. I want something that will checkout my current SVN head, run the unit test, run the Selenium test and then FTP them to the remote server if all tests pass. I am looking into ANT and Capistrano, but am still undecided.