cakephp
Protect Our Coral Sea
Designed to raise awareness about the dangers that Australia’s coral sea is facing. The site’s design is visually stunning and I faced real problems getting the transparent PNG’s to work correctly in IE6. After discussing it with the client, they agreed to degrade gracefully for IE6 and have a less visually stunning design and urged the visitor to upgrade their browser.
The site runs off the same Content Management System as Without Surgery, Skills Connect. The CMS allows the updating of videos, images, menus and more. They can even update the location of the coral see on the Google map (even though I don’t think it’s going anywhere sometime soon). The site also utilises caching to provide maximum performance when under heavy load, especially when the television commercial comes in late September.
In addition, the site is also integrated with Campaign Monitor.
No domain? No problems! Fallback translations in CakePHP
A common methodology in CakePHP is that if something doesn’t exist somewhere, it will look in the next logical spot until it finds it. This is evident with themed views, controllers, models, basically everything in the framework. That’s why I was a little bit suprised dismorning when I was looking into translations within a domain. If the phrase didn’t exist in the domain then it would simply return the original string, without looking inside the default domain.
So I came up with a function that would first look inside the custom domain and if nothing was found then it would naturally work inside the default domain. The function is named __dd(), which is short for default domain.
/** * Allows you to override the current domain for a single message lookup. * If the msg doesn't exist in the current domain, it will use the default * domain. * * @param string $domain Domain * @param string $msg String to translate * @param string $return true to return, false to echo * @return translated string if $return is false string will be echoed */ function __dd($domain, $msg, $return = false) { $d = __d($domain, $msg, true); if ( $d == $msg ) { return __($msg, $return); } if ( $return ) { return $d; } else { echo $d; } }
I’m not sure why the CakePHP gods haven’t done it this way, I’m pretty sure there would be a reason though. The idea came to me with the recent feature addition of domains to my settings plugin (documentation).
CakePHP custom error class doesn’t work when providing translations
So today I was trying to make a form that was friendly between CakePHP and UniForm. Things were going really well, I created a standard options array which converted the markup into UniForm friendly markup, it all looked good until I went to submit. Cake was somehow forgetting the error class I specified. Let’s get to some examples…
The Model Validation Rules
<?php class Product extends AppModel { var $name = 'Product'; var $validate = array( 'title' => array( 'notEmpty' => array( 'rule' => 'notEmpty' ), ) ); } ?>
The View Template
<div class="products form"> <?php echo $form->create('Product', array('type' => 'file'));?> <fieldset> <legend><?php __('Add Product');?></legend> <?php $options = array( 'error' => array( 'class' => 'errorField', 'email' => 'Please enter a product title' ) ); echo $form->input('title', $options); echo $this->element('attachments', array('plugin' => 'media')) ?> </fieldset> <?php echo $form->end('Submit');?> </div> <div class="actions"> <ul> <li><?php echo $html->link(__('List Products', true), array('action' => 'index'));?></li> </ul> </div>
Which, when submitting the form with an empty product title would you give the error message of “Please enter a product title” inside a div with the class “errorField”, however Cake forgets the custom error class and gives the “error-message” class.
What Happened?
I got this code…
<div class="input text error">
<label for="ProductTitle">Title</label>
<input type="text" class="form-error" id="ProductTitle" value="" maxlength="255" name="data[Product][title]"/>
<div class="error-message">Please enter a product title</div>
</div>What was expected?
This…
<div class="input text error">
<label for="ProductTitle">Title</label>
<input type="text" class="form-error" id="ProductTitle" value="" maxlength="255" name="data[Product][title]"/>
<div class="errorField">Please enter a product title</div>
</div>The Fix
After looking through the core code, I traced the problem down into the error function of the FormHelper. The input() function only passes the $field name and the $text variable as the options submitted in the original “error” key to the options passed to the input() function.
In the error function, if the $text array contains the key of the error type, then it disregards the rest of the $text array, forgetting the custom error class. What we need to do is set the $options variable to $text if it is in array, as well as pull the custom message for the error type, kapeech? OK, I’ll just give you the code…
Before
411 412 413 414 415 416 | if (is_array($text) && isset($text[$error])) { $text = $text[$error]; } elseif (is_array($text)) { $options = array_merge($options, $text); $text = null; } |
After
411 412 413 414 | if (is_array($text)) { $options = array_merge($options, $text); $text = isset($text[$error]) ? $text[$error] : null; } |
I never like touching core code so I’m hoking the cake devs will be able to get on this for the next release, and it looks like I just missed the next release, as CakePHP 1.2.5 just popped up on my reader.
I have submitted a ticket at http://code.cakephp.org/tickets/view/76
Ever wondered where the **** that query came from in CakePHP?
I’ve always been frustrated looking at the masses of queries generated by my CakePHP applications and really wondering where they originated from. It would be extremely useful when performing debugging. Sure enough I started looking into cakephp datasources and found that I could implement a solution without even touching the core!
Something like…
I’ve released the datasource to make this happen as part of my Util plugin for CakePHP. To get started please see the Wiki page.
Util is just a plugin full of unrelated libraries for CakePHP, most of the code there is from other people.
Currently only for MySQL but you only have to change one line for different databases.
CakePHP Layouts – Leave your default as default
For the past few months I’ve been following a convention of leaving the default.ctp as the default.ctp and putting my main layout in app.ctp, the only reason being is that when you get those missing controller, missing view, missing method errors it looks ugly in any custom default layout.
You can get your application to use the app.ctp layout by specifying
var $layout = 'app';
in your AppController.php. The only problem with this is that cake will still use this layout when an error occurs, to overcome this we create the app_error.php file and override _outputMessage() method.
<?php class AppError extends ErrorHandler { /** * Output message * * @access protected */ function _outputMessage($template) { $this->controller->layout = 'default'; return parent::_outputMessage($template); } } ?>
The above code reverts the layout back to the default.ctp layout whenever an error occurs so you can see those nasty but nice CakePHP errors.
Tip: Debug on a live site only for you (yes even with a shared IP)
There was a bug on one of our live sites which required some level of debugging. Unfortunately with my CakePHP app turning on debugging meant a whole lot of nastiness that would appear for users of the website. I needed to see the debug information on the live site without affecting any other users (including my bosses in the same office, which meant I couldn’t just turn on debugging for our office IP address).
Here’s what I did:
- Download User Agent Switcher
- Setup a new User Agent and copy “Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 FirePHP/0.3 Debugger” in there. It’s important to keep the firefox related information in there as this allows hacks and stuff to continue knowing that it’s Firefox making the request
- Setup a condition in your code that checks if “Debugger” is present in the user agent string and turns on debugging if so.
My condition code looks this:
if ( strpos($_SERVER['HTTP_USER_AGENT'], 'Debugger') !== false ) { $debug = 2; }
Enjoy full debug freedom on a production site!
Our Tribute
Fresh out of the think tank of Novanate, we realised there was no way to remember loved ones in this new digital age. We meeted several times and specced out a website that would be easy to use and also respectful. The website is acting an online wall where users can remember loved ones from anywhere in the world.
BP North Manly
As you might have noticed, the relationship with Little Miss Nobody gets things done. I was sent the designs and I implemented the site into a working site within 2 afternoons.
In Concerts
What In Concerts needed was essentially a mini Ticketek. The ability to create events, add session times, set the number of tickets available and accept credit card details securely online. A completely custom web application was developed to meet their exact needs.
When CakePHP save doesn’t work – a possible solution
After some frustrating experiences with Cake’s save() and saveAll() functions. They would simply not save the data! I thought the whole thing was messed up and I actually wrote a massive blog post about how to fix it last night. However in my editing and checking dismorning I found the following snippet of code in model.php’s method set.
731 732 733 734 735 736 737 738 739 740 741 | if (is_array($one)) { $data = $one; if (empty($one[$this->alias])) { $keys = array_keys($one); if (in_array($keys[0], array_keys($this->_schema))) { $data = array($this->alias => $one); } } } else { $data = array($this->alias => array($one => $two)); } |
I was trying to save some data which had some fields that wasn’t going to be saved into the database, these were things like credit card numbers which I would process in beforeSave etc. Since the code above will disable your save attempts if the first key in your data array is not a field in the model schema.
Combine your JS & CSS files for faster loading..
With the relatively recent publication of YSlow, it brought to my attention that while seperating your CSS and JS files into seperate files for a more structured application – it can greatly reduce the load time for your users. This solution aims to solve that by keeping your files seperate, and implementing the advantages of cake so ultimately your users will only have to download one aggregated JS and CSS file.
Qcodo vs CakePHP
At work our main PHP framework is Qcodo. However I’m in love with CakePHP. So I set out on creating a presentation which is a comparision of the two frameworks. In the end I concluded that it was like comparing apples and oranges. Qcodo seems like a port of ASP.NET, relies havily on Code Generation whereas CakePHP seems like a port of Ruby on Rails and relies on Metaprogramming.





