Using generateFields() + Fix fields of the type 'date'
Posted by Felix Geisendörfer, on Jan 12, 2006 - in PHP & CakePHP » Controllers, Components & Shells
Deprecated post
The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.
Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.
Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).
If you didn't use the generateFields() function before you've missed out on some good Cake. But there is a little thing you definitly should know when using it. One thing I've discovered is that you can easily create interfaces in scaffolding-speed with it (scaffolding actually makes use of this function as well) but with the advantage of having a lot more control over the way the data is displayed, proccessed and saved.
But here comes the problem: If you use fields of the type date in your database generateFields will generate 3 Selects called date_month, date_day and date_year for them, but once the data get's back in and you want to save it you are responsible for merging it to one 'date' field.
But don't worry there already is a function that does that for you, but it's only inside the Scaffolding Component which means you have to copy and modify it a little bit to make it work inside of your Controller.
Let's look at a complete example on how to do that:
1. The 'add' function of your controller:
Inside of your add() function you have the following code. (If you wonder why there is a @$this->params['data'] inside of the generateFields() call: It's because this gives you the possibilty of providing links to adding items with information already filled in)
-
function add()
-
{
-
$fieldNames = $this->generateFieldNames(@$this->params['data']);
-
$this->set('fieldNames', $fieldNames);
-
return $this->render('edit');
-
}
2. The view 'edit.thtml'
You'll have a view called edit.thtml which will be used for both, creating new data and editing existing data:
-
if($type == 'Edit')
-
{
-
}
-
else
-
{
-
}
-
?>
-
</form>
The Result will be a scaffolding like 'magical' user interface, that will (depending on your table fields) look like this:

3. Save the Posted Data
The next thing is saving the data if a user clicks on the Save button which will lead him to /create of your controller: The easiest way is by doing it like this.
-
function create()
-
{
-
{
-
return $this->add();
-
}
-
-
$this->_cleanUpFields();
-
-
if ($this->Item->save($this->params['data']))
-
{
-
$this->set('message', 'Your Item has been created. The Id is: ' . $this->Item->getLastInsertID());
-
}
-
else
-
{
-
$this->set('error', 'Something went wrong and your item could not be created');
-
}
-
-
return $this->add();
-
}
4. Merge datefields with _cleanUpFields()
Important: As it turns out this might not be the most "best practice" solution to working with date fields since this stuff should be better inside of the model. If you care to do things the right way definitly have a look at CakerBaker's Blog post that deals with that topic and forget about the this step here ; ).
The function _cleanUpFields() is not part of your controller by default but only available in the scaffolding class. But since it comes really handy for merging the day/month/year select boxes of date fields into one variable I've modified it to work from within a regular controller. All you have to do is to Add this to the controller you want to use generateFields() with, or another controller that your controller extends:
-
function _cleanUpFields()
-
{
-
$modelKey = Inflector::humanize($this->modelKey);
-
-
foreach( $this->{$modelKey}->_tableInfo as $table )
-
{
-
foreach ($table as $field)
-
{
-
{
-
$newDate = $this->params['data'][$modelKey][$field['name'].'_year'].'-';
-
$newDate .= $this->params['data'][$modelKey][$field['name'].'_month'].'-';
-
$newDate .= $this->params['data'][$modelKey][$field['name'].'_day'].' ';
-
$this->params['data'][$modelKey][$field['name']] = $newDate;
-
}
-
else if( 'datetime' == $field['type'] && isset($this->params['data'][$modelKey][$field['name'].'_year'] ) )
-
{
-
$hour = $this->params['data'][$modelKey][$field['name'].'_hour'];
-
if( $hour != 12 && 'pm' == $this->params['data'][$modelKey][$field['name'].'_meridian'] )
-
{
-
$hour = $hour + 12;
-
}
-
$newDate = $this->params['data'][$modelKey][$field['name'].'_year'].'-';
-
$newDate .= $this->params['data'][$modelKey][$field['name'].'_month'].'-';
-
$newDate .= $this->params['data'][$modelKey][$field['name'].'_day'].' ';
-
$newDate .= $hour.':'.$this->params['data'][$modelKey][$field['name'].'_min'].':00';
-
$this->params['data'][$modelKey][$field['name']] = $newDate;
-
}
-
else if( 'tinyint(1)' == $field['type'] )
-
{
-
"on" == $this->params['data'][$modelKey][$field['name']] )
-
{
-
$this->params['data'][$modelKey][$field['name']] = true;
-
}
-
else
-
{
-
$this->params['data'][$modelKey][$field['name']] = false;
-
}
-
}
-
}
-
}
-
}
I just started working with generateFields() so there might be some things to improve here and there, but all in all this is the stuff that will really speed up development and using it can be a ton of fun ; ).
A little tip at the end: If you have fields in your database that you want to provide a different interface to then the one generated by generateFields() just do something like this:
-
$fieldNames = $this->generateFieldNames();
This way you can use your own Html for certain fields in the database!
--Felix