Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to process complex datatypes in CakePHP?

My Goal: Replace the Default Cake Datepicker

I hate the default CakePHP FormHelper date-picker select elements and I'd like to use jQuery UI Datepicker widget instead. In order to degrade gracefully, I want to have a date field (enabled with the widget) and a time-picker select box constrained to 15-minute increments.

In case I explained that poorly, here is what it looks like:

date-picker sample

My Ideal Solution

To minimize repetition, I want to put the HTML in a layout Element and process it using a Behavior function. This way I could do something like the following:

view.ctp

echo $this->element( 'datepicker', array( 'data' => $data ) );

model.php

$actsAs = array( 'Datepicker' );

function beforeSave( $options ){
    $this->parseDatepickers();  //behavior function would alter $this->data
    return true;
}

The Problem

Unfortunately, by the time it gets to the beforeSave (or beforeValidate) callback, the datepicker & timepicker fields have been destroyed by the model's deconstruct function. deconstruct seems to be looking for dates & times to be reported the way FormHelper creates them.

In short, it's looking for:

[date_field] => Array
(
    [year] => 2011
    [month] => 11
    [day] => 11
    [hour] => 8
    [min] => 00
    [meridian] => pm
)

but instead it's finding:

[date_field] => Array
(
    [datepicker] => 11/11/2011
    [timepicker] => 8:00 pm
)

And because it doesn't find the structure it expects, I end up with this:

[date_field] =>

I know I can have jQuery update hidden inputs with the appropriately-named fields, but this wouldn't degrade well.

Current Workaround

What I'm doing, for the moment, is washing the data through my behavior function prior to saving -- but this doesn't feel like the right way to do it:

$this->request->data = $this->Event->fixDates( $this->data );
$this->Event->save( $this->data );

So...............

What is the best way to do this? Putting it in beforeSave or beforeValidate seems like "the Cake way", but deconstruct kills me. Do I need to extend AppModel and override deconstruct? That seems ugly too.

like image 741
Farray Avatar asked Nov 05 '11 04:11

Farray


1 Answers

I normally make my date fields as text fields in the view to override the default Form Helper output and then use jQuery date picker (or whatever your alternative picker would be) to set the date:

echo $this->Form->input('date', array('type' => 'text', 'class' => 'datepicker'));

This would output a typical tag rather than all the drop downs.

Then, in my model's beforeSave function, I change the format to MySQL formatted date:

$this->data['Model']['date'] = date('Y-m-d G:i:s', strtotime($this->data['Model']['date']));

(remember to return true in beforeSave)

This works with a proper datetime datatype in the database and it sounds like what you are trying to do.

like image 107
Scott Harwell Avatar answered Sep 22 '22 04:09

Scott Harwell