Mssql_Table Behavior for CakePHP 1.2.x

I've been using CakePHP 1.2.x for projects at work, where our primary database back-end is Microsoft SQL Server. Maybe I'm just missing something, but it seems to me that SQL Server outputs datetime values in an odd way (by odd, I mean not parsable by strtotime). When pulling datetime values out of SQL Server, CakePHP will render them as PHP strings just as they are returned from the server, in this format:

Jan 10 2008 12:25:07:000PM

Now, strtotime parses incoming values according to GNU Date Input Format, which is incompatible with the output from SQL Server (note the milliseconds). To make life easier when working woth models that describe MSSQL tables with datetime fields, using this behavior can make things a little easier.

To use this behavior, put the code in

    app/model/behaviors/mssql_table.php

and including the following line in your model:

var $actsAs = array('MssqlTable' => array());

... and datetime fields will come through as strings formatted according to your current locale (which is parsable by strtotime -- well, at least here in en_us).

Mssql_Table.php

/** 
 * $Id: mssql_table.php 127 2007-06-04 13:11:09Z jbenner $
 * 
 * This behavior will automatically handle some of SQL Server's oddities. Right
 * now all it does is handle parsing of datetime fields automatically, and
 * converts them to GNU datetime compliant strings.
 * 
 * @package      pbuapps
 * @subpackage   pbuapps.base
 * @author       Joshua Benner
 * @copyright    2007 Philadelphia Biblical University
 * @version      $Revision: 127 $
 * @modifiedby   $LastChangedBy: jbenner $
 * @lastmodified $Date: 2007-06-04 08:11:09 -0500 (Mon, 04 Jun 2007) $
 */
 
/**
 * Behavior that will deal with the oddities of SQL Server models.
 */
class MssqlTableBehavior extends ModelBehavior {
 
	protected $__defaultParsers = array( 'datetime' => array('parser' => 'parse_datetime'));
 
	/**
	 * Initialize behavior
	 *
	 * @param object $model
	 * @param array $config
	 */
	function setup(&$model, $config = array()) {
		$settings = am(array('parsers' => $this->__defaultParsers), $config);
		$this->settings[$model->name] = $settings;
	}
 
	/**
	 * After a find is performed, this function will check if any of the fields
	 * returned are datetime fields and reformat them. This is necessary to
	 * deal with microsoft's odd datetime output in SQL Server.
	 *
	 * @param AppModel  $model
	 * @param array   $results
	 * @param boolean $primary Whether or not this is primary query
	 */
	function afterFind(&$model, $results, $primary) {
		// First: find all the offending fields
		$parseFields = array();
		// Load parsers from settings
		$parsers = $this->settings[$model->name]['parsers'];
		// Iterate through fields in table info and check if their type is in our parser list
		foreach ($model->_tableInfo->value as $field) {
			if (array_key_exists($field['type'], $parsers)) {
				// We found a juicy field to parse, so assign a parser function
				$parseFields[$field['name']] = $parsers[$field['type']];
			}
		}
		// Now we know which fields to parse, let's parse them!
		if (count($parseFields)) {
			// Iterate through results rows
			foreach ($results as $i=>$r) {
				// We don't iterate through models, because they can worry about
				// their own datetime parsing if they must.
				$fields = $r[$model->name];
				// Iterate through parsable fields for each row
				foreach ($parseFields as $field=>$func) {
					// If this row has this field
					if (isset($fields[$field])) {
						// Execute associated parser function
						$results[$i][$model->name][$field] = $this->$func['parser']($fields[$field]);
					}
				}
			}
		}
		return $results;
	}
 
	/**
	 * Parses the output from MSSQL datetime field and returns it in a format 
	 * compliant with GNU datetime standards (ie: strtotime can parse it).
	 * 
	 * @param string $datetime
	 * @return string GNU-compliant date string
	 */
	protected function parse_datetime($datetime) {
		// MSSQL Format: Jan 10 2008 12:25:07:000PM
		return strftime('%c', strtotime(str_replace(':000', ' ', $datetime)));
	}
}

Boris (not verified) on June 16th 2007

I have worked in the past with SQL Server and it really gave me some pain, I was using cakephp 1.1.x.x but I couldn't do pagination or other things, I don't know If you can have pagination with SQL Server and cake 1.2.x.x I haven't tried, Please post more about your expiriences with cake and SQL Server

Josh on June 30th 2007

Sorry for taking a while to respond. Yes, my primary development with cake uses SQL Server as back end. I'll write some more articles about my experience, including an updated MssqlTable Behavior.

Darian (not verified) on October 18th 2007

Cake 1.2 and SQL Server gave me the blues big time a few weeks back. I was working on a project that needed Acl.

Acl, however, totally doesn't work with SQL Server, just a heads up to save you some heartache. I submitted some bug reports to Trac detailing that issues that I had (search for "dapatrick").

Best of luck in your Cake & SQL Server forays. I will watch this space for future posts on the topic.

Luis (not verified) on September 30th 2008

Hi, I test this behavior width CakePHP 1.2.0.7296 RC2 and don't work,

I change:

foreach ($model->_tableInfo->value as $field) {
if (array_key_exists($field['type'], $parsers)) {
// We found a juicy field to parse, so assign a parser function
$parseFields[$field['name']] = $parsers[$field['type']];
}
}

Width:

foreach ($model->_schema as $name=>$field) {
if (array_key_exists($field['type'], $parsers)) {
// We found a juicy field to parse, so assign a parser function
$parseFields[$name] = $parsers[$field['type']];
}
}

and seems to work.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <geshi>. Beside the tag style "<foo>" it is also possible to use "[foo]". PHP source code can also be enclosed in <?php ... ?> or <% ... %>.
  • Make a bullet list by starting each line with a '-'. Add more for sublists.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.