Array ACL plugin for CakePHP v1.3

What does this mean? It’s a simple and easy to use alternative to built in ACL component of CakePHP applications. I personally think that CakePHP’s built in Auth+ACL components are a bit unnecessarily complicated (but very versatile and powerful), and sometimes I just need a couple of users and groups, and an easy (opposed to all-purpose) way to implement what can each group member access. Thinking of just that I’ve created this plugin.

It’s main features are:

  • it’s installed and configured in 5 minutes
  • it’s powerful enough for simpler access management
  • access control lists are hard-coded in the application in a form of an array
  • it can be easily modified

At the moment of me starting to write this article the plugin was written for CakePHP v1.3, but before I actually published this article I ported it to CakePHP v2.0 (for which there will be another article soon).

Git repository can be found on github, here:

Or you can download Array ACL plugin for CakePHP 1.3 from here:

More on that simple ACL plugin for CakePHP 1.3…

Multi-column unique key validation in CakePHP

CakePHP (at least in v1.3) by itself does not support a straight-forward multiple column unique key validation, but in a few steps you can have an elegant solution to this problem. In order to create a validation for multi-column unique key, you can use the CakePHP’s custom validation logic by creating a function which will do the validation, and defining the rule in your validations array of your model.

Unique key validation function

In my opinion the best place to be put this method is in your app_model (you can put it in your model class, but this way you can use this in all your models).

Add this function to your /your_app_root/app/models/app_model.php file:

function checkUnique($data, $fields)
{
    // check if the param contains multiple columns or a single one
    if (!is_array($fields))
    {
        $fields = array($fields);
    }

    // go trough all columns and get their values from the parameters
    foreach($fields as $key)
    {
        $unique[$key] = $this->data[$this->name][$key];
    }

    // primary key value must be different from the posted value
    if (isset($this->data[$this->name][$this->primaryKey]))
    {
        $unique[$this->primaryKey] = "<>" . $this->data[$this->name][$this->primaryKey];
    }

    // use the model's isUnique function to check the unique rule
    return $this->isUnique($unique, false);
}

This function basically receives the form parameters containing the values to be added/updated, creates a key-value pair array containing the name of the field in the unique key, and it’s value, adds the primary key and its value to the check (must be different from an existing one, or your updated wouldn’t work), and uses the CakePHP built-in function “isUnique” to do the validation.

More on creating a multiple column unique key validation in CakePHP…

CakePHP in place update (with jQuery) plugin

Recently I had a need for an “in-place-update” of some fields on a CakePHP project that used jQuery. I found a lot of articles, examples and helpers that ironically didn’t help as much as I would like them to do, so I decided to write myself a new one.

I found a great example, but it only worked if you wished to edit items in displayed in a list-style or table-style structure, and I needed to basically have a standard CakePHP view view (yes a view view that corresponds to a view action in the controller), on which I can edit the Post title or description without going to the edit view.

A few slight modifications of the provided example, and voilà, I have created a CakePHP plugin for “in place update”. You can download it from github:

CakePHP in place updater plugin

Installation and usage

Extract the plugin

Extract the contents of the pack to the app/plugins/inplace_updater folder.

Add helper to your controller

Include the inplace_updater helper in your controller or app controller like so:

var $helpers = array(... 'InplaceUpdater.InplaceUpdater' ...);

Download and include Jeditable jQuery plugin to your layout

In order for this plugin to work, you will need to include the contents of the Jeditable jQuery plugin. Probably the simplest solution is to save the minified version (jquery.jeditable.mini.js) to your js folder, so the location of the file is “appwebrootjsjquery.jeditable.mini.js”.

Jeditable jQuery plugin is a plugin for jQuery, so oviously it cannot be run without jQuery. Download the latest jQuery and copy it to “appwebrootjsjquery.js”.

To include the required javascripts, add the following lines to your layout file (usually appviewslayoutsdefault.ctp):

<?php
    echo $javascript->link('jquery');
    echo $javascript->link('jquery.jeditable.mini');
?>

Add an in-place-updater control to your view

The updater helper allows you to add an “input” control to your views that will behave like the a div element (by default, or any other HTML element if you wish) on your view until you click/double-click/hover/etc on it, then it will appear as a text input, or a drop-down list, or any element supported by Jeditable jQuery plugin

<?php
echo $inplaceUpdater->input
(
    'Post',
    'title',
    $post['Post']['id'],
    array
    (
        'value'         => $post['Post']['title'],
        'actionName'    => 'inPlaceUpdate',
        'type'          => 'text',
        'cancelText'    => 'Cancel',
        'submitText'    => 'Save',
        'toolTip'       => 'Click to edit Post Title',
        'containerType' => 'h2',
    )
);
?>

Add an action handler in your controller

When the save button is pressed after modifying the in-place-edit element, a post is made to the inPlaceUpdate (by default) controller action. You can add a function like this to handle the in-place-update action.

function inPlaceUpdate($id = null)
{
    if (!$id)
        return;

    if ($this->data)
    {
        // get all the fields with its values (there should be only one, but anyway...)
        foreach($this->data['Post'] as $field => $value)
        {
            // check if the provided field name is acceptable
            switch($field)
            {
                case 'title':
                case 'description':
                    break;
                default:
                    $this->set('updated_value', '');
                    return;
            }

            $this->Post->id = $id;
            $this->Post->saveField($field, $value);

            $this->set('updated_value', $value);
        }
    }
}

Since you have a new action in your controller which is used for the in-place-update functionality, you will need to add the in_place_update view to your model’s views folder. And that view should display the updated result after save.

<?php 
	echo $updated_value;
?>

Using PHP to generate CSS

A neat and dirty trick for easier CSS manipulation, but you may say is a bit harder to develop CSS this way. My idea was that I can create a PHP file, which will add some more dynamics to your CSS. By that I mean you can add variables such as:

$mainColor = '#123';
$secondaryColor ='"#222';
$fontFamily = 'Georgia';
$fontSize = '12pt';
$backgroundColor = '#f5f5f5';

and use them in your CSS like this:

body
{
    font-family: < ?php echo$fontFamily; ?>;
    font-size: < ?php echo $fontSize; ?>;
    color: < ?php echo $mainColor; ?>;
    background-color: < ?php echo $backgroundColor; ?>;
} 

/* and many, many more elements */

Now you might guess how easy it can be to leave the same layout, but make a completely different look of the application, just by modifying a few variables.

More on generating CSS styles with PHP…

JQValidator – CakePHP Client Side Validation

CheckmarkJQValidator is a plugin for CakePHP used for a client side validation of a CakePHP model, written in jQuery. It’s main purpose is to validate the inserted information prior to their submit to the server, this both reduces the number server requests and makes your application faster and more user-friendly.

The plugin is still in an infant phase of the development, supporting validation for only the following data types:

  • notempty,
  • numeric
  • date

But with further development needs, I will update the plugin accordingly. Any help from anyone else is also appreciated.

JQValidator is available on github. For more information on the functionalities, installation and usage read the JQValidator plugin wiki.

Generate an URL from the controller and action name with CakePHP

CupcakeFirst of all, I am quite sure that there is another way to do this, and those who know must have said “This boy is dumb as a bag of hammers”. Some might even say, “you can generate a link with the Html helper”, yes I know, but I need to generate an URL not a link, for example when I want to add an AJAX call to a specific location within my CakePHP application.

Anyway, until you drop me a comment on how to do this anyhing better, I may reccommend this method. I have created a helper class, that incorporates the HtmlHelper’s link method and gets the url using regex.

Helper class

< ?php
class UrlBuilderHelper extends AppHelper
{
    var $helpers = array('Html');

    function build($options)
    {
        $linkHtml = $this->Html->link('title', $options);
        $regEx = "/<a href="(.*)">.*</a>/";
        $matches = array();
        preg_match($regEx, $linkHtml, $matches);
        return $matches[1];
    }
}
?>

More on generating URLs in CakePHP…

Using multiple column primary key in CakePHP (cascade delete problem)

ReviewI guess you stumbled here because you want to know can you use a primary key in your CakePHP model made of two or more columns.
Well… You can’t, at least in the the CakePHP 1.3, at least I couldn’t, and if you can, let me know, because that would be awesome…

Problem

Anyway, I know I tried to have a table like this:

CREATE TABLE `projects_users`
(
    `project_id` int(10) unsigned NOT NULL,
    `user_id`    int(10) unsigned NOT NULL,
    `attr`     int(10) unsigned NOT NULL,
    PRIMARY KEY (`project_id`,`user_id`)
);

Unlike in all CakePHP projects, I wanted to have a regular HABTM mid-table like I would have had in SQL Server for example. I even saw a web-page (instead of reading this) that described how to use multi-column primary key in CakePHP by adding the $primaryKey value (like below) to your model (in my case “ProjectsUser”):

< ?php
class ProjectsUser extends AppModel
{
    var $name = 'ProjectsUser';
    var $primaryKey = array('project_id','user_id');
    var $belongsTo = array
    (
        'Project' => array
        (
            'className' => 'Project',
            'foreignKey' => 'project_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'User' => array
        (
            'className' => 'User',
            'foreignKey' => 'user_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );
}
?>

Great success… NOT.

So I’ve been working and working on the MVC’s related to this this table, with no problems, until I saw that the cascade delete didn’t work on this table. I didn’t even saw any errors displayed, but it just didn’t work.
More on using multiple column primary key in CakePHP

My experience with CakePHP

“My experience with CakePHP”, sounds like a school assignment we always got when we got back from the summer leave… Anyway I’ve been using CakePHP framework for some time and I have realized that I looked for the same things (how-to’s, helpers, bug fixes, etc…) several times.

Well, not any more, whenever I “discover” something, no matter how embarrassing I’ll try to write it down, it will help me not to forget, and I hope that it helps someone sometime…