CakePHP Query Method Does Support Bind Parameters

Just came across a post from a few months ago where I stated that CakePhp doesn’t support bind parameters. I have learned since then that this is not true. Happily, it does support bind parameters. An example I have used successfully:

    function query_bottom_count($bottom_value, $start_uts, $end_uts)
    {
        $sql = <<<XSQL
SELECT
    REPLACE( SUBSTRING_INDEX( SUBSTRING_INDEX( last_result_url,
        '://', -1 ) , '/', 1 ) , 'www.', '' ) AS domain,
    COUNT( REPLACE( SUBSTRING_INDEX( SUBSTRING_INDEX( last_result_url, '://', -1 ) ,
        '/', 1 ) , 'www.', '' ) ) AS hits
FROM queries as Query
WHERE insert_uts >= ?
AND insert_uts < ?
GROUP BY domain HAVING hits = ?;
XSQL;

        $ParamList = array($start_uts, $end_uts, $bottom_value);
        $Data = $this->query($sql, $ParamList);
        if ( !$Data ) return 0;
        return count($Data);
    }

Just setting the record straight.

Advance Model Testing in CakePhp

One of the most challenging issues I’ve found in developing with CakePhp is unit testing. Testing models, with its dependence on fixtures, is especially touchy. The documentation, while constantly improving, still seems at crucial points incomplete or inconsistent. In this post, I’d like to draw attention to a few pitfalls that I burned a few brain cycles in overcoming and offer some tips for unit testing models with fixtures.

Cake Core Bugs

There are a couple documented bugs that still outstanding as of release 1.2.4.8284. If you are doing anything more than basic testing, one of these could bite you eventually:

https://trac.cakephp.org/ticket/6205
https://trac.cakephp.org/ticket/6468

Here is a patch file that fixes them:

# Fix issues with CakePhp model unit tests
# Tom at klenwell@gmail.com
# CakePhp Version: 1.2.4.8284

diff -r ead5d3b62da7 -r df04a99fec1b cake/libs/model/datasources/dbo_source.php
--- a/cake/libs/model/datasources/dbo_source.php	Mon Aug 10 21:16:09 2009 -0700
+++ b/cake/libs/model/datasources/dbo_source.php	Mon Sep 14 21:08:12 2009 -0700
@@ -2355,6 +2355,15 @@ class DboSource extends DataSource {
 			$column['default'] = null;
 		}

+                // solves fixture problem
+                // see https://trac.cakephp.org/ticket/6205
+                if (($column['type'] == 'datetime' || $column['type'] == 'timestamp' ) &amp;amp;amp;amp;&amp;amp;amp;amp; isset($column['default']) &amp;amp;amp;amp;&amp;amp;amp;amp; $column['default'] === '') {
+                    $column['default'] = null;
+                }
+                if ( $column['type'] == 'timestamp' &amp;amp;amp;amp;&amp;amp;amp;amp; $column['default'] === 'CURRENT_TIMESTAMP' )
+                    #pr($column);
+                    $column['default'] = null;
+
 		if (isset($column['key']) &amp;amp;amp;amp;&amp;amp;amp;amp; $column['key'] == 'primary' &amp;amp;amp;amp;&amp;amp;amp;amp; $type == 'integer') {
 			$out .= ' ' . $this-&amp;amp;gt;columns['primary_key']['name'];
 		} elseif (isset($column['key']) &amp;amp;amp;amp;&amp;amp;amp;amp; $column['key'] == 'primary') {
@@ -2455,4 +2464,4 @@ class DboSource extends DataSource {
 		return 'string';
 	}
 }
-?&amp;amp;gt;
\ No newline at end of file
+?&amp;amp;gt;

diff -r ead5d3b62da7 -r df04a99fec1b cake/tests/lib/cake_test_fixture.php
--- a/cake/tests/lib/cake_test_fixture.php	Mon Aug 10 21:16:09 2009 -0700
+++ b/cake/tests/lib/cake_test_fixture.php	Mon Sep 14 21:08:12 2009 -0700
@@ -114,7 +114,12 @@ class CakeTestFixture extends Object {
 			}
 		}

-		if (!isset($this-&amp;amp;gt;table)) {
+                // solves HABTM problem
+                // see https://trac.cakephp.org/ticket/6468
+                if (isset($model-&amp;amp;gt;table)) {
+                        $this-&amp;amp;gt;table = $model-&amp;amp;gt;table;
+                }
+                elseif (!isset($this-&amp;amp;gt;table)) {
 			$this-&amp;amp;gt;table = Inflector::underscore(Inflector::pluralize($this-&amp;amp;gt;name));
 		}

@@ -190,4 +195,4 @@ class CakeTestFixture extends Object {
 		return $return;
 	}
 }
-?&amp;amp;gt;
\ No newline at end of file
+?&amp;amp;gt;

Fixtures

The design and usage of fixtures still seems fickle. For instance, the CakePhp docs and packaged test examples promote the explicit declaration of fields in fixtures. I find this tedious. Happily, it is also unnecessary, thanks to the import property.

To avoid this nuisance, use the import ‘model’ or ‘table’ setting to automatically load the table schema from the existing database. See the example here:

simple_record_fixture.php

A couple other tips for using fixtures:

1. Import all fixtures associated with a model in the unit test for that model
2. If unit testing a plugin, the value in the fixtures property takes this format: plugin.$plugin_name.$model_name
3. Don’t forget to set up an empty database and include a test_suite setting in your database configuration file.

See these links for additional insight:
Cakewell Database Config File
Model Test with Fixtures
CakePhp cake_test_fixture.php

HABTM Relationships

To test models that have HABTM relationships with other models, it is necessary to create fixtures for both models having the HABTM relationship and a fixture to build the join table. See these files from the Cakewell project for examples:

Authwell User-Role HABTM Fixture
Authwell Role-Privilege HABTM Fixture

The Cakewell Authwell plugin include a good example of a complex model unit test that is successfully configured. It includes tests within the plugin directory that autoload a clean test database and successfully test models with HABTM associations. The source can be found here:

Authwell Plugin Test Directory

Wordpress Upgrade

After reading this alarming post on slashdot, and coming across similar reports on reddit and elsewhere, I decided it was time to bite the bullet and upgrade. I did it the long, manual way. Not as tough as helping your sister move. But it still took about an hour to complete.

This post is mainly just to insure that everything is working correctly. More sporadic posting to follow.

Project Cakewell

Project Cakewell is a CakePhp prototype application. Its main purpose is to document and demonstrate useful concepts and features of a web application built with the CakePhp framework. These include things like unit testing a component, creating a working fixture , and configuring your application to automatically detect the server environment and set the debug level accordingly.

The code is open source and available at the Cakewell Google Code site at:

http://code.google.com/p/cakewell/

The live demo can be found at:

http://cakewell.klenwell.com/

I’ll add updates here as I progress.

Greqo 4 Released

Greqo is a PHP project I started a couple years back for Google’s services. It was an extension of a Blogger API I had written in PHP. I extended it to include Gmail and Google Analytics. I took some time this year to clean it up and recently released Greqo 4. It’s not really the 4th version. More like the 2nd. The 4 signifies full compatability with PHP 4.

For more information on usage, I recommend the unit and acceptance tests that come packaged with the source code.

There are probably better PHP libraries for Google’s Data APIs (e.g. the Zend Framework.) PHPMailer, upon which my Gmail library was built, now supports Gmail natively. Google Analytics now has an export API. And PHP 4, of course, has reached the end of its life.

But Greqo 4 runs on PHP 5. And if you need a PHP 4 implementation of these Google APIs, well then here you are:

Download: Greqo 4 Release for Google Mail, Blogger, and Analytics

Going forward, the Greqo library will abandon complete PHP 4 compatibility and focus on PHP 5 and, eventually, PHP 6.