CakePHP
Cakephp Model-less Form Helper
Below is a simple helper I've creating to help with generating forms, using field names and options stored in a database. It's actually a modified version of the helper I created for my Cakeforms plugin- an easy to use form plugin for Cakephp/Croogo that basically allows people to create forms for their Croogo site without having to write any code. I'll post about it when I get the time to clean it up and update the git repo.
This helper assumes you are passing an array of fields with the following options:
$formField['FormField'] = array(
array(
'name' => 'field_name', //required
'label' => 'field_label',
'type' => 'type', //required. Options: fieldset, text, textbox, disabled, textonly, select, checkbox, radio,
'default' => 'default_value',
'options' => array('option1' => 'value', //options for checkbox, select and radio
'option2' => 'value')
)
I actually store all these values in a database table- in my model's afterFind() function I convert options from a comma separated list to an associative array.
Below is a basic version of the helper. Put this in your app/views/helpers/ folder and call it cakeform.php. You can download the file here: cakeform.php
class CakeformHelper extends AppHelper {
public $helpers = array('Html', 'Form', 'Javascript');
/**
* used in generating form fieldsets
*
* @access public
*/
public $openFieldset = false;
/**
* Generates form HTML
*
* @param array $formData
* @param mixed $action
*
* @return string Form Html
* @access public
*/
function insert($formFields, $action){
$out .= $this->Form->create('Form', array('url' => $action));
if(isset($formFields['FormField'])){
foreach($formFields['FormField'] as $field){
$out .= $this->field($field);
}
}
if($this->openFieldset == true){
$out .= "</fieldset>";
}
$out .= $this->Form->end('Submit');
return $this->output($out);
}
/**
* Generates appropriate html per field
*
* @param array $field Field to process
* @parram array $custom_options Custom $form->input options for field
*
* @return string field html
* @access public
*/
function field($field, $custom_options = array()){
$options = array();
$out = '';
if(!empty($field['type'])){
switch($field['type']){
case 'fieldset':
if($this->openFieldset == true){
$out .= "</fieldset>";
}
$out .= "<fieldset>";
$this->openFieldset = true;
if(!empty($field['name'])){
$out .= "<legend>".Inflector::humanize($field['name'])."</legend>";
$out .= $this->Form->hidden('fs_' . $field['name'], array('value' => $field['name']));
}
break;
case 'textonly':
$out = $this->Html->para('textonly', $field['label']);
break;
default:
$options['type'] = $field['type'];
if(in_array($field['type'], array('select', 'checkbox', 'radio'))){
if($field['type'] == 'checkbox'){
if(count($field['options']) > 1){
$options['type'] = 'select';
$options['multiple'] = 'checkbox';
$options['options'] = $field['options'];
} else {
$options['value'] = $field['name'];
}
} else {
$options['options'] = $field['options'];
$options['empty'] = 'select one';
}
}
if(!empty($field['depends_on']) && !empty($field['depends_value'])){
$options['class'] = 'dependent';
$options['dependsOn'] = $field['depends_on'];
$options['dependsValue'] = $field['depends_value'];
}
if(!empty($field['label'])){
$options['label'] = $field['label'];
if($field['type'] == 'radio'){
$options['legend'] = $field['label'];
}
}
if($field['type'] == 'radio' && count($field['options']) == 2 ){
$options['div'] = 'input radio bool';
$options['legend'] = false;
$options['before'] = $this->Html->div('radio-label', $field['label']);
}
if(!empty($field['default']) && empty($this->data['Form'][$field['name']])){
$options['value'] = $field['default'];
}
$options = Set::merge($custom_options, $options);
$out .= $this->Form->input($field['name'], $options);
break;
}
}
return $out;
}
}
Cached Twitter Profile Widgets in Cakephp
Configuring the Cache
I use the following cache config in my core.php which will cache the tweets for 15 minutes:
Cache::config('social', array(
'engine' => 'File',
'duration'=> 60*15, //15 minutes
));
Retrieving the Tweets
The following pulls the last 5 twitter posts for the user traffick911. It first checks if there is a cached version, and if not it will request the latest tweets from twitter.com. I kept all this in my twitter element, which does break MVC, but it could easily be moved to app_controller.php.
$twitter_response = Cache::read('tweets', 'social');
if(empty($twitter_response)){
App::import('Core', 'HttpSocket');
$HttpSocket = new HttpSocket();
$twitter_response = $HttpSocket->get('http://twitter.com/statuses/user_timeline/traffick911.xml', 'count=5');
if(strlen($twitter_response)>0){
Cache::write('tweets', $twitter_response, 'social');
}
}
Displaying the Tweets
To actually display the tweets I basically copied the HTML and CSS produced by the twitter widget and converted it into an element:
HTML:
<div class="twtr-doc" style="width: 300px;">
<div class="twtr-hd"><a target="_blank" href="http://twitter.com/traffick911" class="twtr-profile-img-anchor">
<img alt="profile" class="twtr-profile-img" src="http://a3.twimg.com/profile_images/544416859/traffick_two_FLAT_edited_normal.jpg" /></a>
<h3>Traffick911</h3>
<h4><a target="_blank" href="http://twitter.com/Traffick911">Traffick911</a></h4>
</div>
<div class="twtr-bd">
<div class="twtr-timeline" style="height: auto;">
<div class="twtr-tweets">
<?php if(!empty($twitter_response)):
$tweets=new SimpleXMLElement($twitter_response);?>
<?php foreach($tweets as $tweet):?>
<div class="twtr-tweet">
<div class="twtr-tweet-wrap">
<div class="twtr-avatar">
<div class="twtr-img">
<a target="_blank" href="http://twitter.com/<?php echo $tweet->user->name;?>">
<img alt="Traffick911 profile" src="<?php echo $tweet->user->profile_image_url;?>" />
</a>
</div>
</div>
<div class="twtr-tweet-text">
<p>
<a target="_blank" href="http://twitter.com/<?php echo $tweet->user->name;?>" class="twtr-user"><?php echo $tweet->user->screen_name;?></a>
<?php
$message=preg_replace("/http:\/\/(.*?)\/[^ ]*/",'\\0',$tweet->text);
$message=ereg_replace("[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]","<a href=\"\\0\" rel=\"nofollow\">\\0</a>",$message);
echo $message;?>
<em> <a target="_blank" class="twtr-timestamp" href="http://twitter.com/<?php echo $tweet->user->name?>/status/<?php echo $tweet->id?>"><?php echo $this->Time->timeAgoInWords(strtotime($tweet->created_at) + $tweet->utc_offset);?></a>
<a target="_blank" class="twtr-reply" href="http://twitter.com/?status=@<?php echo $tweet->user->name?>%20&in_reply_to_status_id=<?php echo $tweet->id?>&in_reply_to=<?php echo $tweet->user->name?>">reply</a> </em>
</p>
</div>
</div>
</div>
<?php endforeach;?>
<?php else:?>
<div class="twtr-tweet">
<div class="twtr-tweet-wrap">
<div class="twtr-tweet-text">
<p>
Tweets could not be loaded at this time.
</p>
</div>
</div>
</div>
<?php endif;?>
</div>
</div>
</div>
<div class="twtr-ft">
<div><a target="_blank" href="http://twitter.com"><img alt="" src="http://widgets.twimg.com/i/widget-logo.png" /></a>
<span><a target="_blank" class="twtr-join-conv" style="color:#ffffff" href="http://twitter.com/traffick911">Join the conversation</a></span>
</div>
</div>
</div>
CSS:
The easiest way to generate the css is to go to http://twitter.com/about/resources/widgets/widget_profile and actually design your widget- then just copy and paste it into your stylesheet.
Timezones in Cakephp 1.3 and php 5.3.
I recently updated to php version 5.3.5, and immeiately got the following error in my Cakephp 1.3.x apps:
Warning (2): strtotime() [http://php.net/function.strtotime]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Chicago' for 'CST/-6.0/no DST' instead [CORE/cake/libs/cache.php, line 570]
Code | Context
$settings = array(
"engine" => "File",
"path" => "/private/var/www/skyrocketstudio.com/app/tmp/cache/persistent/",
"prefix" => "cake_core_",
"lock" => false,
"serialize" => true,
"isWindows" => false,
"duration" => "+10 seconds",
"probability" => 100
)
strtotime - [internal], line ??
CacheEngine::init() - CORE/cake/libs/cache.php, line 570
FileEngine::init() - CORE/cake/libs/cache/file.php, line 81
Cache::_buildEngine() - CORE/cake/libs/cache.php, line 151
Cache::config() - CORE/cake/libs/cache.php, line 126
Configure::__loadBootstrap() - CORE/cake/libs/configure.php, line 420
Configure::getInstance() - CORE/cake/libs/configure.php, line 52
include - CORE/cake/bootstrap.php, line 38
require - APP/webroot/index.php, line 76
[main] - CORE/index.php, line 55
Notice: Trying to get property of non-object in /private/var/www/skyrocketstudio.com/cake/libs/cache/file.php on line 248 Fatal error: Call to a member function cd() on a non-object in /private/var/www/skyrocketstudio.com/cake/libs/cache/file.php on line 248
Turns out it's an easy fix- uncomment date_default_timezone_set('UTC');(around line 242) in your core.php file.
For convenience' sake, here's a list of US timezones, taken from a comment that I always have to refer back to on php.net [http://www.php.net/manual/en/timezones.america.php#93028]
| Common Abbr. | Value for date_default_timezone_set |
|---|---|
| AST | America/Puerto_Rico |
| EDT | America/New_York |
| CDT | America/Chicago |
| MDT | America/Boise |
| MST | America/Phoenix |
| PDT | America/Los_Angeles |
| AKDT | America/Juneau |
| HST | Pacific/Honolulu |
| ChST | Pacific/Guam |
| SST | Pacific/Samoa |
| WAKT | Pacific/Wake |