Some interesting findings from web-dev land…
If you get this error:
1 | Warning: Warning (2): preg_match() [<a href='function.preg-match'>function.preg-match</a>]: Delimiter must not be alphanumeric or backslash in [/var/www/vhosts/h2oservices.com/httpdocs/cake/libs/model/model.php, line 2611] |
When trying to use a custom validation rule, make sure the method visibility is set to public.
So this should work:
1 2 3 | public function myCustomValidateRule(){ // Custom validation code } |
It seems protected visibility works on some versions of PHP (5.2.11 tested and working) and not others.
It can’t be done using the normal Ternary operator but you can emulate it with:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // So instead of: $str = <<<HTML {$a ? 1 : 2} HTML; // You can do: $values = array('1', '2'); $str = <<<HTML {$values[$a]} HTML; |
Don’t forget kids to check the size of the tmp partition if you are having issues uploading large files with PHP.
After setting all the usual configuration directives (upload_max_filesize, post_max_size etc) uploads were still failing for me returning error code 7.
After poking around on the Debian VPS for a while I realised the /tmp partition was 128mb!!
Luckily you can set the path for file uploads using the following directive:
1 | upload_tmp_dir = /path/to/somewhere/with/some/disk/space |
If you have fields that don’t exist in your table schema and you want to submit those to an action that is protected by the Security component. You can tell the component to ignore (and therefore not black hole/404 your request) the field(s) using its $disabledFields attribute.
In this example I’m ignoring the security_code (captcha) field, which obviously I don’t store anywhere in the database table:
1 2 3 | $this->Security->disabledFields = array( 'Enquiry.security_code' ); |
The proper way to do this is with a static call to Debugger:
1 | Debugger::log($output); |
For my own records. Batch file rename using shell:
1 2 3 | Rename all jpg files that contain the string 19_ and replace it with 28_ for file in *.jpg ; do mv $file `echo $file | sed 's/19_/28_/g'` ; done |
Just managed to count another table using a model virtual field, obviously preserving the association with the sub query conditions.
So in my ProductTemplate model I have this:
1 2 3 | var $virtualFields = array( 'page_count' => 'SELECT COUNT(*) FROM pages as Page WHERE Page.product_template_id = ProductTemplate.id' ); |
The nice thing about this is you can use the field with the CakePHP Model::find ordering and with the pagination component.
You can save has and belongs to many models in CakePHP (v1.3.4) whilst adding additional data to the join table, in a single operation.
In this example I’m saving Users that HABTM Videos. The users_videos join table has an order column.
Firstly add the ‘with’ parameter to the join, you can add the ‘order’ parameter too if it makes sense in your context:
1 2 3 4 5 6 7 8 9 10 | class User extends AppModel { public $hasAndBelongsToMany = array( 'Video' => array( 'with' => 'UsersVideo', 'order' => 'UsersVideo.order' ) ); } |
Make sure you do a $model->saveAll() in the controller:
1 2 3 4 5 6 | if($this->User->saveAll($this->data)){ // Success message // Redirect } else { // Error message } |
The trick is in the naming of the form input elements. The format is Video.X.UsersVideo.field_name.
Here’s an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?= $form->input('Video.id') ?> <?= $form->input('Video.0.UsersVideo.video_id', array( 'type' => 'select', 'options' => $videos )) ?> <?= $form->input('Video.0.UsersVideo.order', array( 'type' => 'select', 'options' => range(1, count($videos)) )) ?> <?= $form->input('Video.0.UsersVideo.user_id', array( 'type' => 'hidden', 'value' => $user['User']['id'] )) ?> |
Which outputs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [User] => Array ( [id] => 3 ) [Video] => Array ( [0] => Array ( [UsersVideo] => Array ( [video_id] => 9 [order] => 2 [user_id] => 3 ) ) ) |
This will add a record to the join table with the order value.
Obviously you can expand on this to save more users_videos records during the same saveAll call.
I had a couple of CKEditors in a jQuery UI dialog box today. The dialog box contained an iFrame with the actual CKEditors inside that.
On the odd occasion when the modal box opened (tested in FireFox 3.6 on the Mac and PC) the vertical scroll position of the iFrame would not be at the top. Instead it was focused on one of the lower CKEditors.
After some Googling and hacking and still no solution I placed this in each CKeditor onReady/instanceReady callback, which did the trick:
1 2 3 | CKEditor.on("instanceReady", function(event){ $(window).scrollTop(0); }); |
I’m in the situation where most of my CMS components are extensible CakePHP plugs.
I’ve just started to use the CakeDC migrations plugin (been meaning to for a long time as I always loved Rails migrations).
I had previously automated the insertion of plugin ACO node records using a Bash script that chugged through a stack of ‘cake acl create aco bla/bla bla’ commands.
After playing with the migration callbacks for a while I figured out how to insert ACO nodes. The killer part of this process is remembering to attach the Tree behavior to the ACL model. Otherwise your ACO tree hierarchy will get toasted!
My advice would be to SQL dump your database/ACO table before playing with this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | # Migration after callback # Inserts a node for the Dashboard controller and then a single admin_index child action. public function after($direction) { $aco = $this->generateModel('Aco'); // Be sure to attach this. Otherwise it's bye-bye tree hierarchy!! $aco->Behaviors->attach('Tree'); if( $direction == 'up' ){ // Insert ACO node for dashboard controller. $data['Aco']['parent_id'] = 1; $data['Aco']['alias'] = 'Dashboard'; $aco->save($data); // Insert ACO node for dashboard admin_index action. $data['Aco']['parent_id'] = $aco->id; $data['Aco']['alias'] = 'admin_index'; $aco->create(); $aco->save($data); } elseif( $direction == 'down' ) { $dashboard = $aco->findByAlias('Dashboard'); // Remove ACO nodes. if( !empty($dashboard) ){ $aco->deleteAll(array('Aco.parent_id' => $dashboard['Aco']['id'])); $aco->delete($dashboard['Aco']['id']); } } return true; } |
Coupling this with a create_table in the up stage of the migration will mean plugin installations should be a 2 stage process.
1) Import plugin using Piston/SVN external.
2) Run the install migration creating table(s) and registering permit-table actions (ACO nodes).