Category Archives: Geekiness

CakePHP Personal Notes

Just links and things as I learn my way around CakePHP

https://github.com/mcurry/cakephp_static_user – didn’t work

Realised that the acl plugin should be in app/Plugin not /plugins
http://book.cakephp.org/2.0/en/plugins.html

Get data from another controller.
http://stackoverflow.com/questions/9205540/cakephp-how-to-retrieve-data-from-another-model-in-controller

$this->Result->Quiz->Question->find('count')

This found all the questions – not, as I first thought, the questions for that quiz.

http://devblog.springest.com/how-to-find-related-data-in-habtm-models/
Helped me to

    public function number_of_questions()
    {
        $x = $this->Question->Quiz->find('all',array(
            'conditions' => array(
                'Quiz.id' => $this->id
            )));
        return(count($x[0]['Question']));        
    }

Not sure what the 0 should be.  Not very “CakePHP ish”. Then

$this->Quiz->number_of_questions()

Uploads:
https://github.com/blueimp/jQuery-File-Upload

CakePHP eureka moments

It is a very  steep learning curve, and I keep forgetting what I learn, so just going to keep a list.

  1. To make a link to ‘id’ on a .ctp page link to something more useful change the column name thus:
    echo $this->Html->link($powerpoint['User']['id'], array('controller' => 'users', 'action' => 'view', $powerpoint['User']['id'])); 
    
    //becomes
    
    echo $this->Html->link($powerpoint['User']['username'], array('controller' => 'users', 'action' => 'view', $powerpoint['User']['id']));

    (The query is doing a join automatically in the background)

  2. To make a droplist show a useful thing like the name rather than the key, you need to go in to the XxxxxxController and change the function thus:
    $users = $this->Powerpoint->User->find('list');
    
    //becomes
    
    $users = $this->Powerpoint->User->find('list',array('fields' => array('User.id', 'User.username')));

    I guess it then used the two fields as given.  If you add a third field it is used as a label in the option.  Not sure how to concatenate the columns if you want “Firstname Lastname” in the droplist.

  3. The Model reflects the database. I knew that but recording it here, as I actually used it.
  4. If you have a table that is joined through another table (belongsto > belongsto) then you can make it appear thus in the Controller:
    		$users = $this->Question->Powerpoint->find('list', array(
    				"fields" => array('Powerpoint.user_id', 'Users.username'),
    				"joins" => array(
    					array(
    						"table" => "Users",
    						"type" => "LEFT",
    						"conditions" => array(
    							"Powerpoint.user_id = users.id"
    						)
    					)
    				)
    			));

     

CakePHP ACL with bcrypt/blowfish

I have been playing around with cakePHP, trying to get the authentication to play nicely with bcrypt.  bcrypt (blowfish crypt?) is a way of encrypting data which includes its own random salt in the hash.  So you only need one field for the password but it is pretty secure.

After a lot of pain, it turns out that moving from the working basic ACL security (set up using the tutorial) to bcrypt is pretty easy.  Two files to change!  But it took me hours to work out because of silly errors like not having the password field in the database long enough for the hash (they appear to be 250 characters long).

I suspect I don’t need the ‘username’ => ‘username’ etc. but after a long effort to get it working I don’t really want to break it again.

<?php
/**
 * Application level Controller
 *
 * This file is application-wide controller file. You can put all
 * application-wide controller-related methods here.
 *
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       app.Controller
 * @since         CakePHP(tm) v 0.2.9
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 */

App::uses('Controller', 'Controller');

/**
 * Application Controller
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @package		app.Controller
 * @link		http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
 */
class AppController extends Controller {

    public $components = array(
        'Acl',
        'Auth' => array(
            'authorize' => array(
                'Actions' => array('actionPath' => 'controllers')
            ),
			'authenticate' => array(
				'Blowfish' => array(
					'fields' => array(
						'username' => 'username',
						'password' => 'password'
					),
					'userModel' => 'User',
					'scope' => array()
				)
			)
        ),
        'Session'
    );

    public $helpers = array('Html', 'Form', 'Session');

    public function beforeFilter() {

		// Use bcrypt for hashes
		Security::setHash('blowfish');

        //Configure AuthComponent
        $this->Auth->loginAction = array(
          'controller' => 'users',
          'action' => 'login'
        );
        $this->Auth->logoutRedirect = array(
          'controller' => 'users',
          'action' => 'login'
        );
        $this->Auth->loginRedirect = array(
          'controller' => 'posts',
          'action' => 'add'
        );

		$this->Auth->allow('display');
    }
}

And change the beforeSave function in Model/User.php

	// for acl with blowfish/bcrypt
    public function beforeSave($options = array()) {

		// hash the password
        $this->data['User']['password'] = Security::hash($this->data['User']['password']);	

        return true;

    }

Of course, enabling this breaks the working logins and you have to edit them to get the new hashes.  You’ll be locked out if you don’t put $this->Auth->allow(); in the beforeFilter() function of the UsersController.php whilst you do it.