<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gergely Hodicska &#187; zend framework</title>
	<atom:link href="http://blog.felho.hu/stock/php/zend-framework/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.felho.hu</link>
	<description>Random secrets of PHP, web development</description>
	<lastBuildDate>Fri, 30 Nov 2007 10:16:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Extending Zend_Acl to support custom roles and resources</title>
		<link>http://blog.felho.hu/extending-zend_acl-to-support-custom-roles-and-resources.html</link>
		<comments>http://blog.felho.hu/extending-zend_acl-to-support-custom-roles-and-resources.html#comments</comments>
		<pubDate>Thu, 29 Nov 2007 16:08:03 +0000</pubDate>
		<dc:creator>Felho</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend acl]]></category>

		<guid isPermaLink="false">http://blog.felho.hu/extending-zend_acl-to-support-custom-roles-and-resources.html</guid>
		<description><![CDATA[Few days ago I played a little with the Zend_Acl package, which provides lightweight and flexible access control list functionality and privileges management. It was very easy to use, but I found that the base Zend_Acl package has some limitation/problem if you want to use it in a bigger real life project. Zend_Acl supports only [...]]]></description>
			<content:encoded><![CDATA[<p>Few days ago I played a little with the Zend_Acl package, which provides lightweight and flexible access control list functionality and privileges management. It was very easy to use, but I found that the base Zend_Acl package has some limitation/problem if you want to use it in a bigger real life project. Zend_Acl supports only logical roles, resources so I decided to extend it to allow using custom roles and resources which can represent existing entities (for example users/groups and topics in a database). You will find the full source code and sample sql dump in the end of the post.<span id="more-56"></span></p>
<h2>Zend_Acl</h2>
<p>The package provides classical ACL functionality. There are roles, resources and privileges, and you can assign them to each other via deny and allow rules. For example you can say that <code>XY user</code>(role) is allowed to <code>moderate</code>(privilege) the <code>PHP topic</code>(resource) in a forum. You don&#8217;t have to always specify all the three part, for example you can say, that <code>administrator</code> can <code>moderate</code> any topic.</p>
<p>I won&#8217;t introduce the <code>Zend_Acl</code> package, it has an easy to understand <a href="http://framework.zend.com/manual/en/zend.acl.html" title="Zend_Acl's manual page">manual page</a>. Some observation which could be interesting related to this post:</p>
<ul>
<li>
There is no separate user and group in Zend_Acl, the concept of role includes both of them. A role can have multiple parents, so roles compose a directed graph.
</li>
<li>
Resources can have only one parent so they compose a tree.
</li>
</ul>
<h2>Zend_Acl limitations/problems</h2>
<p>Consider a forum where you have a lot of users/groups and a lot of resources (topics). You have have to add all of them (manually one at a time) to the <code>Acl</code> object which is very memory and time consuming task. Of course once you build the <code>Acl</code> object you can save it (in a serialized form) and reuse it next time but it will eat a lot of memory too. To make this clear check the following code:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><div class="php" style="font-family: monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #0000ff;">$acl</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Acl<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">addRole</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'guest'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; -&gt;<span style="color: #006600;">addRole</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'member'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; -&gt;<span style="color: #006600;">addRole</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'admin'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #0000ff;">$parents</span> = <span style="color: #000066;">array</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'guest'</span>, <span style="color: #ff0000;">'member'</span>, <span style="color: #ff0000;">'admin'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">addRole</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Role<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'someUser'</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #0000ff;">$parents</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">add</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Resource<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'someResource'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">deny</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'guest'</span>, <span style="color: #ff0000;">'someResource'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">allow</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'member'</span>, <span style="color: #ff0000;">'someResource'</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #000066;">echo</span> <span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'someUser'</span>, <span style="color: #ff0000;">'someResource'</span><span style="color: #66cc66;">&#41;</span> ? <span style="color: #ff0000;">'allowed'</span> : <span style="color: #ff0000;">'denied'</span>;<br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></table></div>

<p>You can see that if I want to reference a role or a resource in the <code>allow/deny</code> method, first I have to add it to the <code>Acl</code> object.</p>
<p>My other problem is that the Zend_Acl doesn&#8217;t support different type of roles/resources. Of course you can use a prefix, but maybe different roles/resources should be handled in a different way.</p>
<p>I wanted to come up with a solution where I have to define only the access rules and the Acl automatically checks if the referenced entity exists and automatically handles its relations (parent[s]), something like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><div class="php" style="font-family: monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #0000ff;">$acl</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Acl<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">deny</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'guest'</span>, <span style="color: #ff0000;">'someResource'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">allow</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'members'</span>, <span style="color: #ff0000;">'otherResource'</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #000066;">echo</span> <span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'someUser'</span>, <span style="color: #ff0000;">'someResource'</span><span style="color: #66cc66;">&#41;</span> ? <span style="color: #ff0000;">'allowed'</span> : <span style="color: #ff0000;">'denied'</span>;<br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></table></div>

<p>You may have immeditaley a problem with this code: how can we distinguish the different roles/resources? Yes, we need one more step to have enough felxibility:<br />
<?php<br />
$acl = new Zend_Acl();</p>
<p>$acl->deny(&#8216;group:guest&#8217;, &#8216;topic:membersonly&#8217;);</p>
<p>echo $acl->isAllowed(&#8216;user:someUser&#8217;, &#8216;topic:membersonly&#8217;) ? &#8216;allowed&#8217; : &#8216;denied&#8217;;<br />
?><br />
With this notation we can have any type of roles and resources. In a typical application you will have a user and a group roles, but you can have for example an ldapuser too.</p>
<h2>Foo_Acl</h2>
<p>After a little planning I find out the following structure:<br />
<a href="http://blog.felho.hu/wp-content/fooaclclassdiagram.png" title="Foo_Acl class diagram"><img src="http://blog.felho.hu/wp-content/fooaclclassdiagram497.png" alt="Foo_Acl class diagram" /></a></p>
<p>Zend_Acl has a RoleRegistry but I needed more functionality so I extended it. In Zend_Acl there is no ResourceRegistry, so I added to the Foo_Acl package, its functionality is very similar to the RoleRegistry. For both of them I defined an interface, they can handle any role/resource which implements it. This interfaces extends the proper interfaces in the Zend_Acl package, and defines some more basic functionality: getting the relation(s) of the role/resource and loading it. For example the Foo_Acl_Role_Interface is the following:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><div class="php" style="font-family: monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #808080; font-style: italic;">/**<br />
&nbsp;* Interface of custom roles, Foo_Acl_Role_Registry can handle an object which implements it.<br />
&nbsp;* &nbsp; <br />
&nbsp;* @category &nbsp; Foo<br />
&nbsp;* @package &nbsp; &nbsp;Foo_Acl<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">interface</span> Foo_Acl_Role_Interface <span style="color: #000000; font-weight: bold;">extends</span> Zend_Acl_Role_Interface<br />
<span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Returns the array of the identifier of th parent roles<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @return array<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getParents<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Returns the specified role if it exists or null. <br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @return Foo_Acl_Role_Interface<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066;">static</span> <span style="color: #000000; font-weight: bold;">function</span> load<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$resourceId</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #66cc66;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></table></div>

<p>The functionality of different roles/resources is very similar, so I created a default implementation for both of this interfaces, and you can easily create custom ones by extending it. The default implementation of the Foo_Acl_Role_Interface is the following:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
</pre></td><td class="code"><div class="php" style="font-family: monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #808080; font-style: italic;">/**<br />
&nbsp;* The base implementation of Foo_Acl_Role_Interface, custom roles can extend it.<br />
&nbsp;* <br />
&nbsp;* @category &nbsp; Foo<br />
&nbsp;* @package &nbsp; &nbsp;Foo_Acl<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">class</span> Foo_Acl_Role_CustomBase implements Foo_Acl_Role_Interface<br />
<span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Unique id of Role<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @var string<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; protected <span style="color: #0000ff;">$_roleType</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Unique id of Role<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @var string<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; protected <span style="color: #0000ff;">$_roleId</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Array of the identifiers of the Role's parents<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; protected <span style="color: #0000ff;">$_parents</span>;<br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Sets the Role data<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param &nbsp;string $id<br />
&nbsp; &nbsp; &nbsp;* @param &nbsp;array $parents<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* @return void<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$roleId</span>, <span style="color: #0000ff;">$parents</span> = <span style="color: #000066;">array</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$this</span>-&gt;_roleId = <span style="color: #66cc66;">&#40;</span>string<span style="color: #66cc66;">&#41;</span> <span style="color: #0000ff;">$roleId</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$this</span>-&gt;_parents = <span style="color: #0000ff;">$parents</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$className</span> = <span style="color: #000066;">get_class</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span><span style="color: #66cc66;">&#41;</span>; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$this</span>-&gt;_roleType = <span style="color: #000066;">strtolower</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066;">substr</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$className</span>, <span style="color: #000066;">strrpos</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$className</span>, <span style="color: #ff0000;">'_'</span><span style="color: #66cc66;">&#41;</span><span style="color: #cc66cc;">+1</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Defined by Zend_Acl_Role_Interface; returns the Role identifier<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @return string<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getRoleId<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>-&gt;_roleType.<span style="color: #ff0000;">':'</span>.<span style="color: #0000ff;">$this</span>-&gt;_roleId;<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Defined by Foo_Acl_Role_Interface; returns the Role's parents<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @return array<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getParents<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>-&gt;_parents;<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Returns the specified role if it exists or null. <br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @return Foo_Acl_Role_Interface<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066;">static</span> <span style="color: #000000; font-weight: bold;">function</span> load<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$roleId</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">null</span>;<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
<span style="color: #66cc66;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></table></div>

<p>If you want to create a custom role you should extend this class and overwrite the load function which responsibility is to check if the specified role exists and to instantiate the proper role object. I wrote some sample custom rules, the following is for representing users:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre></td><td class="code"><div class="php" style="font-family: monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #808080; font-style: italic;">/**<br />
&nbsp;* Custom role representing users in the forum.<br />
&nbsp;* <br />
&nbsp;* @category &nbsp; Foo<br />
&nbsp;* @package &nbsp; &nbsp;Foo_Acl<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">class</span> Foo_Acl_Role_Custom_User <span style="color: #000000; font-weight: bold;">extends</span> Foo_Acl_Role_CustomBase<br />
<span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Returns the specified role if it exists or null.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @return Foo_Acl_Role_Interface<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066;">static</span> <span style="color: #000000; font-weight: bold;">function</span> load<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$roleId</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">// For more flexibility we support to refer a role with its name.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$lookUpByName</span> = !<span style="color: #000066;">ctype_digit</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$roleId</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp;if ($cache = Foo_Cache_Factory::getInstance()) {</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ($lookUpByName) {</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ($storedRoleId = $cache-&gt;fetch('acl.role.user.name2id.'.$roleId)) {</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$roleId = $storedRoleId;</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ($storedRole = $cache-&gt;fetch('acl.role.user.obj.'.$roleId)) {</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return &nbsp;$storedRole;</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$query</span> = <span style="color: #0000ff;">$lookUpByName</span> ?<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">'SELECT u.user_id, g.group_id FROM user u LEFT JOIN user2group g ON u.user_id = g.user_id WHERE u.nickname = ?'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">'SELECT u.user_id, g.group_id FROM user u LEFT JOIN user2group g ON u.user_id = g.user_id WHERE u.user_id = ?'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$rows</span> = <span style="color: #0000ff;">$GLOBALS</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'DB'</span><span style="color: #66cc66;">&#93;</span>-&gt;<span style="color: #006600;">getAll</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$query</span>, <span style="color: #000066;">array</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$roleId</span><span style="color: #66cc66;">&#41;</span>, DB_FETCHMODE_ASSOC<span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$rows</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$parents</span> = <span style="color: #000066;">array</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">// If the user belongs to some groups we set them as its parents.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>!<span style="color: #000066;">is_null</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$rows</span><span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'group_id'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$rows</span> <span style="color: #b1b100;">as</span> <span style="color: #0000ff;">$row</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$parents</span><span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span> = Foo_Acl_Role_Custom_Group::<span style="color: #006600;">load</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$row</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'group_id'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$lookUpByName</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ($cache) {</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$cache-&gt;store('acl.role.user.name2id.'.$roleId, $row['user_id'], 1800);</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$roleId</span> = <span style="color: #0000ff;">$row</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'user_id'</span><span style="color: #66cc66;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$role</span> = <span style="color: #000000; font-weight: bold;">new</span> self<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$roleId</span>, <span style="color: #0000ff;">$parents</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ($cache) {</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$cache-&gt;store('acl.role.user.obj.'.$roleId, $role, 1800);</span><br />
<span style="color: #808080; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$role</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">null</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
<span style="color: #66cc66;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></table></div>

<p>You can see it is very straightforward to create a new role. I commented out the caching codes because I am in changing the cache implementations and I could not put it to sample code.</p>
<p>The Foo_Acl package provide an effective and convenient way to handle a huge number of entity:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
</pre></td><td class="code"><div class="php" style="font-family: monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<br />
<span style="color: #808080; font-style: italic;">//insert into topic values(1, null);</span><br />
<span style="color: #808080; font-style: italic;">//insert into topic values(2, null);</span><br />
<span style="color: #808080; font-style: italic;">//insert into topic values(3, null);</span><br />
<span style="color: #808080; font-style: italic;">//insert into topic values(4, 1);</span><br />
<span style="color: #808080; font-style: italic;">//insert into topic values(5, 2);</span><br />
<span style="color: #808080; font-style: italic;">//insert into topic values(6, 4);</span><br />
<span style="color: #808080; font-style: italic;">//insert into user_group values(1, 'group1');</span><br />
<span style="color: #808080; font-style: italic;">//insert into user_group values(2, 'group2');</span><br />
<span style="color: #808080; font-style: italic;">//insert into user values(1, 'user1');</span><br />
<span style="color: #808080; font-style: italic;">//insert into user values(2, 'user2');</span><br />
<span style="color: #808080; font-style: italic;">//insert into user values(3, 'user3');</span><br />
<span style="color: #808080; font-style: italic;">//insert into user values(4, 'user4');</span><br />
<span style="color: #808080; font-style: italic;">//insert into user2group values (1,1);</span><br />
<span style="color: #808080; font-style: italic;">//insert into user2group values (2,1);</span><br />
<span style="color: #808080; font-style: italic;">//insert into user2group values (3,2);</span><br />
<span style="color: #808080; font-style: italic;">//insert into user2group values (4,2);</span><br />
<br />
<span style="color: #0000ff;">$acl</span> = <span style="color: #000000; font-weight: bold;">new</span> Foo_Acl<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">allow</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:1'</span>, <span style="color: #ff0000;">'dummy:foo'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:1'</span>, <span style="color: #ff0000;">'dummy:foo'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// true</span><br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:1'</span>, <span style="color: #ff0000;">'dummy:bar'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// flase</span><br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">allow</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'group:group1'</span>, <span style="color: #ff0000;">'dummy:coverpage'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:user2'</span>, <span style="color: #ff0000;">'dummy:coverpage'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// true</span><br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:user3'</span>, <span style="color: #ff0000;">'dummy:coverpage'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// flase</span><br />
<br />
<span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">allow</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'group:group1'</span>, <span style="color: #ff0000;">'hierarchy:1'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:1'</span>, <span style="color: #ff0000;">'hierarchy:4'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// true</span><br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:2'</span>, <span style="color: #ff0000;">'hierarchy:6'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// true</span><br />
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$acl</span>-&gt;<span style="color: #006600;">isAllowed</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'user:1'</span>, <span style="color: #ff0000;">'hierarchy:2'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// flase</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></table></div>

<p>I tested it on the database of a bigger forum and it worked very well. You can download the <a href='http://blog.felho.hu/wp-content/fooacl.zip' title='Source code of Foo_Acl package and some sample code.'>sample code here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.felho.hu/extending-zend_acl-to-support-custom-roles-and-resources.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>


