Welcome to the Cookbook

loading...

5.1.3.2 Creating Access Request Objects (AROs) and Access Control Objects (ACOs)

In creating new ACL objects (ACOs and AROs), realize that there are two main ways to name and access nodes. The first method is to link an ACL object directly to a record in your database by specifying a model name and foreign key value. The second method can be used when an object has no direct relation to a record in your database - you can provide a textual alias for the object.

In general, when you're creating a group or higher level object, use an alias. If you're managing access to a specific item or record in the database, use the model/foreign key method.

You create new ACL objects using the core CakePHP ACL models. In doing so, there are a number of fields you'll want to use when saving data: model, foreign_key, alias, and parent_id.

The model and foreign_key fields for an ACL object allows you to link up the object to its corresponding model record (if there is one). For example, many AROs will have corresponding User records in the database. Setting an ARO's foreign_key to the User's ID will allow you to link up ARO and User information with a single User model find() call if you've set up the correct model associations. Conversely, if you want to manage edit operation on a specific blog post or recipe listing, you may choose to link an ACO to that specific model record.

The alias for an ACL object is just a human-readable label you can use to identify an ACL object that has no direct model record correlation. Aliases are usually useful in naming user groups or ACO collections.

The parent_id for an ACL object allows you to fill out the tree structure. Supply the ID of the parent node in the tree to create a new child.

Before we can create new ACL objects, we'll need to load up their respective classes. The easiest way to do this is to include Cake's ACL Component in your controller's $components array:

var $components = array('Acl');
  1. var $components = array('Acl');

Once we've got that done, let's see what some examples of creating these objects might look like. The following code could be placed in a controller action somewhere:

While the examples here focus on ARO creation, the same techniques can be used to create an ACO tree.

Keeping with our Fellowship setup, let's first create our ARO groups. Because our groups won't really have specific records tied to them, we'll use aliases to create these ACL objects. What we're doing here is from the perspective of a controller action, but could be done elsewhere. What we'll cover here is a bit of an artificial approach, but you should feel comfortable using these techniques to build AROs and ACOs on the fly.

This shouldn't be anything drastically new - we're just using models to save data like we always do:

function anyAction()
{
	$aro =& $this->Acl->Aro;
	
	//Here's all of our group info in an array we can iterate through
	$groups = array(
		0 => array(
			'alias' => 'warriors'
		),
		1 => array(
			'alias' => 'wizards'
		),
		2 => array(
			'alias' => 'hobbits'
		),
		3 => array(
			'alias' => 'visitors'
		),
	);
	
	//Iterate and create ARO groups
	foreach($groups as $data)
	{
		//Remember to call create() when saving in loops...
		$aro->create();
		
		//Save data
		$aro->save($data);
	}

	//Other action logic goes here...
}
  1. function anyAction()
  2. {
  3. $aro =& $this->Acl->Aro;
  4. //Here's all of our group info in an array we can iterate through
  5. $groups = array(
  6. 0 => array(
  7. 'alias' => 'warriors'
  8. ),
  9. 1 => array(
  10. 'alias' => 'wizards'
  11. ),
  12. 2 => array(
  13. 'alias' => 'hobbits'
  14. ),
  15. 3 => array(
  16. 'alias' => 'visitors'
  17. ),
  18. );
  19. //Iterate and create ARO groups
  20. foreach($groups as $data)
  21. {
  22. //Remember to call create() when saving in loops...
  23. $aro->create();
  24. //Save data
  25. $aro->save($data);
  26. }
  27. //Other action logic goes here...
  28. }

Once we've got them in there, we can use the ACL console application to verify the tree structure.

$ cake acl view aro

Aro tree:
---------------------------------------------------------------
  [1]warriors

  [2]wizards

  [3]hobbits

  [4]visitors

---------------------------------------------------------------

I suppose it's not much of a tree at this point, but at least we've got some verification that we've got four top-level nodes. Let's add some children to those ARO nodes by adding our specific user AROs under these groups. Every good citizen of Middle Earth has an account in our new system, so we'll tie these ARO records to specific model records in our database.

When adding child nodes to a tree, make sure to use the ACL node ID, rather than a foreign_key value.

function anyAction()
{
	$aro = new Aro();
	
	//Here are our user records, ready to be linked up to new ARO records
	//This data could come from a model and modified, but we're using static
	//arrays here for demonstration purposes.
	
	$users = array(
		0 => array(
			'alias' => 'Aragorn',
			'parent_id' => 1,
			'model' => 'User',
			'foreign_key' => 2356,
		),
		1 => array(
			'alias' => 'Legolas',
			'parent_id' => 1,
			'model' => 'User',
			'foreign_key' => 6342,
		),
		2 => array(
			'alias' => 'Gimli',
			'parent_id' => 1,
			'model' => 'User',
			'foreign_key' => 1564,
		),
		3 => array(
			'alias' => 'Gandalf',
			'parent_id' => 2,
			'model' => 'User',
			'foreign_key' => 7419,
		),
		4 => array(
			'alias' => 'Frodo',
			'parent_id' => 3,
			'model' => 'User',
			'foreign_key' => 7451,
		),
		5 => array(
			'alias' => 'Bilbo',
			'parent_id' => 3,
			'model' => 'User',
			'foreign_key' => 5126,
		),
		6 => array(
			'alias' => 'Merry',
			'parent_id' => 3,
			'model' => 'User',
			'foreign_key' => 5144,
		),
		7 => array(
			'alias' => 'Pippin',
			'parent_id' => 3,
			'model' => 'User',
			'foreign_key' => 1211,
		),
		8 => array(
			'alias' => 'Gollum',
			'parent_id' => 4,
			'model' => 'User',
			'foreign_key' => 1337,
		),
	);
	
	//Iterate and create AROs (as children)
	foreach($users as $data)
	{
		//Remember to call create() when saving in loops...
		$aro->create();

		//Save data
		$aro->save($data);
	}
	
	//Other action logic goes here...
}
  1. function anyAction()
  2. {
  3. $aro = new Aro();
  4. //Here are our user records, ready to be linked up to new ARO records
  5. //This data could come from a model and modified, but we're using static
  6. //arrays here for demonstration purposes.
  7. $users = array(
  8. 0 => array(
  9. 'alias' => 'Aragorn',
  10. 'parent_id' => 1,
  11. 'model' => 'User',
  12. 'foreign_key' => 2356,
  13. ),
  14. 1 => array(
  15. 'alias' => 'Legolas',
  16. 'parent_id' => 1,
  17. 'model' => 'User',
  18. 'foreign_key' => 6342,
  19. ),
  20. 2 => array(
  21. 'alias' => 'Gimli',
  22. 'parent_id' => 1,
  23. 'model' => 'User',
  24. 'foreign_key' => 1564,
  25. ),
  26. 3 => array(
  27. 'alias' => 'Gandalf',
  28. 'parent_id' => 2,
  29. 'model' => 'User',
  30. 'foreign_key' => 7419,
  31. ),
  32. 4 => array(
  33. 'alias' => 'Frodo',
  34. 'parent_id' => 3,
  35. 'model' => 'User',
  36. 'foreign_key' => 7451,
  37. ),
  38. 5 => array(
  39. 'alias' => 'Bilbo',
  40. 'parent_id' => 3,
  41. 'model' => 'User',
  42. 'foreign_key' => 5126,
  43. ),
  44. 6 => array(
  45. 'alias' => 'Merry',
  46. 'parent_id' => 3,
  47. 'model' => 'User',
  48. 'foreign_key' => 5144,
  49. ),
  50. 7 => array(
  51. 'alias' => 'Pippin',
  52. 'parent_id' => 3,
  53. 'model' => 'User',
  54. 'foreign_key' => 1211,
  55. ),
  56. 8 => array(
  57. 'alias' => 'Gollum',
  58. 'parent_id' => 4,
  59. 'model' => 'User',
  60. 'foreign_key' => 1337,
  61. ),
  62. );
  63. //Iterate and create AROs (as children)
  64. foreach($users as $data)
  65. {
  66. //Remember to call create() when saving in loops...
  67. $aro->create();
  68. //Save data
  69. $aro->save($data);
  70. }
  71. //Other action logic goes here...
  72. }

Typically you won't supply both an alias and a model/foreign_key, but we're using both here to make the structure of the tree easier to read for demonstration purposes.

The output of that console application command should now be a little more interesting. Let's give it a try:

$ cake acl view aro

Aro tree:
---------------------------------------------------------------
  [1]warriors

    [5]Aragorn

    [6]Legolas

    [7]Gimli

  [2]wizards

    [8]Gandalf

  [3]hobbits

    [9]Frodo

    [10]Bilbo

    [11]Merry

    [12]Pippin

  [4]visitors

    [13]Gollum

---------------------------------------------------------------

Now that we've got our ARO tree setup properly, let's discuss a possible approach for structuring an ACO tree. While we can structure more of an abstract representation of our ACO's, it's often more practical to model an ACO tree after Cake's Controller/Action setup. We've got five main objects we're handling in this Fellowship scenario, and the natural setup for that in a Cake application is a group of models, and ultimately the controllers that manipulate them. Past the controllers themselves, we'll want to control access to specific actions in those controllers.

Based on that idea, let's set up an ACO tree that will mimic a Cake app setup. Since we have five ACOs, we'll create an ACO tree that should end up looking something like the following:

  • Weapons
  • Rings
  • PorkChops
  • DiplomaticEfforts
  • Ales

One nice thing about a Cake ACL setup is that each ACO automatically contains four properties related to CRUD (create, read, update, and delete) actions. You can create children nodes under each of these five main ACOs, but using Cake's built in action management covers basic CRUD operations on a given object. Keeping this in mind will make your ACO trees smaller and easier to maintain. We'll see how these are used later on when we discuss how to assign permissions.

Since you're now a pro at adding AROs, use those same techniques to create this ACO tree. Create these upper level groups using the core Aco model.