Archive for the ‘CakePHP 1.2’ Category

INI Based Permission Component


Warning: fopen(/ini.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/ini.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/ini.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/ini.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Yet another permission component was created this week but this time, it’s simplier and written in a text file. In one of our project, one of the follow-up requirement was to allow users of certain groups upgrade into a better status. The project was already in production and I was using ACL with Auth component to do my authentication. Unfortunately, this is one of ACLs weakness.

Changing a users group does not change the ARO parent (effectively making it useless/impossible to change groups). I tried fixing this home-brew style, but since there’s no setParent in 1.2′s db_acl, it’s far harder than it should be.

That was reported back in 2007 and there was still no solution found in the net. It is also not an option for me to go through the above suggestion in fixing the problem so the the other solution is to find another one or create one. I chose the latter.

Why create a new one?

The other solutions that I found still needs some configuration in the controllers. Since I already have a ton of files, I don’t want to go through all of them to add a line or two. I need ACLs way of doing it all in the background. Also, I am already using Auth component and I want to keep it.

Why did I choose a text file over a database?

My intention is to make the application faster since load time is really getting slower. Since the application isn’t that big, I only have less than 200 lines for the permissions, so a database is just overkill. Even if I use a database, I might cache it anyway so it saves me extra query.

The component

So Permission Component was created. Below is the instruction on how to install it.

  1. Download this component and copy to your components folder.
  2. Create cake_dir/app/config/permissions.ini

The content for permissions.ini is as follows

1

2
[ControllerName]
3
actionName = group_id,group_id
4
 
5
[PluginName.ControllerName]
6
actionName = group_id,group_id
7

The ControllerName should be the controller name itself (in camel-case format).

The actionName is also the action name itself (in camel-case format).

The PluginName is the plugin name itself (in camel-case format).

The group_id is the one written in your Auth component. Your Auth component should have a group_id value because this is what our Permission component will look for. It could be a number or set of characters.

Example:

01

02
; Group ID 1 = Admin
03
; Group ID 2 = Member
04
[Accounts]
05
index =
06
add = 1
07
edit = 1,2
08
delete = 1,2
09
 
10
[ShoppingCart.Orders]
11
index =
12
report = 1
13

Assigning no group id in an actionName will simply ignore it.

Reminder

Use at your own risk. If you found a bug, please post them at the comment form.

How to Bake a New Project in CakePhp

I use bake to start any project of mine and therefore doesn’t mean that using it produces a complete app unless you only want a CRUD application.

This tutorial is intended for beginners in cakephp. It is still recommended that you look at the blog tutorial in cakephp manual because it has a more complete introduction for the framework.

Take note that I am using the Cakephp 1.2.0.7692 RC3 in demonstrating this little project because it is the latest release as of this writing.

What to do and what do we need to begin?

To start off, we need a project. I opted a mini-library application which consists of

Books
Authors
Book reviews by users

Read the rest of this entry »

Tags: ,

Learn Containable Behavior by Example

In cakephp, adding relationships is easy. We just have to declare the hasOne, belongsTo, hasMany and the famous HABTM relationship to do all the dirty work of joining tables. But declaring them all at once could lead to a slow page.

In version 1.1, what we do is utilize the bindModel() and unbindModel(). We do not declare all associations in the Model class yet. This was a good solution. I was looking for this option in version 1.2 and I found the Containable Behavior. Studying containable was a little rough before but there are documents now that are really helpful.
Read the rest of this entry »

Tags: ,

Use Model->create()

From now on, I’ll always use Model->create() before saving new data.

I’ve been using Model->create() for a series Model->save() calls (like in a loop) to initialize the model class for saving new information. But when I only need to do a single call to save(), I no longer call create() assuming that I’m starting with a new set of information. I was always able to get away with it until I had this bug that annoyed me for a few hours.

Long story short, I learned something: not only when doing multiple calls to Model->save(), you should also call Model->create() before saving if a previous call to Model->read() was made. Or better yet, always call Model->create() whenever you are about to save new data. There are cases the previous calls to save and read made are not that obvious, like in the beforeFilter() callbacks of the controller (or the parent::beforeFilter(), like in my case).

jQuery star rating problem with brackets []


Warning: fopen(/html4strict.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html4strict.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/javascript.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

If you used the star rating plugin of jQuery in cakePHP, you might experienced that the hover effects are not working properly. This is because one of the class name used to identify the buttons uses the radio button name. This will be a problem in cakephp because we use brackets in names.


<input type="radio" name="data[Model][field]" class="star" />

In order to fix that, we need to remove them. Here is quick fix. Open file jquery.rating.js:

from (line 97):


// grouping:
  var n = this.name;

to:


// grouping:
  var real_name = this.name;
  var n = real_name.replace(/[^A-Za-z0-9_\-]/g, '-'); // remove unwanted characters

from (line 108):


$.rating.groups[n].valueElem = $('<input type="hidden" name="' + n + '" value=""' + (settings.readOnly ? ' disabled="disabled"' : '') + '>');

to:


$.rating.groups[n].valueElem = $('<input type="hidden" name="' + real_name + '" value=""' + (settings.readOnly ? ' disabled="disabled"' : '') + '>');

I have reported this in the bugtracker and I hope it will be included in the next release.

Tags: , ,

Making Clickable Images on CakePHP

Hello again,

Yesterday, i stumbled upon this problem on how am i suppose to create an image with a link on it. I needed to know it because of my goal. I wanted to use images as my buttons to navigate the admin pages. So without further ado, here’s how:

1. We will use HTML Helpers Image and Link, and we shall combine this 2.

2. For Image,

Syntax:

$html->image(string $path, array $htmlAttributes, boolean $return = false);

Example:

$html->image(‘/img/images/cancel.png’, array(‘class’ => ‘save_button’));

3. For Link,

Syntax:

$html->link(string $title, string $url, array $htmlAttributes, string $confirmMessage = false, boolean $escapeTitle = true, boolean $return = false);

Example:

$html->link(‘SAVE’, ‘/registers’, array(), false, false, false);

4. So to make an image clickable,

<?php echo $html->link($html->image(‘/img/images/cancel.png’,array(‘class’ => ‘save_button’)), ‘/registers’, array(), false, false, false); ?>

That’s it. I hope this will help you in the future.

Setting Frontpage in CakePHP

Hello again readers,

I have another topic for newbies like me. I know this will help you. And this is very, very easy and it’s a common thing to do when developing websites. It’s establishing a homepage. Here’s how and this won’t take long.

1. Code your desired design. This does not require you to complete the entire html tags. Just the contents inside <body></body> would be fine.

2. Then save it as home.ctp and upload to app/views/pages.

And that’s it. You can now check your new homepage design.

Setting Your Page Layout in CakePHP

I am not a pro in CakePHP, and in fact, i am just a beginner who wanted to explore it. When I was on my way to creating my goal, I stumbled upon a problem on how to change and then set the new page layout to be used. Honestly, the problem didn’t took me long to solve. I was lucky to have read the manual on the official site. So to cut the long story short, here is the list of steps which I did to come up with my new and first page layout on my CakePHP inspired website and you might consider following this little manual, too.

1. First, design the layout that you wanted to implement and use. Assuming we have the simple code below as your desired page layout.
<html>
<head>
<title></title>
</head>
<body>

</body>
</html>

2. After having established the base, let us now put the code that will show the title of your page. We will use $title_for_layout to do the job. So your head section will now look like this:
<head>
<title><?php echo $title_for_layout?></title>
</head>

3. Next inline would be displaying the contents. We will use $content_for_layout. It will tell CakePHP where to place the code for your views. Our code now will look like this one.
<html>
<head>
<title><?php echo $title_for_layout?></title>
</head>
<body>
<?php echo $content_for_layout ?>
</body>
</html>

4. Then save it as app/views/layouts/default.ctp.

Next topic would be creating and using multitle layouts for single website. Please feel free to share your views which you think can help us beginners make a step higher on CakePHP.

CakePHP 1.2: Using Auth with ACL


Warning: fopen(/sql.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/sql.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/sql.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/sql.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/sql.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/sql.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

A project we’re working on needed something to keep track of user activity and restrict parts of the application to certain users/groups. We are using CakePHP 1.2 and decided to use its built-in support for user authentication and access control list. Though each of them is nicely documented at the Cookbook, there wasn’t much info or resource that shows how to put these two components to work together. Fortunately, we have found some nice tutorials/articles that helped us implement them into our application. Check out those links at the end.

The Setup

We want to restrict certain actions to certain types of users. But instead of assigning permissions to each user, we just divide users into groups and assign permission to groups. Users under the same group have the same set of permission.

For this example,  we’ll be dividing users into groups namely: admin, editor and member.

Setting up the database tables

Users Table:

<br />CREATE TABLE `users` (&nbsp;&nbsp;&nbsp;&nbsp; <br /><br />	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,<br />	`username` VARCHAR( 20 ) NOT NULL ,<br />	`password` VARCHAR( 50 ) NOT NULL ,<br />	`group_id` TINYINT( 2 ) NOT NULL DEFAULT '0',<br />	PRIMARY KEY ( `id` )) ENGINE = MYISAM ;

Groups Table:

<br />CREATE TABLE `groups` (<br /><br />	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,<br />	`parent_id` INT UNSIGNED NOT NULL DEFAULT '0',<br />	`name` VARCHAR( 20 ) NOT NULL ,<br />	PRIMARY KEY ( `id` )<br />) ENGINE = MYISAM ;

ACL Tables:
The sql dump for the acl table can also be found at the app/config/sql folder of your application

<br />CREATE TABLE acos (<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,<br />	parent_id INTEGER(10) DEFAULT NULL,<br />	model VARCHAR(255) DEFAULT '',<br />	foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,<br />	alias VARCHAR(255) DEFAULT '',<br />	lft INTEGER(10) DEFAULT NULL,<br />	rght INTEGER(10) DEFAULT NULL,<br />	PRIMARY KEY&nbsp;&nbsp;(id));<br /><br />CREATE TABLE aros_acos (<br />	id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,<br />	aro_id INTEGER(10) UNSIGNED NOT NULL,<br />	aco_id INTEGER(10) UNSIGNED NOT NULL,<br />	_create CHAR(2) NOT NULL DEFAULT 0,<br />	_read CHAR(2) NOT NULL DEFAULT 0,<br />	_update CHAR(2) NOT NULL DEFAULT 0,<br />	_delete CHAR(2) NOT NULL DEFAULT 0,<br />	PRIMARY KEY(id)<br />);<br /><br />CREATE TABLE aros (<br />	id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,<br />	parent_id INTEGER(10) DEFAULT NULL,<br />	model VARCHAR(255) DEFAULT '',<br />	foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,<br />	alias VARCHAR(255) DEFAULT '',<br />	lft INTEGER(10) DEFAULT NULL,<br />	rght INTEGER(10) DEFAULT NULL,<br />	PRIMARY KEY&nbsp;&nbsp;(id)<br /><br />);

Setting up the models

After setting up the tables, we now move on to creating the models for our CakePHP application:

User model:

<br />uses('Sanitize');<br />class User extends AppModel {<br />	var $name = 'User';<br /><br />	// Set the User model to use the ACL Behavior<br />	// This will take care of ACL-related things when working on<br />	// this model like adding/deleting the corresponding ARO node<br />	// when a user is added/deleted.<br />	var $actsAs = array('Acl');<br /><br />	// Associate with the Group table<br />	var $belongsTo = array('Group');	<br /><br />	function parentNode(){<br />		if (!$this->id) {<br />			return null;<br />		}<br /><br />		$data = $this->read();<br /><br />		if (!$data['User']['group_id']){<br />	&nbsp;&nbsp;		return null;<br />		} else {<br />	&nbsp;&nbsp;		return array('model' => 'Group', 'foreign_key' => $data['User']['group_id']);<br />		}<br />	}<br /><br />	// Ok, even if the ACL behavior takes care of the insertion of the<br />	// corresponding ARO node, it doesn't save an alias so you have to<br />	// give one yourself. We'll be using the username for the alias.<br />	// We'll do this after a new user is saved/inserted, so do it inside<br />	// the model's afterSave function<br />&nbsp;&nbsp;	function afterSave($created) {<br /><br />		// Do this if the save operation was an insertion/record creation<br />		// and not an update operation<br />&nbsp;&nbsp;		if($created) {<br />&nbsp;&nbsp;			// Ah, yes... we'll be needing the Sanitize component<br />&nbsp;&nbsp;			$sanitize = new Sanitize();	<br /><br />			// Get the id of the inserted record<br />			$id = $this->getLastInsertID();<br /><br />			// Instantiate an ARO model that will be used for updating<br />			// the ARO<br />			$aro = new Aro();<br /><br />			// I'm using updateAll() instead of saveField()<br />			// Instead of querying the table to get the id of the<br />			// ARO node that corresponds to the user, I just provided<br />			// two field conditions whose combination uniquely identifies<br />			// the node (Model=> User, Foreign Key=> User id).<br /><br />			// I don't know why it wasn't sanitizing my input and not<br />			// enclosing the input in quotes. I had to do it myself<br />			$aro->updateAll(<br />			array('alias'=>'\''.$sanitize->escape($this->data['User']['username']).'\''),<br />				array('Aro.model'=>'User', 'Aro.foreign_key'=>$id)<br />			);<br />		}<br />		return true;<br />	}<br />}

The line:

var $actsAs = array('Acl');

Sets the model to use CakePHP built-in ACL behavior. This will take care of ACL-related things when working on this model like adding/deleting the corresponding ARO node when a user is added/deleted.

When using the ACL Behavior, you need to provide a parentNode() method in your model. The parentNode() method returns the id of the parent of the current acl node. A tree structure is used to implement ACL, so you can either directly assign permission to a node or just allow a node to inherit the permissions of its parent.

I found out from Geoff’s blog (LemonCake) that the key to using groups for user permission is to set the user aros as children of the a group aro. You can do this inside the models parentNode() method:

Group Model:

<br />// Okay, I won't be commenting on this since this almost the same<br />// as what you can see from the user model definition<br /><br />uses('Sanitize');<br />class Group extends AppModel {<br />	var $name = 'Group';<br />	var $actsAs = array('Acl');<br /><br />	function parentNode(){<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;	if (!$this->id) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;		&nbsp;&nbsp;&nbsp;&nbsp;	return null;<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;	}<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;	$data = $this->read();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;	if (!$data['Group']['parent_id']){<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;		return null;<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;	} else {<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;		return $data['Group']['parent_id'];<br />&nbsp;&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&nbsp;	}<br />&nbsp;&nbsp;	}<br /><br />&nbsp;&nbsp;	function afterSave($created) {<br />&nbsp;&nbsp;		if($created) {<br />&nbsp;&nbsp;			$sanitize = new Sanitize();	<br /><br />			$id = $this->getLastInsertID();<br /><br />			$aro = new Aro();<br /><br />			$aro->updateAll(<br />				array('alias'=>'\''.$sanitize->escape($this->data['Group']['name']).'\''),<br />				array('Aro.model'=>'Group', 'Aro.foreign_key'=>$id)<br />				);<br />		}<br />		return true;<br />	}<br />}

Setting up the controllers

Okay now, let’s keep the code short. We won’t provide any user registration here, just a way of logging users in and out of the application.

users_controller.php:

<br />class UsersController extends AppController {<br />	var $name = 'Users';<br />	// We will be using the Acl and Auth component<br />	// The order you declare the components is<br />	// important. Acl first before Auth or you<br />	// will get an error message.<br />	var $components = array('Acl', 'Auth');<br /><br />	// This is how complicated the login part<br />	// gets when using the auth component.<br />	function login() {<br />	}<br /><br />	// ... and the logout part<br />	function logout() {<br />		$this->redirect($this->Auth->logout());<br />	}<br /><br />	function beforeFilter() {<br />		$this->Auth->logoutRedirect = array(<br />			'admin' => false,<br />			'controller' => 'pages',<br />			'action' => 'index'<br />		);<br />	}<br /><br />}

Now that takes care of the user authentication. To use Auth w/ ACL in our controllers, we first need to include the components (of course!). Make sure that Acl goes before the Auth component or else, you’ll get an error message.

<br /> var $components = array('Acl', 'Auth');

Then, we need to set the Auth component to treat the controller and actions as our access control objects. Inside the beforeFilter() method:

<br /> function beforeFilter()<br /> {<br /> 	$this->Auth->authorize = 'actions';<br /> }

Setting Up AROs, ACOs and Permissions:

Our AROs will be the users and groups. Since our user and group models already use the ACL behavior, we no longer have to worry creating AROs for them- they are already created when a new user or group is added. We only have to deal with creating ACOs. If you’ve already read the part of the manual about access control lists, you’ll find out that adding an ACO is just like saving data using models. You just need to specify the name of the controller/action as its alias and its parent id.

<br /> 	$aco = new Aco();<br /> 	$aco->create();<br /><br /> 	$aco->save(array(<br /> 	&nbsp;&nbsp; 'model'=>null,<br /> 	&nbsp;&nbsp; 'foreign_key'=>null,<br /> 	&nbsp;&nbsp; 'parent_id'=> $parentIdIfAny,<br /> 	&nbsp;&nbsp; 'alias'=> $nameOfControllerOrAction<br /> 	));

You might want to have a root node where all default permissions will be based upon. Then this node will contain child nodes, which will be our controller names. Then each controller will have action names as child nodes.

Controller
     |- Pages
     |    |- index
     |    |- about
     |    |- contact
     |- Articles
          |- index
          |- view
          |- add
          |- edit
          |- delete

To assign permissions, use the allow() and deny() methods of the ACL component. These methods takes at least 2 parameters: first is the ARO and second is the ACO. We could reference an ARO/ACO node using its alias or by providing an array of field conditions that uniquely describes the node.

<br />$this->Acl->allow(array('model'=>'Group', 'foreign_key'=>$groupId), $nameOfControllerOrAction);

Since it is very likely that different controllers to have the same action names (thus making their alias non-unique and cause ambiguity), we can specify the path to the node using slashes (/).

<br />$this->Acl->allow(array('model'=>'Group', 'foreign_key'=>$groupId), 'Pages/index');<br />$this->Acl->allow(array('model'=>'Group', 'foreign_key'=>$anotherGroupId), 'Articles/index');

You can deny all permissions on the root node (in this case, the ‘Controller’) to set default permissions that will be inherited by all the controllers. Then grant permission per controller or per action.

The Test Run:

I provided a simple app demo for download (acl_demo.zip).
1) Extract the contents of the zip file.
2) Run the sql file found inside the models folder
3) Edit the content (ROOT, APP_DIR and CAKE_CORE_INCLUDE_PATH paths) of index.php under the webroot folder according to you CakePHP setup
4) Access the index page of the app (ex: http://localhost/acl/) and click the setup button. Take note of the username and password of the accounts that will be created.
5) Login and test the application. Members page should only be accessible to members and admin. Editors page to editors and admin. Administrators page to administrator only.

Errors, corrections or suggestions? Feel free to leave a comment.

Sources:
http://manual.cakephp.org/view/171/access-control-lists
http://manual.cakephp.org/view/172/authentication
http://lemoncake.wordpress.com/2007/07/15/using-aclbehavior-in-cakephp-12/
http://lemoncake.wordpress.com/2007/07/19/acl-with-groups/
http://aranworld.com/article/161/cakephp-acl-tutorial-what-is-it

Tip: use CakePHP Route::url() for your URLs


Warning: fopen(/html4strict.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html4strict.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html4strict.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html4strict.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/html.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Warning: fopen(/php.php) [function.fopen]: failed to open stream: Permission denied in /home/promet/public_html/cakephp/wp-content/plugins/devformatter/devgeshi.php on line 103

Routing is one of the amazing features of CakePHP because it makes the urls beautiful. We use this most of the time and last time, I blogged about the helper to shortcut ones typing when using the HTML helper. Overtime, I realize how helpful it can be. Read on.

Always use array when passing parameters when creating a link or using Router::url(), it will save you time in the future. Why? Consider this scenario:

You created a controller /users/register and in your code and you added this


<?php echo $html->link('User Registration', '/users/register')?>

Then your group or your boss decided to use a better name /register. Your initial thought would be to replace all those texts to those new ones, isn’t it? There is a better approach. Try the ffg:

In /config/router.php


<?php Router::connect('/register',	array('controller'=>'users','action'=>'register'));  ?>

In your view:


<?php echo $html->link('Registration', array('controller'=>'users','action'=>'register'))?>

the HTML helper uses Router::url() in its link function and the Router class magically converts array parameters to what you stated in your config. In writing urls, we have to be consistent because it can be bad for SEO when you have too many urls pointing to the same location.

Although the above works beautifully but it can be a tedious job. I wrote not long ago about the html helper that could make this approach easier so you could write the ffg in your view.


<?php echo $html->link('Registration', url( 'users', 'register', null, 'teacher' ))?>

It saves a few characters!

From the last post, I refactored it and placed it in the bootstrap so I can call it anywhere (got that idea from the google groups).

Here it is:


    function url() {
        $args = func_get_args();
        $count = func_num_args();
 
        if ( $count == 1 ) {
            if ( is_array( $args[0] ) ) {
                $args = $args[0];
                $count = count($args);
            } else {
                return $args[0];
            }
        }
 
        $short_keys = array(
            0 => 'controller',
            1 => 'action',
            2 => 'plugin',
            'c' => 'controller',
            'a' => 'action',
            'p' => 'plugin',
        );
 
        foreach ( $short_keys as $short_name => $long_name ) {
 
            if ( isset( $args[$short_name] ) ) {
                $args[$long_name] = $args[$short_name];
                unset( $args[$short_name] );
            }
 
        }
 
        // Need to explicitly assign plugin key
        if ( !isset( $args['plugin'] ) ) $args['plugin'] = null;
        if ( !isset( $args['action'] ) ) $args['action'] = 'index';
        if ( !isset( $args['admin'] ) ) $args['admin'] = false;
 
        $routing = Configure::read('Routing.admin');
        if ( preg_match( "/^{$routing}_/", $args['action'] ) && $routing ) {
            $args['admin'] = true;
            $args['action'] = substr( $args['action'], strlen($routing) + 1 );
        }
 
        return $args;
    }

The function above could take an array OR any number of string parameters.


url ( 'controller', 'action', 'plugin_name', ...[more params here] )
url ( array( 'c' => 'controller', 'a' => 'action', 'p' => 'plugin' ) )

The first one is strict for the first 3 parameters. The latter can be written in any order as you like. I also added support for prefix routing such as admin_*. So you can write:


url ( 'controller', 'admin_action', 'plugin_name', ...[more params here] )
url ( array( 'c' => 'controller', 'a' => 'admin_action', 'p' => 'plugin' ) )

Router::parse() can also be used instead of url() function but the latter is faster.

That’s it. Happy Baking!

Tags: ,