<?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>HirdWeb &#187; cakePHP</title>
	<atom:link href="http://www.hirdweb.com/tag/cakephp/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hirdweb.com</link>
	<description>Another Blog clogging up the already crowded internet</description>
	<lastBuildDate>Wed, 28 Jul 2010 16:05:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>PEAR and CakePHP</title>
		<link>http://www.hirdweb.com/2009/05/04/pear-and-cakephp/</link>
		<comments>http://www.hirdweb.com/2009/05/04/pear-and-cakephp/#comments</comments>
		<pubDate>Tue, 05 May 2009 02:23:41 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[PEAR]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=185</guid>
		<description><![CDATA[This post is about my experience with loading in PEAR to a CakePHP 1.2.x application. This may be the right way or the wrong way, but I got it to work throughout the application. I had to do some changes, and if there is a better way of doing this, please let me know. First [...]]]></description>
			<content:encoded><![CDATA[<p>This post is about my experience with loading in PEAR to a CakePHP 1.2.x application. This may be the right way or the wrong way, but I got it to work throughout the application. I had to do some changes, and if there is a better way of doing this, please let me know. </p>
<p>First off, here is the issue. I needed to be able to export a group of records from the database to an excel spreadsheet. I have tried to use the <a href="http://bakery.cakephp.org/articles/view/excel-xls-helper" target="_blank">Excel Spreadsheet add in that is listed on the Bakery</a>. It works nice, and I had to do some modification for 1.2, but it worked. But not the way I wanted it. I have used the PEAR library Spreadsheet_Excel_Writer before and I like the type of control that I wanted, over the cells, the formatting, the merging, etc etc etc. It provides the type of control that I wanted. So here is what I did to get this to work with the CakePHP framework. </p>
<p>First, I have to download the PEAR library and the Spreadsheet_Excel_Writer libraries to use. Since I use a local system to help develop, I could download these libraries to the local system and transport these over to the CakePHP application. So I went to PEAR site to get the libraries. To download these I ran the following commands:</p>
<pre>
pear install PEAR-1.8.1
pear install OLE-1.0.0RC1
pear install Spreadsheet_Excel_Writer-0.9.1
</pre>
<p>URL&#8217;s are listed below:</p>
<p>http://pear.php.net/package/PEAR/download</p>
<p>http://pear.php.net/package/Spreadsheet_Excel_Writer/download</p>
<p>http://pear.php.net/package/OLE/download</p>
<p><span id="more-185"></span><br />
These downloaded the to local drives and I copied them over to the CakePHP area. Here is where it gets a little tricky. And I thank &#8220;brian&#8221; who helped me on the <a href="http://groups.google.com/group/cake-php">Cake Google group</a> to get past this when I got into a problem. So here we go, diving in to this. </p>
<p>First off, the PEAR libraries need to be put in the vendors directory. If you look at the directory structure for Cake, it appears like this:<br />
/app<br />
/cake<br />
/vendors</p>
<p>Inside of the /app directory, there is another vendors directory. This is where I put the PEAR libraries. This causes problems, because in the /cake/config/paths.php file, there is a path defined for VENDORS, and for PEAR:</p>
<pre>
if (!defined('VENDORS')) {
	define('VENDORS', CAKE_CORE_INCLUDE_PATH.DS.'vendors'.DS);
}

define('PEAR', VENDORS.'Pear'.DS);
</pre>
<p>Now, I have put the PEAR libraries in the top level vendor directory. If you choose to put it in the app/vendors directory, then you may need to change a core file, which is not advisable, because you would need to change the path above to</p>
<pre>
if (!defined('VENDORS')) {
	define('VENDORS', CAKE_CORE_INCLUDE_PATH.DS.'app/vendors'.DS);
}
</pre>
<p>So back to the PEAR libraries. Here is what I needed to do. I moved the PEAR directories to the /vendors directory. So here is what that directory looks like:</p>
<pre>
/vendors
    /css
    /js
   /Pear   <--- Look at this, case sensitive based on those paths above
        /OLE
        /OS
        /PEAR
        /scripts
        /Spreadsheet
        INSTALL
        LICENSE
        OLE.php
        package.dtd
        PEAR.php
        PEAR5.php
        README
        System.php
        template.spec
    /shells
</pre>
<p>This is part of the PEAR install we need to do. Now we need to update the paths in some of these files so that CakePHP can find them and include them. </p>
<p>**** ORIGINAL ENTRY THAT HAS BEEN EDITED/DEPRECATED ********************<br />
**** EDIT: Based on the original post this is the method I originally used. This way works, but requires a<br />
**** little too much overhead and editing the files in the PEAR libraries which is never really a good idea<br />
**** and should only be used sparingly. To see the way that it should be done, please see below this<br />
**** section.<br />
****<br />
**** In the file /vendors/Pear/Spreadsheet/Excel/Writer.php there is 2 requires<br />
**** require_once 'PEAR.php';<br />
**** require_once 'Spreadsheet/Excel/Writer/Workbook.php';<br />
****<br />
**** In order for the Cake App to see these, at least in my set up, I needed to change these to the<br />
**** following:<br />
**** require_once 'PEAR.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Workbook.php';<br />
****<br />
**** I needed to add "PEAR . " to the require_once call. Now I needed to add this to the following files:<br />
**** /vendors/Pear/Spreadsheet/Excel/Writer.php<br />
**** require_once 'PEAR.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Workbook.php';<br />
****<br />
**** /vendors/Pear/Spreadsheet/Excel/Writer/Workbook.php<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Format.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/BIFFwriter.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Worksheet.php';<br />
**** require_once PEAR . 'Spreadsheet/Excel/Writer/Parser.php';<br />
**** require_once PEAR . 'OLE/PPS/Root.php';<br />
**** require_once PEAR . 'OLE/PPS/File.php';<br />
****<br />
**** /vendors/Pear/OLE/PPS.php<br />
**** require_once 'PEAR.php';<br />
**** require_once PEAR . 'OLE.php';<br />
****<br />
**** This had helped the application find my PEAR libraries when trying to do this<br />
**** END ORIGINAL ENTRY ***********************************************</p>
<p><strong><em>Now, a word about the edit. The above method works, but is not a preferred method. The best method for this, so there is no need to edit PEAR library files is the following. And a big thanks to <a href="http://cakebaker.42dh.com/">Daniel Hofstetter</a> for pointing this out. </em></strong></p>
<p>I put this at the top of my controller file. I am sure there is better places for this, probably even the app_controller file so that all controllers get the needed include path set. Here is what I did. </p>
<p>I needed to append the include path so that the new PEAR path would be found. After the php opening, I added this line:</p>
<pre>
ini_set("include_path", PEAR . PATH_SEPARATOR . ini_get("include_path"));
</pre>
<p>I am going to go over this just a little. First off, the ini_set is called to set the include_path. But we do not want to destroy any other include paths that are set up as well. So when we add the PEAR path, we need to also include the other paths as well. So the initial include_path was as follows (given in example form only, where the directory "test" is where I have CakePHP installed)<br />
ini_get("include_path") = </p>
<pre>
/www/htdocs/html/test:/www/htdocs/html/test/app/:.:/usr/local/php5/lib/php
</pre>
<p>Since CakePHP already defines the variable for the PEAR path as "PEAR", we can use that to add to the include path, like shown above. After setting the path using ini_set(), we run ini_get("include_path") it would = </p>
<pre>
/www/htdocs/html/test/vendors/Pear/:/www/htdocs/html/test:/www/htdocs/html/test/app/:.:/usr/local/php5/lib/php
</pre>
<p>By doing it this way, there is no need to edit the PEAR library files, and we can add new PEAR libraries without having to worry about editing those files as well. </p>
<p>Now, I needed to make the controller aware of the vendor library. In my controller file I added this line before the class declaration:</p>
<pre>
App::import('vendor', 'Spreadsheet_Excel_Writer', array('file' => '../vendors/Pear/Spreadsheet/Excel/Writer.php'));
</pre>
<p>In Cake 1.2, this is how the vendor's are imported. The vendor() declaration has been deprecated. This imports a vendor, gives the class a name (I choose the base one that it is usually called), and the location of the of the file. In my set up, I needed to add the "../", you may not have to. </p>
<p>In the function, (I called "export"), I did not want to have a "view" page for it. The first thing I did was grab the information I needed. For this example, I needed all users that signed up for a conference. So I grabbed that information and put it in an array $registrations. </p>
<pre>
function export ($id = null){
       // I only want to get a specific conference, not all of them
	if ( $id == 'all' ){
		$this->Session->setFlash('Please select a specific conference to export the registrations.');
		$this->redirect(array('action' => 'index'));
	}

	// Now get the registrations for the conference
	$registrations = $this->Registration->find('all',
		array(
			'conditions' => array('conference_id' => $id),
			'fields' => array('*'),
			'recursive' => '-1',
			'order' => array('Registration.created'),
		)
	);
</pre>
<p>Now comes the fun part, building the column heading array, and then instantiating the writer</p>
<pre>
	// Set up the header array
	$titles = array(
		'Name' => 15,
		'Address' => 20,
		'City' => 20,
		'State' => 7,
		'Zip Code' => 10,
		'Email' => 20,
		'Phone' => 13,
	);

	$rn = 0; // row number
	// Build the XLS file using PEAR
	$xlsBook = new Spreadsheet_Excel_Writer();
	$xlsBook->send("registrations.xls");
	$xls =&#038; $xlsBook->addWorksheet('Registrations');
</pre>
<p>Everything else is now just as the same as it would be with the Spreadsheet-Excel_writer. Create the formats as you would like, for text, numerics, specialized strings, colors, etc. Write the sheet headings, if you so desire</p>
<pre>
	/* Create styles for the spreadsheet */
	$format_bold =&#038; $xlsBook->addFormat();
	$format_bold->setBold();

	$main =&#038; $xlsBook->addFormat(
		array('Size' => 14,
			'Align' => 'center',
			'Color' => 'black',
			'Bold' => 'true'
		));
	$main->setBold();

	$formatText =&#038; $xlsBook->addFormat(array('Size' => 11));

	$cn = 0;
	$xls->write($rn, 0, "CONFERENCE REGISTRATIONS", $main);
	$xls->mergeCells($rn,0,$rn,11);
	$rn++;
</pre>
<p>As you can see, just use the writer calls to write the data, format it, and do what you need. To get more information on this, please <a href="http://pear.php.net/package/Spreadsheet_Excel_Writer/docs">check the PEAR documentation for this library</a>. </p>
<p>Finish up the column headings by doing a quick little loop</p>
<pre>
	// Set up the headings of the columns
	foreach ( $titles as $t => $val){
		$xls->setColumn($cn, $cn, $val);
		$xls->write($rn, $cn++, $t, $format_bold);
	}
	$rn++;
	// reset the column num
	$cn = 0;
</pre>
<p>Now you can do the actual rows in a loop:</p>
<pre>
	foreach ( $registrations as $r ){
		$xls->write($rn, $cn++, $r['Registration']['name'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['address'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['city'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['state'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['zip_code'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['email'], $formatText);
	    $xls->write($rn, $cn++, $r['Registration']['contact_phone1'], $formatText);
	    // cycle to the next row
	    $rn++;
	    // Reset the column
	    $cn = 0;
	}

	$xlsBook->close();
	exit();
} // end of function
</pre>
<p>Now, this does the work for me on my code. To call it in the view, I have a page that shows all registrations on the page, the function name is "registrations". I set a variable in this function for the ID number to be passed to the view. In the view for this function, I have put the following:</p>
<pre>
if ( $param != 'all') {
	echo "&lt;p&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - - &lt;b&gt;";
	echo $html->link(__('EXPORT DATA', true), array('action' => 'export', $param) );
	echo "&lt;/b&gt; - - &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;";
}
</pre>
<p>So I want a specific conference. If there is not one, and they are viewing all registrations for all conferences, then it does not show the link. But if it is a specific id, then it shows the link to export with the corresponding parameter for the ID. </p>
<p>And there it is. Using the Spreadsheet_Excel_Writer PEAR library with CakePHP 1.2. </p>
<p>Again, this works for me, and there may be a better way of doing things, and if so, please feel free to tell me. I am always looking for new things to learn. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2009/05/04/pear-and-cakephp/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Regular Expressions</title>
		<link>http://www.hirdweb.com/2009/04/05/regular-expressions/</link>
		<comments>http://www.hirdweb.com/2009/04/05/regular-expressions/#comments</comments>
		<pubDate>Mon, 06 Apr 2009 01:55:06 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=168</guid>
		<description><![CDATA[Here is a topic that has really flustered a lot of developers. Regular expressions is a concept that can be hard to get a real handle on. PHP has a couple of functions that can help do regular expressions. The one I focus on most is using the function: preg_match() This is a very useful [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a topic that has really flustered a lot of developers. Regular expressions is a concept that can be hard to get a real handle on. PHP has a couple of functions that can help do regular expressions. The one I focus on most is using the function:<br />
preg_match()</p>
<p>This is a very useful tool, and if you look at the <a href="http://us3.php.net/manual/en/function.ereg.php">PHP manual for ereg()</a>, it states that the function &#8220;preg_match&#8221; is a faster alternative to &#8220;ereg()&#8221;. Now while I am not going to get into the details of the speed and response times for both functions, as there will always be someone with a different opinion or case that shows how their way is better, and that is fine. What most people have a hard time dealing with is getting the actual match to do what is needed. There are times when It is just easier to do a Google search and get some code that someone else has already done and plug it in. But the real power is knowing what you are doing first, that way you can build your own.</p>
<p>For this example, we can take a look at CakePHP&#8217;s own little validation object. When you set up a model and add some validation to it, it calls this object. Based on the data that this going into the tables, it will call one of these functions. The way these functions work is by checking the input for a specific character list/set that should be contained in the text. If the entry does not match up, then it is not validated. The way CakePHp does this is by using the preg_match() function.<br />
<span id="more-168"></span></p>
<p>If you are new to regular expressions, then seeing something like this:</p>
<pre>
define('VALID_EMAIL', "/^[a-z0-9!#$%&#038;'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&#038;'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[a-z]{2,4}|museum|travel)$/i");
</pre>
<p>may be a little scary. But never fear, this is not as bad as it seems. It just looks real scary. And besides, even Cake made it a little better. </p>
<p>So let&#8217;s look at this function:</p>
<pre>
function email($check, $deep = false, $regex = null) {
. . .
	if (is_null($_this->regex)) {
		$_this->regex = '/^[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+)*@' . $_this->__pattern['hostname'] . '$/i';
	}
	$return = $_this->_check();
. . .
}

function _check() {
. . .
	if (preg_match($_this->regex, $_this->check)) {
		$_this->error[] = false;
		return true;
	} else {
		$_this->error[] = true;
		return false;
	}
}
</pre>
<p><em>If you would like to know more about the function, then please browse to the CakePHP manual to get more info about that function, since all this is going to do is point out the regex part of it. </em></p>
<p>First off, the function called is &#8220;email&#8221;. In this function, there is a regex match set that is the following:<br />
&#8216;/^[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+)*@&#8217; . $_this->__pattern['hostname'] . &#8216;$/i&#8217;</p>
<p>It passes that to the _check() function, which puts this regex pattern to the email address that is entered to see if there is a match. So to jump ahead if someone were to put in an email address of:<br />
 &#8211; flavio@nothing.com<br />
It would pass that function. (NOTE: this does not mean it is a valid email address that can recieve emails, it just means that the characters in the email address are in the valid format of (address_name)@(hostname).(Extension) )</p>
<p>But this also means that someone could put in the email address:<br />
 &#8211; flavio@nothing.show<br />
And that would pass as well, while the following email addresses:<br />
 &#8211; flavio<br />
 &#8211; flavio@nothing<br />
 &#8211; flavioATnothingDOTcom<br />
would fail. </p>
<p>But now that we know that, how did we get there? </p>
<p>Let&#8217;s break down the match. </p>
<p>The first thing, we are looking for a pattern, so we need to ad the following:<br />
/ /<br />
around the pattern. This is a Perl syntax that is followed for finding patterns. Now the bookends come, with the caret ( ^) and the dollar sign ( $ ). The caret means to search the beginning of the string for the pattern, and the dollar sign matches the end of the string. In this example, the caret matches the first part of the email address entered, and the dollar sign matches the end. </p>
<pre>
'/^[ ]$/'
</pre>
<p>So we are off to a good start. but there since we are looking for a pattern that does not need to be case sensitive, as we do not care if there are uppercase letters or not, we need to add an &#8220;i&#8221; at the end. </p>
<pre>
'/^[ ]$/i'
</pre>
<p>Now we are ready to start looking at the beginning of the string. We are going to put this in a bracket to group the characters, or create a class. We want to get any valid characters for an email address. This would include any letters, numbers and some special characters. We will need to escape some of these (using the &#8220;\&#8221; to escape)</p>
<pre>
'/^[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]$/i'
</pre>
<p>This will now look for the address name, sort of. As long as there are no periods in the address account name, it will work, but there are addresses out there that have a &#8220;.&#8221; in it:<br />
 &#8211; flavio.elguappo@nothing.com<br />
would not pass the validation as of yet (given that we would have also added the domain by the time it is checked). </p>
<p>So we need to add that match set in to the expression. CakePHP does this by using an atomic grouping. Using the parenthesis usually means that a &#8220;backreference&#8221; should be done. You can escape this by using &#8220;?:&#8221;. The question mark-colon combo after the first parenthesis signifies that what is coming is not a backreference. Now, to get the addresses that have a period in the account name we add this:<br />
(?:\.[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+)</p>
<p>As you can see, this is almost the same pattern as before. We want to check the same things again after any appearance of a period. So now it looks like:</p>
<pre>
'/^[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+)$/i'
</pre>
<p>Last things here, we need to account for the @ symbol in the address, and add the domain name. Since CakePHP already takes care of that, they have there own addition:</p>
<pre>
'/^[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+)*@' . $_this->__pattern['hostname'] . '$/i'
</pre>
<p>And the final php code would be as follows:</p>
<pre>
$checked = preg_match('/^[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&#038;\'*+\/=?^_`{|}~-]+)*@' . $_this->__pattern['hostname'] . '$/i', $email_address_to_check);

return $checked;
</pre>
<p>Now I am sure I glossed over some regex rules and explanations. I will never claim to be an expert on regex, as I am still learning as much as I can about this. Now this is not the only way to check an email address. If you do not use CakePHP and the real nifty built in helper, then you can use this one:</p>
<pre>
"/^[^0-9][A-z0-9_]+([.][A-z0-9_]+)*[@][A-z0-9_]+([.][A-z0-9_]+)*[.][A-z]{2,4}$/"
</pre>
<p>This one is similar, check the account name for valid characters, see if it has any periods in the name, check the @ symbol and then check the domain name, and then the domain extension, allowing for 2-4 characters in the extension. </p>
<p>And if you want to get some real good info on other regex info, here are a couple of links I found useful:<br />
<a href="http://www.webcheatsheet.com/php/regular_expressions.php">http://www.webcheatsheet.com/php/regular_expressions.php</a><br />
<a href="http://www.regular-expressions.info/tutorial.html">http://www.regular-expressions.info/tutorial.html</a><br />
<a href="http://us3.php.net/manual/en/function.preg-match.php">http://us3.php.net/manual/en/function.preg-match.php</a><br />
(Make sure you read the comments as they have some good info)</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2009/04/05/regular-expressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP and Symfony</title>
		<link>http://www.hirdweb.com/2009/03/02/cakephp-and-symfony/</link>
		<comments>http://www.hirdweb.com/2009/03/02/cakephp-and-symfony/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 04:02:05 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=158</guid>
		<description><![CDATA[There are many frameworks out there that have a good deal of uses to them. In this post, the focus is on CakePHP vs Symfony. Does this mean one will be a winner over the other? Not really. I will only present what I have come to find in each of these frameworks and how [...]]]></description>
			<content:encoded><![CDATA[<p>There are many frameworks out there that have a good deal of uses to them. In this post, the focus is on CakePHP vs Symfony. Does this mean one will be a winner over the other? Not really. I will only present what I have come to find in each of these frameworks and how I have used them in different ways.</p>
<p>Since this will be a comparison, most of the ideas will revolve around the tutorials that each camp has created. Plus, I will be only looking at the latest stable versions, so they are:<br />
CakePHP: 1.2.1.8004<br />
Symfony: 1.2</p>
<p>Each have their own tutorials, and they are at the following:<br />
Symfony: <a href='http://www.symfony-project.org/jobeet/1_2/Propel/en/01' target='_blank' title='Jobeet Tutorial'>Jobeet Tutorial</a>, using Propel.<br />
CakePHP: <a href='http://book.cakephp.org/view/219/Blog' target='_blank' title='CakePHP Blog'>CakePHP Blog</a></p>
<p><strong>First off, about the tutorials. </strong><br />
I really do think that Symfony has a better tutorial. It is a lot more intensive and sometimes confusing, which means it also goes more in depth about what this framework can do, and how to do it. This tutorial also brings in a good deal of real world dilemmas. </p>
<p>CakePHP&#8217;s blog tutorial is just a standard blog tutorial, which everyone seems to have anymore. It is a good tutorial, and it does show off some real good aspects of the framework, but it really does lack some of the &#8220;gotchas&#8221; that would really happen in the real world.<br />
<span id="more-158"></span></p>
<p><strong>Installation Process and Upgrade</strong><br />
Symfony &#8211; Getting Symfony is pretty easy. You can download it from the site in a &#8220;sandbox&#8221; form. It is pretty easy and able to do much right from the download. But what makes this framework so wonderful about getting it, is that you can use PEAR to download it. By following the <a href='http://www.symfony-project.org/installation/1_2' target='_blank' title='Symfony Detailed Installation Instructions'>detailed installation instructions</a>, there are a few different ways to install this. If you have the PEAR libraries, it makes it very easy to install and upgrade. </p>
<p>CakePHP &#8211; <a href='http://book.cakephp.org/view/32/Installation' target='_blank' title='CakePHP Installation'>Getting CakePHP is also easy</a>. While it does not have a PEAR installation path, the zip file is available in many forms, like .zip, or .gz, bz2, or .dmg. After you unzip the file, just plop it in the web accessible document root. It will work right out of the box provided on most systems. It is supposed to work right away with mod_rewrite, so certain Windows systems may have issues. (However, I have loaded it on a Windows Vista system and it worked ok, so take that for what it is worth). The directory structure allows it to work right away as is. However, the webroot  app can be moved outside the normal directory structure to make a different configuration. Upgrading can be done as well, usually by overwriting the /cake directory.</p>
<p>But as with everything, always follow directions on upgrading. Very important. </p>
<p><strong>Basic Ideals Behind the Framework</strong><br />
Symfony &#8211; Using a basic MVC (Model-View-Controller) design theory, it really does separate the logic portions of the application. By using the built in view, it keeps the majority of the PHP out of the HTML area. The models use more of a YAML approach to build the data objectivity. YAML (YAML Ain&#8217;t a Markup Language, morphed from Yet Another Markup Language). It can use Propel or Doctrine to help in this. The Jobeet tutorial I used was the Propel version. The controller is a standard idea of what you would expect in a controller. </p>
<p>CakePHP &#8211; Uses a MVC design theory, and really follows the same patterns. The real strength of CakePHP, at least to me, is it does not mess around with another version of data markup, like YAML. Some people like it, I do not prefer it. So to me this is better. However, the model also provides a real easy way to provide data validation for each row in the table. By using basic PHP concepts, you can set up validation for inserts and/or updates. The view is a little less robust than the Symfony version. While it does help with different pages/views, the framework does have a little too much reliance on php generated code. However, it does have excellent helpers to help generate HTML, forms, tables, etc. </p>
<p><strong>Routing and Fancy URLs</strong><br />
Symfony &#8211; By updating the file: apps/frontend/config/routing.yml (yes it uses another YAML format) you can route certain calls to certain pages. However, this makes it real easy to create Fancy URLs in which the URL actually has some real data in it instead of something like : &#8216;jobs/2/34&#8242;. </p>
<p>CakePHP &#8211; In order to create Fancy URLs, CakePHP needs to have the default routes updated. While it is not as easy as it is in Symfony, it is possible. By using the <a href='http://book.cakephp.org/view/46/Routes-Configuration' target='_blank' title='Routes Configuration'>detailed instructions</a> in the Cookbook, you can set this up to have the nice URLs. </p>
<p><strong>Command Line Interface Utilities</strong><br />
Symfony &#8211; Now while this is not an instructional post on how to use each CLI, I must say, I like the Symfony version a lot better. While it is clean and real forthcoming, there is a lot you can do with it. Combine that with the Propel and you have a really good CLI tool to help with the application. </p>
<p>CakePHP &#8211; The CLI in CakePHP leaves a little to be desired. While it is very helpful in creating the Models, the Controllers, and the Views, it really does not do as much. But for CakePHP this is actually ok. There are a lot of things to do with the CLI, but not as much as Symfony has.</p>
<p><strong>Configuration</strong><br />
Symfony &#8211; Symfony seems to thrive on configurations for some reason. There is a whole directory dedicated to just config files. To me this seems a bit of overkill to do it this way. However, with the way Symfony is laid out, it works this way. There are different things to configure, and following the instructions is key. Especially since these files are read from top to bottom, so if you have a custom config in the routes after the default entry, it will never find the custom one. </p>
<p>CakePHP &#8211; There is also a full directory dedicated to configurations as well, but less files to parse through. Some may say this is a bad thing, some may say this is a good thing. The main files to look at are the core.php and database.php files. The routes.php file is also useful, but all in all, less config files to deal with. </p>
<p><strong>Naming Conventions</strong><br />
Instead of separating this area, it is important to note that with each framework, there is a reason behind the madness with naming conventions. By adhering to these conventions, the framework works a lot better and can do a lot more. </p>
<p>In Symfony there is more leeway with file names, tables, etc. </p>
<p>In CakePHP they are a bit more strict, but these conventions can also be bent to suit the needs. </p>
<p><strong>Core Components</strong><br />
Symfony &#8211; There is a good deal of components in this framework, and they all have a set purpose. Instead of matching each one as a 1:1 deal, it is important to go over the usability of these components. In Symfony, there are good ones to help paginate, create sessions, scaffold an application and even do security. Using these is easy, and this is one area where both frameworks excel.  </p>
<p>CakePHP &#8211; Again, this is a great area for both frameworks. While in CakePHP, the components are not limited to the core ones, but can be extended (as in Symfony), they are very useful in helping create the application. These components are very helpful and can be a boon to even the novice programmer. </p>
<p>Both of these frameworks use these components to help speed the application up while not giving in to shoddy work. </p>
<p><strong>Testing</strong><br />
Symfony &#8211; The great thing about Symfony, is that it has a built in testing platform. The testing platform it includes is Lime. This is a great boost to development. Now while writing the application, you can actually write the test first, then the application to make sure you know which area needs more attention. Both Unit and Functional testing is handled, and can work with others like PHPUnit and Selenium. </p>
<p>CakePHP &#8211; one of the great things about this framework, is that you can choose which testing platform to use. The drawback to that is, you do not get a testing platform with the package. However, it is encouraged to use SimpleTest to do this. Installation is another step, but it helps to test the application. Writing the tests is a little more than what it takes in Symfony, however, I also believe that it does testing better than Symfony. </p>
<p><strong>Security</strong><br />
Here is a question for any and all frameworks. How secure is it? well this can be answered with the following question:<br />
How secure are you writing this application?</p>
<p>Even though Symfony and CakePHP provide good methods, components and helpers to handle securing your application, you have to use these, and use them correctly. Both proved ACL implementations, data validation and sanitation and much more to help secure the app. For any one to make a statement that one framework is more secure than the other, is just not getting the point of security. </p>
<p><strong>Documentation</strong><br />
Symfony &#8211; By far, this is the more documented framework. I have been able to find a ton of information on Symfony questions. The documentation in the cookbook is solid, and the tutorial is better than anything I have seen from other frameworks. There are other groups, IRC channels and other avenues to explore to help you get the info you need. </p>
<p>CakePHP &#8211; This framework is still coming of age. So the documentation is not always complete and not always found right away. There are groups, IRC channels and other avenues to get this information, just not as plentiful. However, that will change very shortly. With a stronger emphasis on community events and community submissions, this framework could easily have a plethora od documentation avenues by next year. </p>
<p><em>**NOTE: The following is based on my own personal experience.<br />
As mentioned in the comments below, CakePHP does have stats to show it is bigger and more popular than Symfony. Please see Nate&#8217;s comments below for the links.</em></p>
<p><strong>Community</strong><br />
Symfony &#8211; With many sites already using Symfony, the community is growing like wildfire. It was already a very abundant community, with many people helping and contributing. As with every open source project, it is only as strong as its community, which is very active. </p>
<p>CakePHP &#8211; <del datetime="2009-05-21T13:05:57+00:00">This is the up and comer. Not quite as widespread as Symfony, but it has it very loyal followers.</del> There are many ways that a community member can help out (and not just by donating), and this community is really rising fast to help meet the demand for more events and more documentation. </p>
<p><strong>Final Analysis</strong><br />
While I will not give a clear cut answer as to which is the better framework, because the best solution is the solution that will meet the needs of the business/client/etc. Sometimes that may be Symfony, sometimes it may be CakePHP. Sometimes it may just be .ASPX. But there is no real clear cut winner in my mind. </p>
<p>I have used both frameworks to develop applications. Some of them huge, some of them small. I find CakePHP easier to start up from the ground up. And I find the extensibility of Symfony really helpful in certain apps that require a lot of redundant user input. Both frameworks are great. I would use both of them all the time for different things. </p>
<p>Which also means that I am no expert in either one. Since I spend time in both frameworks, I know what I like and do not like about each of them. I would also wager to say that no one is really an expert in either framework, unless you are the main developer of that project. What I am presenting is the different aspects I have found from my development standpoint. Some may see things missing in this list, which I am sure there are. These are some of the things to decide when trying to figure out if a framework will help you. Some developers also are of the opinion that no framework is good and would rather develop from scratch. That is fine too. Remember that the best solution to the problem, is the solution that solves the main crux of the problem. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2009/03/02/cakephp-and-symfony/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Central ACL Check</title>
		<link>http://www.hirdweb.com/2008/11/17/central-acl-check/</link>
		<comments>http://www.hirdweb.com/2008/11/17/central-acl-check/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 12:33:31 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=142</guid>
		<description><![CDATA[With checking ACL&#8217;s, the code I use is as follows: $info = $this->Member->read(null, $id); // Check for permissions to edit this account if ( !$this->Acl->check(array('model' => 'Member', 'foreign_key' => $this->Auth->user('member_id')), $info['Member']['username'], 'update') ) { $this->Session->setFlash(__('You are not allowed to edit this user. -- ' . $this->Auth->user('member_id'), true)); $this->redirect(array('action'=>'index')); } While this works and is not [...]]]></description>
			<content:encoded><![CDATA[<p>With checking ACL&#8217;s, the code I use is as follows:</p>
<pre>
$info = $this->Member->read(null, $id);

// Check for permissions to edit this account
if ( !$this->Acl->check(array('model' => 'Member', 'foreign_key' => $this->Auth->user('member_id')), $info['Member']['username'], 'update') ) {
	$this->Session->setFlash(__('You are not allowed to edit this user. -- ' . $this->Auth->user('member_id'), true));
	$this->redirect(array('action'=>'index'));
}
</pre>
<p>While this works and is not that bad of an idea at all, there is a way to centralize this check and put it in the main app_controller.php file.<br />
<span id="more-142"></span></p>
<p>Depending on the scope of the project, or the business needs of the application, this check can be done and centralized so that there is not the need to put the ACL check in its form above in every action in every controller that needs to have this done. So for the Member controller, you may need to copy/paste the code above to check the ACL for permissions to view, edit, delete, add, etc. That is just one controller, what if there were others as well, like Post, Event, Pictures, etc. That is going to be a lot of code to write to check the ACL. </p>
<p>Now even though the <a href='http://book.cakephp.org/view/471/Checking-Permissions-The-ACL-Component' target='_new' title='5.1.3.4 Checking Permissions: The ACL Component'>Cookbook on checking ACLs</a> shows a simple one line approach:</p>
<pre>
$this->Acl->check(array('model' => 'User', 'foreign_key' => 2356), 'Weapons');
</pre>
<p>it is not just a simple one line approach. There are other things to consider, like what do you want to do if it fails. Is there a specific error message, does it need to redirect to a certain page, and what about if the person needs to be logged in and not need any special ACL permissions.This can get to be a few lines in length, and have a few more things that need to be done. This would be per function/action in the controller. </p>
<p>What I have done, is put the check in the app_controller. This way I need to check it with one line of code, instead of a few. I know, this may seem trivial, but this is something that could get really drawn out in heavier applications. </p>
<p>In the app_controller.php file, I created two functions:<br />
_enforceAccess()<br />
_checkAccess()</p>
<p>First I will explain the _enforceAccess() function. Since I use the model method of ACL, the function is looking for the following:<br />
model<br />
user&#8217;s ID<br />
Object being acted on<br />
Action for the object<br />
Redirect Page</p>
<p>I also do a check for logged in status as well, to make sure that if an action is needed after login, like viewing, then I can check that here as well, instead of per function in the controller. I set all of the parameters to null, in case there is no needed permission check and I need to check logged in status. </p>
<p>So the way this function looks after everything is added:</p>
<pre>
function _enforceAccess($model = null, $id = null,$object = null, $action = null, $redirect = array("/")) {
	if (!$this->loggedin) {
		$this->Session->setFlash('You do not have permissions to carry out the requested action.');
    	$this->redirect('/members/login');
    	exit();
    }
	if ($this->_checkAccess($model,$id, $object, $action)) {
		return true;
	}
	$this->Session->setFlash('You do not have permissions to carry out the requested action.');
	$this->redirect($redirect);
	exit();
}
</pre>
<p>This function first checks for logged in status, if the person is logged in, then I go to the next step, if not, then I would redirect to the login page to get the user to log in to perform this action. As a side note to this: <i>If you are using the Auth component, after the person logs in, the Auth component will redirect back to the prior page where this check was made.</i> </p>
<p>After checking logged in status, it makes a call to the _checkAccess() function and passes the parameters needed to check the ACL. If everything works out ok, and the person has the permission to do the requested action on the object, then the code sends it back to the controller to do any other scripts. The person is authorized, and so it lets them through. </p>
<p>If the person does not have the permission, then they are redirected to the page that is set as they redirect. If no page is given, then the default is just the top level page, or home page of the application. If you specify a redirect page. Either way, the error message is printed out for the end user. </p>
<p>In the _checkAccess() function, it requires the parameters to check the ACL:<br />
$model<br />
$id<br />
$object<br />
$action<br />
This function does the straightforward work. </p>
<pre>
function _checkAccess($model = null,$id = null, $object = null, $action = null) {
	// safety check just in case
	if ( !$this->loggedin ) {
		return false;
    }
    // Just checking for logged in status in this case
	if ( is_null($object) &#038;&#038; is_null($action) ) {
		return true;
	}
	// Check access to a specific record
	if ( !is_null($object) &#038;&#038; !is_null($action) ) {
		if ( $this->Acl->check(array('model' => $model, 'foreign_key' => $id), $object, $action) ) {
			return true;
		}
	}
	// Everything failed, so return false
	return false;
}
</pre>
<p>The first thing the function checks is a safety check. Just to make sure, we check to see if they are logged in. If they are not, return false. This is not really a necessary step, but for this application, one of the requirements was paranoid-like logged in checking. The next feature is to make sure logged in users are authorized. If there is no real check for permissions, and they just want to make sure the person is logged in, then this is one method I use to check this. Your application may be different, and that is ok. The final feature is to check a real object and action. We just put the ACL check here, and return true if it is allowed. If all of the IF statements do not get run, then it returns false. So when if you use this method, make sure that the needed checks are done, and the parameters that are passed have a real value and are not just NULL. </p>
<p>So this accounts for the checks I do now. I take out the calls in the controllers and replace them with this call. To see this in action, lets look at a few examples. </p>
<p>A member is logged in and would like to edit their friend&#8217;s profile:</p>
<pre>
function edit($id = null) {
    $info = $this->Member->read(null, $id);
    $this->_enforceAccess("Member", $this->Auth->user('member_id'),  $info['Member']['username'], 'update', array('controller' => "members"))
    // The rest of the action code goes here
}
</pre>
<p>This will do all the checks for you, and redirect to the members index page if the person does not have permission to edit other user&#8217;s account information. </p>
<p>Another example: a person who is logged in wants to view all posts. Posts are visible to only logged in accounts.</p>
<pre>
function view() {
    $this->_enforceAccess();
    // The rest of the action code goes here
}
</pre>
<p>Since this is open to everyone who is logged in, we do not need to send any parameters over, we just need to make sure they are logged in. Since the _enforceAccess() function already checks for this, we do not need to do any further checks in this function. </p>
<p>Another example: an admin wants to delete an account, and this account is the admin account, (yes this has happened before where an admin was &#8220;three sheets to the wind&#8221; and trying to perform an emergency delete of an employee who was terminated, and tried to delete their own account):</p>
<pre>
function delete($id = null) {
    $info = $this->Member->read(null, $id);
    $this->_enforceAccess("Member", $this->Auth->user('member_id'),  $info['Member']['username'], 'delete', array('controller' => "members"))
    // The rest of the action code goes here
}
</pre>
<p>Last example: A member is logged in and trying to view all events for the group they do not belong to:</p>
<pre>
function viewEvents($group_id = null) {
    $info = $this->Events->read(null, $group_id);
    $this->_enforceAccess("Event", $this->Auth->user('member_id'),  $info['Events']['group_id'], 'view', array('controller' => "events", 'action' => "comingup"))
    // The rest of the action code goes here
}
</pre>
<p>In this check, the code pulls in the groups events based on the foreign key of group_id in the Events table. We are enforcing the the access to view these events, based on the person&#8217;s ID. If the person&#8217;s ID does not have permission to view the events for that group, it will redirect the user to the page events/comingup. Which does it&#8217;s own little thing. Each example here will spit out the error message in the _enforceAccess() function. </p>
<p>Now, even though these two functions added some more lines of code, it has reduced what is needed to be done in each controller. Instead of doing a check in each function in each controller, with its accompanying lines of code, you have just one check to do, usually in one line of code. </p>
<p>What works so well for me in this, is that the _enforceAccess() method can be extended. If you want a generic error message, and then do special errors on certain cases, add a new parameter for the error message, and a check to see if it is filled out. If it is use the special error message, if not, then use the default. If you need additional permission checks, this method also provides a central point to do those. </p>
<p>Remember that in any application, it is all what is required by the business/client/needs. This may work in some instances, and not in others.</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/11/17/central-acl-check/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ACL Implementation</title>
		<link>http://www.hirdweb.com/2008/11/05/acl-implementation/</link>
		<comments>http://www.hirdweb.com/2008/11/05/acl-implementation/#comments</comments>
		<pubDate>Wed, 05 Nov 2008 13:32:38 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=134</guid>
		<description><![CDATA[After doing a few posts on Access Control Lists (ACLs), the need to look further into the implementation of ACLs in a CakePHP project could be helpful. If there are questions on setting up the ACL tri-table in the database, you can review the previous postings, or check out the CakePHP documentation. But now that [...]]]></description>
			<content:encoded><![CDATA[<p>After doing a few posts on Access Control Lists (ACLs), the need to look further into the implementation of ACLs in a CakePHP project could be helpful. If there are questions on setting up the ACL tri-table in the database, you can review the <a href='http://www.hirdweb.com/2008/08/25/access-control-lists-acls/' title='Access Control Lists'>previous postings</a>, or check out the <a href='http://book.cakephp.org/view/465/Understanding-How-ACL-Works' target='_blank' title='CakePHP Documentation'>CakePHP documentation</a>. But now that you have the ACL tables set up, how does it actually work?</p>
<p>First, the ACL happens after authentication. So whether or not you are using the Auth component, you will still need to authenticate the user some how, some way. Then once the user is authenticated and logged in, that user will have permissions to do different thing. Let&#8217;s say one of those things is to edit accounts. If it is a regular user, he should be able to edit his own and no one else. If the user was a &#8220;site admin&#8221; he should be able to edit his own and any account that is not a &#8220;super-admin&#8221;. If he is a super admin then he should edit everyone&#8217;s account. However, the first part of this is setting up the initial ACL permissions. </p>
<p><span id="more-134"></span></p>
<p>This step happens right on the account creation action. After the user has been created, and we grab the last inserted ID, we can update the ACL tables. </p>
<pre>
$usr = $this->User->getLastInsertID();

// Set up the ARO data for this user, assign as a member only at this point.
$aro = new Aro();
// Create the info for this new user
$user = array(
	'alias' => $this->data['User']['username'],
	'parent_id' => 4, // member ARO
	'model' => 'User',
	'foreign_key' => $usr
);
// Create the new ARO for the user
$aro->create();
$aro->save($user);
/**********************************************************************/
// Users are a little crazy because they are also ACOs
$aco = new Aco();
$aco_usr = array(
	'alias' => $this->data['User']['username'],
	'parent_id' => 2, // User ACO id
	'model' => 'User',
	'foreign_key' => $usr
);
// Create the new ACO for the user
$aco->create();
$aco->save($aco_usr);

// A User may update itself but not delete itself.
$this->Acl->allow( array('model' => 'User', 'foreign_key' => $usr), $this->data['User']['username'], 'update' );
$this->Acl->deny( array('model' => 'User', 'foreign_key' => $usr), 'Users', 'delete' );

$this->Session->setFlash(__('The User has been saved', true));
$this->redirect(array('action'=>'index'));
</pre>
<p>This will provide for the base permissions for the user. </p>
<p>Remember at this point, we are looking at ACLs from a user model only. If we wanted to extend this to groups, posts, calendars, etc we would add this in here as well. Say we also had a &#8220;posts&#8221; feature in our application, and we wanted to let the user create their own posts, edit their own posts, but no one elses:</p>
<pre>
$usr = $this->Auth->user('user_id');
$aco_posts = array(
	'alias' => $this->data['Post']['post_id'],
	'parent_id' => 4, // Posts ACO id
	'model' => 'Post',
	'foreign_key' => $usr
);
// Create the new ACO for the user to post
$aco->create();
$aco->save($aco_posts);

// A User may add, edit or delete their own posts, but not other user's posts
$this->Acl->allow( array('model' => 'Post', 'foreign_key' => $usr), $this->data['Post']['post_id'], 'update' );
$this->Acl->allow( array('model' => 'Post', 'foreign_key' => $usr), $this->data['Post']['post_id'], 'delete' );
</pre>
<p>So for anything that you want to limit the user access to, this is your chance. But remember the old saying &#8220;Keep it simple stupid&#8221;. Only do something if it makes sense and the project calls for it. I usually only do a User ACL in the users controller. </p>
<p>Now when you a user wants to go to an edit action after they are logged in, we need to check to make sure they can do this action:</p>
<pre>
$info = $this->User->read(null, $id);

// Check for permissions to edit this account
if ( !$this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('user_id')), $info['User']['username'], 'update') ) {
	$this->Session->setFlash(__('You are not allowed to edit this user. -- ' . $this->Auth->user('user_id'), true));
	$this->redirect(array('action'=>'index'));
}
</pre>
<p>The above code, broken out:</p>
<ul>
<li />$info gets all of the data about the id to be edited. It grabs the data from the table and stores it in the $info array
<li />Does a check to verify that they have permission, always checking for a NOT to be on the safe side
<li />The Acl->check is looking at the User model, since that is the object that is going to be edited (ACO)
<li />The Auth->user(&#8216;user_id&#8217;) is the object requesting permission to do an edit (ARO)
<li />$info['User']['username'] is the exact ACO that will be updated
<li />&#8216;update&#8217; is the action that will be taken on the exact ACO
</ul>
<p>If the test does not pass, and the currently logged in user does not have permission to update the user_id, then they will be redirected to a the index page for the controller. </p>
<p>Let&#8217;s also take the example above with the Posts, and lets say that a user is wanting to edit a post. At the very top of the function, we would put in a very similar check:</p>
<pre>
$info = $this->Post->read(null, $id);

// Check for permissions to edit this account
if ( !$this->Acl->check(array('model' => 'Post', 'foreign_key' => $this->Auth->user('user_id')), $info['Post']['post_id'], 'update') ) {
	$this->Session->setFlash(__('You are not allowed to edit this post. -- ' . $this->Auth->user('user_id'), true));
	$this->redirect(array('action'=>'index'));
}
</pre>
<p>In this example, we just replace User with Post and the info array elements. The same type of check could be done for delete, create and read actions in the controller. As you can see, this check could be done in a function in the app_controller.php file for a central location, which I will get into the next post. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/11/05/acl-implementation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP Auth error message</title>
		<link>http://www.hirdweb.com/2008/09/01/cakephp-auth-error-message/</link>
		<comments>http://www.hirdweb.com/2008/09/01/cakephp-auth-error-message/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 17:48:54 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=79</guid>
		<description><![CDATA[Today is just going to be a quick post. It is Labor Day here in the States and that means a whole heap of people are not going to be working, including me. So I am just messing around with some stuff in CakePHP as I am doing a side project for a local church [...]]]></description>
			<content:encoded><![CDATA[<p>Today is just going to be a quick post. It is Labor Day here in the States and that means a whole heap of people are not going to be working, including me. So I am just messing around with some stuff in CakePHP as I am doing a side project for a local church to put up a calendar. Most of it is complete, but there was one thing that I wanted to change. </p>
<p>I am using the Auth component in my User model. I have allowed register, resetpass, and index. So when I go to view a user&#8217;s detailed profile, there is that message: &#8220;You are not authorized to access that location.&#8221; Which is a fine message and all, but I want it to be site specific, and also controller specific. So the Users controller will have a separate Auth error message than the Calendars controller. So here is what I did. </p>
<p>In the Users controller, I built a beforeFilter function. I set my authorized actions, set redirect to false. I also set a session level variable with the Auth, then I set the error message. There are a couple of messages you can set for the Users controller. You can set the loginError and the authError. The loginError will be the error when the user logs in and is unable to for whatever reason. The authError is what the user will see when they try to perform an action that is not allowed by them, whether it is because they are not logged in (as in my case) or you are using Auth to &#8220;authorize&#8221; an action. </p>
<p>So here is what it would look like:</p>
<pre>
function beforeFilter() {
	parent::beforeFilter();

	$this->Auth->allow('register', 'index', 'resetpass');
	$this->Auth->autoRedirect = false;
	$this->Auth->authorize = 'controller';
	$this->set('my_id', $this->Auth->user('user_id'));
	$this->Auth->authError = "Please log in first in order to preform that action.";
}
</pre>
<p>So when you want to change the standard Auth error message, just remember to set the &#8220;authError&#8221; to whatever message you would like. Happy Labor Day!</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/09/01/cakephp-auth-error-message/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Access Control Lists (ACLs) Part 3</title>
		<link>http://www.hirdweb.com/2008/08/27/access-control-lists-acls-part-3/</link>
		<comments>http://www.hirdweb.com/2008/08/27/access-control-lists-acls-part-3/#comments</comments>
		<pubDate>Wed, 27 Aug 2008 16:58:51 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=72</guid>
		<description><![CDATA[In the first part, the idea and theory behind an ACL was discussed. In part 2, the set up of AROs, ACOs, and ACLs via the command line was shown. Now in part three, we look at why this is so important. Because an interactive site with memberships should never be static, what happens when [...]]]></description>
			<content:encoded><![CDATA[<p>In the first part, the idea and theory behind an ACL was discussed. In part 2, the set up of AROs, ACOs, and ACLs via the command line was shown. Now in part three, we look at why this is so important. Because an interactive site with memberships should never be static, what happens when a new member signs up? What happens when a member is promoted to an &#8220;admin&#8221; level? And what happens when users change? This can all be happened via ACLs. </p>
<p>In part 2, existing member were set up as AROs. And with user accounts, we also have to set those up as ACOs. Then those AROs (people) need to have permissions set for the CRUD actions. (Create, Read, Update, Delete). These actions are specific to the ACO, or object they are trying to manipulate. So if a user wants to edit their own account, do they have permission? If a user wants to delete another person&#8217;s account, do they have permissions to? With setting up ACLs, this can be checked. But what do we do when a new person signs up for an account? We need to create the code to do this. </p>
<p>In the Users Controller, we need to make sure we use the ACL component is included. So include this in the controller:</p>
<pre>
class UsersController extends AppController {
	var $name = 'Users';
	var $components = array('Acl');
</pre>
<p>Also remember that the Auth and Security components are also very powerful components and should be included as well, but the above only shows where to include the components. Now with this in place, we can no address the add (or register) function of the controller. </p>
<p><span id="more-72"></span><br />
When a new user registers an account on the site, we want to make sure to give them only access to their own account, and be able to read the other user profiles. The first thing is to create an &#8220;add&#8221; (or register, I actually prefer that because it just seems to be more logical to me, but I will use the &#8220;add&#8221; function for this example).</p>
<pre>
function add() {

}
</pre>
<p>Now we need to create the basics, or even better, better Bake up the views for the User controller. This helps set the base actions needed to add an account. But here is what some of the included actions should be:</p>
<pre>
function add() {
	if (!empty($this->data)) {
		// Sanitize the stuff
		$clean = new Sanitize();
		$clean->clean($this->data);

		// Set the data to the model
		$this->User->set($this->data);

		// Clean all of the elements in the data array, Attendee, Organization, and Bill information areas
		$this->data['User']['username']	  = $clean->paranoid($this->data['User']['username'], array('.', '-', '\''));
		// Make sure you clean all the user input values to help clean the input from the user, this is just an example line

		// Set any defaults for the user table, these would be items that are not on the form, ie avatar default, last_login date or ip, just to make sure there is no XSS on those fields

		$this->User->create();

		if ($this->User->save($this->data)) {
			$this->Session->setFlash(__('The User has been saved', true));
			$this->redirect(array('action'=>'index'));
		} else {
			$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
		}
	}
}
</pre>
<p>This is just some extensions of the Baked output from the Users controller. I always suggest to sanitze the data, and always set defaults if there are more fields in the table that do not have corresponding inputs. This just helps to cut down on XSS (cross site scripting) and helps to maintain some order of data expected to go in the tables. The next step is to add the ARO and ACO creations for this user. </p>
<p>Every user is an ARO, but they are also ACOs as they may have other users requesting to take action on their accounts. So we need to create the AROs and ACOs for the user right after the create() method:</p>
<pre>
. . .
$this->User->create();
if ($this->User->save($this->data)) {
	$usr = $this->User->getLastInsertID();
</pre>
<p>First we need to get the last inserted ID, because this is the user&#8217;s new user_id. We need to use that here. Then we need to instantiate the ARO object</p>
<pre>
$aro = new Aro();
</pre>
<p>With the ARO object ready to use, we need to create some date to send to the ARO. </p>
<pre>
$user = array(
	'alias' => $this->data['User']['username'],
	'parent_id' => 4, // member ARO
	'model' => 'User',
	'foreign_key' => $usr
);
</pre>
<p>We are creating the information we are to put in to the ARO, the alias (which is the username), the parent ID, in this case, the &#8220;Members&#8221; ARO is aro_id 4, (your parent_id may be different depending on how many AROs you have), the model, which is User in this example, and the foreign key which is the new user id that was just created. Now the Cookbook will say you do not need to put in the alias and the model/foreign_key. But I do because it makes the table easier to read, especially if you are looking at the table doing troubleshooting. It is easier for me, but feel free to find a good method for your own application. </p>
<p>Now take the data, create and ARO and save the data to it. </p>
<pre>
$aro->create();
$aro->save($user);
</pre>
<p>Creating the ACO is similar to the ARO, and this is how it would look. </p>
<pre>
$aco = new Aco();
$aco_usr = array(
	'alias' => $this->data['User']['username'],
	'parent_id' => 2, // User ACO id
	'model' => 'User',
	'foreign_key' => $usr
);

$aco->create();
$aco->save($aco_usr);
</pre>
<p>Now we have an ARO created, and an ACO, we need to make sure the ARO has certain permissions to the ACO (and its parent). Remember that a few rules for all new accounts is that they can only edit their own account, they can not delete any account, and they can view any account. So we can set these permissions after the ARO and ACO creations. </p>
<p>First we want to set it that they can only edit their own account. We are going to implicitly allow access to only this account. </p>
<pre>
$this->Acl->allow( array('model' => 'User', 'foreign_key' => $usr), $this->data['User']['username'], 'update' );
</pre>
<p>By setting the permission this way, it is only granting access to their own account in order to edit or update. If this ARO tries to update another account, it will not have the permissions needed to do so. Now we need to deny the delete action for all User ACOs. </p>
<pre>
$this->Acl->deny( array('model' => 'User', 'foreign_key' => $usr), 'Users', 'delete' );
</pre>
<p>This will deny all delete actions for this ARO. By specifying the &#8220;Users&#8221; ACO, we are safeguarding the delete action. This not only denies the delete action from happening on the &#8220;User&#8221; ACO itself, but all of its child nodes, or in other words, any ACO that has the &#8220;Users&#8221; ACO as it parent. Thus, this newly registered user can not delete any account in the system. </p>
<p>Here is it in its entirety:</p>
<pre>
function add() {
	if (!empty($this->data)) {
		// Sanitize the stuff
		$clean = new Sanitize();
		$clean->clean($this->data);

		// Set the data to the model
		$this->User->set($this->data);

		// Clean all of the elements in the data array, Attendee, Organization, and Bill information areas
		$this->data['User']['username']	  = $clean->paranoid($this->data['User']['username'], array('.', '-', '\''));
		// Make sure you clean all the user input values to help clean the input from the user, this is just an example line

		// Set any defaults for the user table, these would be items that are not on the form, ie avatar default, last_login date or ip, just to make sure there is no XSS on those fields

		$this->User->create();
		if ($this->User->save($this->data)) {
			$usr = $this->User->getLastInsertID();

			$aro = new Aro();
			$user = array(
				'alias' => $this->data['User']['username'],
				'parent_id' => 4, // member ARO
				'model' => 'User',
				'foreign_key' => $usr
			);

			$aro->create();
			$aro->save($user);

			/*****************************/
			$aco = new Aco();
			$aco_usr = array(
				'alias' => $this->data['User']['username'],
				'parent_id' => 2, // User ACO id
				'model' => 'User',
				'foreign_key' => $usr
			);

			$aco->create();
			$aco->save($aco_usr);

			// Set the permissions
			$this->Acl->allow( array('model' => 'User', 'foreign_key' => $usr), $this->data['User']['username'], 'update' );
			$this->Acl->deny( array('model' => 'User', 'foreign_key' => $usr), 'Users', 'delete' );

			$this->Session->setFlash(__('The User has been saved', true));
			$this->redirect(array('action'=>'index'));
		} else {
			$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
		}
	}
}
</pre>
<p>So that will set a new ARO and ACO for a new user. You would follow the same path for an event, or group, but you would only set a new ACO, and the permissions as needed, based on requirements. But this is not the only thing to do. We still need to check these permissions. As it stands right now, any user can edit or delete any other user, because we have not included the ACL check yet. So to demonstrate this check, we will use the Edit function as an example. </p>
<p>In the edit function, there is an ID passed to the function. This is the ID of the account to be edited. We need to check if the currently logged in user has the permissions to edit this account. We do that by doing an ACL check. </p>
<pre>
$this->Acl->check(array('model' => 'model_name', 'foreign_key' => "id of logged in person" "alias of ACO", "action requested");
</pre>
<p>So for this example, it is the User ACO we are wanting, more specifically the user account requested to be edited, and the action is (of course) update. So the first thing is to get the alias of the user to be edited</p>
<pre>
function edit($id = null) {
	$info = $this->User->read(null, $id);
}
</pre>
<p>This will pull the id into an array called &#8220;info&#8221; and we are looking for <i>$info['User']['username']</i>. Remember that your version may vary based upon the table info you have. Now we can do a check based on the currently logged in user, and in this example I am using the Auth component to get that. </p>
<pre>
if ( $this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('user_id')), $info['User']['username'], 'update') ) {
	// Do the edit stuff here
} else {
	$this->Session->setFlash(__('You are not allowed to edit this user.', true));
	$this->redirect(array('action'=>'index'));
}
</pre>
<p>This will check the currently logged in user to see if they have update permissions on the specified user_id&#8217;s ACO. If they do have permission, then it will go through the edit actions, checks, etc. If they do not, it bypasses that altogether and kicks them back to the index view with a message. </p>
<p>The same can be done for the delete action</p>
<pre>
function delete($id = null) {
	$info = $this->User->read(null, $id);

	if ( !$this->Acl->check(array('model' => 'User', 'foreign_key' => $this->Auth->user('user_id')), $info['User']['username'], 'delete') ) {
		// Do the delete stuff here
	} else {
		$this->Session->setFlash(__('You are not allowed to DELETE this user.', true));
		$this->redirect(array('action'=>'index'));
	}
}
</pre>
<p>Now this is just a simple example, and this same type of idea can be done for events, editing events, viewing events, etc. The same goes for groups and any other type of application where a permission check is needed. </p>
<p>Now, is my soap-box time. Why use ACLs at all? Wouldn&#8217;t a simple &#8220;level&#8221; table be enough to create this same type of effect? Yes and no. Remember that the right program for the job is determinant upon the job requirements. If an application is going to be used for a small purpose, and maybe you only will have 50 people at the most in a calendar application, then an ACL may be going a little overboard. However, if you have 50 people who are part of different groups, and based on group membership can do different things on the application, and the tasks may change from person to person based on work load, then an ACL may take some of the stress of of doing this type of thing. </p>
<p>Remember that an ACL is a great way to keep permissions in check with little human overhead involved. But sometimes the job requires that human overhead is needed, sometimes not. ACLs are great, and I use them frequently on big jobs. For the smaller jobs, I do not. But after this, hopefully you know better about what an ACL is, and how to use one in an application. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/27/access-control-lists-acls-part-3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Access Control Lists (ACLs) Part 2</title>
		<link>http://www.hirdweb.com/2008/08/26/access-control-lists-acls-part-2/</link>
		<comments>http://www.hirdweb.com/2008/08/26/access-control-lists-acls-part-2/#comments</comments>
		<pubDate>Wed, 27 Aug 2008 01:34:56 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=65</guid>
		<description><![CDATA[In my last post, I covered a little bit about what an Access Control List (ACL) was. The Cookbook provides a great more detail. To go along with the idea of the last post, the application has a few different areas: Users who are members of groups, Groups which have users as members, and Events [...]]]></description>
			<content:encoded><![CDATA[<p>In my last post, I covered a little bit about what an Access Control List (ACL) was. The <a href="http://book.cakephp.org/view/171/access-control-lists" target="_blank">Cookbook </a>provides a great more detail. </p>
<p>To go along with the idea of the last post, the application has a few different areas: Users who are members of groups, Groups which have users as members, and Events that belong to either the user or the group. Since the creation of ACOs and AROs are basically the same for each area (Users, Groups, Events), I will detail some code for the Users area making use of ACLs. </p>
<p>The first thing we need to do is create an ARO grouping and an ACO grouping. Remember that AROs are the requester of an object. In this example, we can think of them as people. And people have different types of roles, which is what we need to create for the people. In this example application, there will be site admins (Admins), group leaders (Leaders) and regular members (Members). So we need to create this type of ARO. We can do this in a controller, and a page, or we can do this via the command line. </p>
<p><span id="more-65"></span><br />
If you create the AROs and ACOs via a controller, it would be done this way:</p>
<pre>
$aro = new Aro();
$groups = array(
	0 => array('alias' => 'Admins'),
	1 => array('alias' => 'Leaders'),
	2 => array('alias' => 'Members'),
);

foreach($groups as $data)
{
	$aro->create();
	$aro->save($data);
}
</pre>
<p>Instantiate the new ARO object, then set up information for the ARO. Then iterate through the array in a foreach loop.  You can do the same for the ACO parents that need to be created. The ACOs in this example are similar to our models. There are events, users, and groups. To create those, follow the same pattern as above, only make sure to use the &#8220;Aco()&#8221; object. However, an easier way (at least I think so), is to use the command line interface (cli) to create these. </p>
<p>To use the cli for this, you will need to be logged in via &#8220;SSH&#8221; to the server, or connected via shell, or however else you choose to connect. The command to create the ACOs and AROs is:</p>
<pre>
# cake acl create aro (parent) (node)
# cake acl create aco (parent) (node)
</pre>
<p>So if I was going to create the groups for the parent AROs, I would do the following:</p>
<pre>
# cake acl create aro Members admin
</pre>
<p><i>NOTE:</i> If you have not set up the <a href="http://book.cakephp.org/view/108/the-cakephp-console" target="_new">CakePHP console paths according the Cookbook specifications</a>, then you may have to use this command line a little different call. I always suggest to run the console from the App folder. From there, you can run the following:</p>
<pre>
# php ../cake/console/cake.php acl create aro Members admin
</pre>
<p>I do suggest you set up the console to work without this, but if for some reason you are unable to, this can work as well. </p>
<p>So this will set up each parent ARO and ACO. Now we need to address the users. If there are already users in the system, then we can use the cli to update them and add them to the ARO table. However, users a different bunch, and this is why I choose to use the example on them instead of events or groups. Events and groups are both objects which are requested by users. But users, they are different. For example, if a user with the username of &#8220;test1&#8243; exists, and logs in, and then sees another account, let&#8217;s say that account username is &#8220;answer1&#8243;, we do not want &#8220;test1&#8243; to be able to edit this account. However, we would want an administrator to have this ability. So we need to lock down edit permissions from &#8220;test1&#8243; so that he can only update his own account, and we want to be able to give administrators access to edit any User account. So now users are not only an ARO, but they become an ACO as well. And we need to give (or deny) permissions to any user based on who they are. </p>
<p>So lets say we have 3 users already in the system. &#8220;BigMan1&#8243;, and administrator, &#8220;Newbie&#8221; and &#8220;Lilie&#8221; both regular members. We want to be able to create an ARO for each of them, and then create an ACO for each of their accounts, and then give them permissions. To create the ARO and ACO for each account (with showing the return from the console):</p>
<pre>
$ cake acl create aro Members BigMan1
New Aro 'BigMan1' created.

X-Powered-By: PHP/5.2.6
Content-type: text/html
</pre>
<pre>
$ cake acl create aco Users BigMan1
New Aco 'BigMan1' created.

X-Powered-By: PHP/5.2.6
Content-type: text/html
</pre>
<p>Now we can follow this for the other two and they would be created. Now we need to give them permissions. The admin should have access to edit any User account, delete any user account except for their own, and be able to view any User account. To grant permissions, the command is:</p>
<pre>
$ cake acl grant admin aro aco  action
</pre>
<p>The action can be one of the four CRUD members or &#8220;all&#8221;.  We are going to start with the admin user, because they will get access to all Users. </p>
<pre>
$ cake acl grant BigMan1 Users update
Permission granted.
X-Powered-By: PHP/5.2.6
Content-type: text/html

$ cake acl grant BigMan1 Users delete
Permission granted.
X-Powered-By: PHP/5.2.6
Content-type: text/html

$ cake acl grant BigMan1 Users read
Permission granted.
X-Powered-By: PHP/5.2.6
Content-type: text/html
</pre>
<p>Now there is a problem here. The Admin can delete his own account right now, because we have given him permissions to delete and User account (parent ACO = Users). We do not want him to delete his own account, so we need to deny him permission. This is done very similar, only instead of &#8220;grant&#8221;, it is &#8220;deny&#8221;.</p>
<pre>
$ cake acl deny BigMan1 BigMan1 delete
Permission granted.
X-Powered-By: PHP/5.2.6
Content-type: text/html
</pre>
<p>In the above example, we are doing an acl command, denying permissions for ARO BigMan1 on ACL BigMan1 for the delete action. In the previous example where we granted him permissions, we set the ACO on the parent, so that any child nodes would inherit the same permissions. But on this deny, we want to deny only for a child node. </p>
<p>Now, when we grant access to other users who are not admins, we would do this on the child nodes. So lets say that users can read any User account, only edit their own, and never delete their own account. So we would do that as:</p>
<pre>
$ cake acl grant Newbie Newbie update
Permission granted.
X-Powered-By: PHP/5.2.6
Content-type: text/html

$ cake acl deny Newbie Users delete
Permission denied.
X-Powered-By: PHP/5.2.6
Content-type: text/html

$ cake acl grant Newbie Users read
Permission granted.
X-Powered-By: PHP/5.2.6
Content-type: text/html
</pre>
<p>This will grant &#8220;Newbie&#8221; access to read any User account, update their own account, and denied being able to delete any account. </p>
<p>So that does it for the existing users. But now what about any new user that registers on the site? That will be covered in part 3, and will show some of the true power of the ACL when used in applications. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/26/access-control-lists-acls-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Access Control Lists (ACLs)</title>
		<link>http://www.hirdweb.com/2008/08/25/access-control-lists-acls/</link>
		<comments>http://www.hirdweb.com/2008/08/25/access-control-lists-acls/#comments</comments>
		<pubDate>Tue, 26 Aug 2008 01:20:49 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=42</guid>
		<description><![CDATA[Access Control Lists, or ACLs, provide a good level of access control on any site. Code bases and platforms may use a different method of instituting ACLs and I am going to go through how CakePHP 1.2.x is handling them. First is to understand what an ACL really is. The Cookbook has a good page [...]]]></description>
			<content:encoded><![CDATA[<p>Access Control Lists, or ACLs, provide a good level of access control on any site. Code bases and platforms may use a different method of instituting ACLs and I am going to go through how CakePHP 1.2.x is handling them. </p>
<p>First is to understand what an ACL really is. The <a href="http://book.cakephp.org/view/171/access-control-lists" target="_new">Cookbook has a good page explaining this type of concept</a>. I highly recommend reading through this page. The whole concept behind this ACL can be divided in three parts:</p>
<ul>
<li>ACO &#8211; Access Control Object, object that is being requested</li>
<li>ARO &#8211; Access Request Object, object that is putting in the request</li>
<li>ACL &#8211; Access Control List, determines if an ARO can access an ACO.</li>
</ul>
<p><em>In the Cookbook, they have a very good call out about the ACL, it is not authentication. No matter what code base, or platform you are on, never mistake this. The ACL verification only happens after the person logs in. They can be very powerful together, but authentication must happen first. </em></p>
<p>The next thing to understand is the way an ACL would look in a matrix. Again, the Cookbook provides a great example of this. The one thing that I would rather prefer, but understand why they do this, is the use of the example. Sure, we all like movies, and the Lord of the Rings is a great way to really explain different things, but it may be hard to switch that over to the real world of coding. So for this entry, I am going to use as an example, and Event Calendar. </p>
<p><span id="more-42"></span><br />
In this Event Calendar, here is the breakdown: there are events, there are groups, there are users. Each user is going to be a member of a group. A group will have a &#8220;leader&#8221; who can add, edit or delete group events. A group will also have an &#8220;editor&#8221; who will be able to add or edit group events. And the default group membership is one who can only view group events. </p>
<ul>
<li><strong>Groups</strong></li>
<li> &#8211; <em>Leader</em></li>
<li> &#8211; - Add, edit, delete group events</li>
<li> &#8211; - View all group events</li>
<li> &#8211; <em>Editor</em></li>
<li> &#8211; - Add, or edit group events</li>
<li> &#8211; - View all group events</li>
<li> &#8211; <em>Member</em></li>
<li> &#8211; - View all group events</li>
</ul>
<p>Users will be anyone who creates a login to the application. Of course there will be a &#8220;site admin&#8221; who can add, edit, delete to any user account except their own. They can assign a user to a group, or remove memberships. The group leader can add or remove memberships to their own group only. They can not add, edit or delete user accounts. The default user can edit their own account, and request for the account to be deleted (they can not delete their own account). </p>
<ul>
<li><strong>Users</strong></li>
<li> &#8211; <em>Site Admin</em></li>
<li> &#8211; - Add, edit, delete all user accounts (except the site admin account)</li>
<li> &#8211; - Add, or remove users from any group</li>
<li> &#8211; <em>Leader</em></li>
<li> &#8211; - Add or remove users from their own group only</li>
<li> &#8211; <em>Users</em></li>
<li> &#8211; Sign up for an account, edit only their profile</li>
<li> &#8211; request to be a member of a group</li>
</ul>
<p>Events can be either a group event, or an individual event. Group members can see group events, and an individual event is only available to be viewed by the user who entered the event. </p>
<ul>
<li><strong>Events</strong></li>
<li> &#8211; <em>Group Events</em></li>
<li> &#8211; - Viewable by members of the group</li>
<li> &#8211; <em>Individual Events</em></li>
<li> &#8211; - Viewable only by the user who entered the event</li>
</ul>
<p>To put this in a &#8220;use case&#8221; scenario, here are four examples:</p>
<p>Case 1: Username &#8220;MotoCrash&#8221; is a registered user of the site. He is also a group leader of the &#8220;ProFootball&#8221; group. He is able to update membership of the group, and is able to edit the different events for the group calendar. There are some events he has had to delete. He often updates his own account with a new avatar image. He can view all of the group events to determine if any of them need to be edited.<br />
ARO = &#8220;MotoCrash&#8221;<br />
ACOs = Groups, Events, Users</p>
<p>Case 2: Username &#8220;FootballNut&#8221; is a registered user of the site. He is a member of two (2) groups. He is a regular member of the group named &#8220;ProFootball&#8221; and a group leader of &#8220;PopWarnerBall&#8221;. He is able to see events in both groups, but is only able to add, edit, or delete events in the &#8220;PopWarnerBall&#8221; group. He adds his own events for personal uses that only he is able to see.<br />
ARO = &#8220;FootballNut&#8221;<br />
ACOs = Groups (2 checks), Events</p>
<p>Case 3: Username &#8220;Angel&#8221; is a regular member. She is not part of a group as of yet, but posts events to her own personal calendar. She is able to edit her account, adding a new signature line every month. She is able to view her own events. She is an avid football fan, but is unable to see events for the ProFootball group.<br />
ARO = &#8220;Angel&#8221;<br />
ACOs = Groups, Users, Events</p>
<p>Case 4: Username &#8220;Admin&#8221; is a the site admin. They are able to do all actions in any group, and able to update any memberships, or add, edit or delete accounts. They are not able to delete their own account.<br />
ARO = &#8220;Admin&#8221;<br />
ACOs = Groups, Events, Users, Administation</p>
<table width='90%' cellpadding='2' cellspacing='2' border='1'>
<tr>
<td>&nbsp;</td>
<td colspan='4'>Users</td>
</tr>
<tr>
<td>Area</td>
<td>MotoCrash</td>
<td>FootballNut</td>
<td>Angel</td>
<td>Admin</td>
</tr>
<tr>
<td><b>Group ACO</b>: ProFootball</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>Add Members</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Remove Members</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Group ACO</b>: PopWarnerBall</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>Add Members</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Remove Members</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Event ACO</b>: ProFootball</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View Events</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Add, Edit or Delete Events</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Event ACO</b>: PopWarnerBall</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Add, Edit or Delete Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Individual Event ACO</b>: MotoCrash</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View, Add, Edit, Delete  Events</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Individual Event ACO</b>: FootballNut</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View, Add, Edit, Delete  Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Individual Event ACO</b>: Angel</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View, Add, Edit, Delete  Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>User ACO</b></td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>Update Own Account</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Update Other Account</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Delete Own Account</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
</tr>
<tr>
<td><i>Delete Other Account</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
</table>
<p>I hope this has been helping to better understand ACLs. In order to really delve into this topic, and separate the different areas, I am finishing this post here. I am going to post another one that gets into the code of setting up the tables (acos, aros, aros_acos), and then the coding portion of the ACLs, like when a new user is created, group membership changes, or how to validate on the ACL based on the logged in user. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/25/access-control-lists-acls/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Queries using CakePHP find()</title>
		<link>http://www.hirdweb.com/2008/08/18/queries-using-cakephp-find/</link>
		<comments>http://www.hirdweb.com/2008/08/18/queries-using-cakephp-find/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 17:51:09 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[cakePHP]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[queries]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=35</guid>
		<description><![CDATA[CakePHP now has deprecated some queries. The findALL, findCount, etc etc etc. This now uses the find() method for all of these, and has a basic syntax for this. If it is basic, why blog about it then? Good question. The documentation is there in the API, and is there in the Cookbook, it took [...]]]></description>
			<content:encoded><![CDATA[<p>CakePHP now has deprecated some queries. The findALL, findCount, etc etc etc. This now uses the find() method for all of these, and has a basic syntax for this. If it is basic, why blog about it then? Good question. The documentation is there in the <a href="http://api.cakephp.org/class_model.html#e60758f27fa8486a063b8cc424bad741">API</a>, and is there in the <a href="http://book.cakephp.org/view/73/retrieving-your-data">Cookbook</a>, it took me some time to really get a good idea on an applicable example and took many times of &#8220;trial and error&#8221; to help me get along. Because finding is good, and will give you all the information you need, if it is a simple, 1 table find. If you need to query two or three tables, how does this work. So this will go into those as well. </p>
<p>The basic idea of find, as listed by the API is this:</p>
<pre>
find(
	array $conditions,
	array $fields,
	string $order,
	int $recursive
);
</pre>
<p>This will find one record based on conditions, return the desired fields (or all of them if nothing is specified), order the results, and go so many levels deep (-1 for just the current table).<br />
<span id="more-35"></span></p>
<p>To get all the results instead of just one field, you would follow this:</p>
<pre>
find(
	string $notation_find,
	array(
		array $conditions,
		array $fields,
		string $order,
		int $recursive
	)
);
</pre>
<p>To find just one record, you need to use the first method, to find all records or a specific &#8220;notation&#8221; find, you would use the second method. The list of some of the &#8220;notations&#8221; are listed below:<br />
all<br />
neighbors<br />
list<br />
count<br />
threaded</p>
<p>So to use examples of this, lets say we have a &#8220;forum&#8221; area of a site, where it reads from a User table, a Forum table and a Post table. We have three tables, and we need to find certain things:</p>
<ol>
<li>The current Forum information (1 record, 1 table only)</li>
<li>The current number of posts in a forum (1 table, count)</li>
<li>The last post, and who posted it, in the selected forum (3 tables, 1 record, certain fields)</li>
<li>All posts in a forum topic, paginate results (3 tables, all records on specific conditions, certain fields)</li>
</ol>
<p>The way these tables (Forums, Posts and Users) relate to each other is by use of table-name_id (user_id, forum_id, post_id). User can have many posts, post belongs to a user, post belongs to a forum, forum has many posts. Now we need to do a simple query to get current forum info. I am doing this all in a forums_controller.php file. These can be a myriad of different function names, but each function would always be looking for some type of input. <em>NOTE: fields are arbitrary to this example. You can have as many or as little fields needed. </em></p>
<p>1. The current Forum information (1 record, 1 table only)</p>
<pre>
$forums = $this->Forum->find(
	array('Forum.forum_id' => $id),
	array('Forum.forum_id', 'Forum.forum_name', 'Forum.description', 'Forum.created'),
	null,
	-1
);
</pre>
<p>This grabs the current, or selected forum (passing in the $id from the function parameters), grabbing four fields from the table, no need to sort 1 record, and I only want this table&#8217;s data. This would return something like:</p>
<pre>
Array(
	[Forum] => Array(
		[forum_id] => 1
		[forum_name] => Sample Forum
		[description] => A Forum to discuss anything, upcoming and past.
		[created] => 2008-07-23 20:15:41
	)
)
</pre>
<p>2. The current number of posts in a forum (1 table -Posts-, count)</p>
<pre>
$post_count = $this->Post->find(
	'count',
	array(
		'conditions' => array('forum_id' => $id),
		'recursive' => -1
	)
);
</pre>
<p>With using count, there is no need to get fields or sort order, all we really need to do is get the conditions set, which are: all posts with the selected forum_id value. This returns a number of the records returned. Let&#8217;s say for this example it returned 12. </p>
<p>3. The last post, and who posted it, in the selected forum (3 tables -Users Posts Forums- , 1 record, certain fields)<br />
For this we can do a trick in the query, instead of getting just all the records, or the last entered one, we could try this:</p>
<pre>
$lastP = $this->Post->find(
	array('Post.forum_id' => $id), //array of conditions
	array('Post.created', 'User.username', 'Post.parent_topic', 'Post.title', 'Post.post_id', 'Forum.forum_name'), //array of field names
	'Post.created DESC', //string or array defining order
	-1, //int recursive level
	1 //int number of records to return
);
</pre>
<p>This is going to query the tables, where these conditions are met, order them descending order, and then return 1 record, the first one, which will be the last entry made in the table with that forum_id. Now we get into the &#8220;meat&#8221; of this thing. </p>
<p>4. All posts in a forum topic, paginate results (3 tables, all records on specific conditions, certain fields)</p>
<pre>
// Get the parent post
$parent = $this->Post->find(
	array('Post.post_id' => $id),
	array('Post.post_id', 'Post.forum_id', 'Post.title', 'Post.details', 'Post.created', 'User.username', 'User.avatar', 'User.biography', 'User.created', 'Forum.name'),
	'Post.created DESC',
	0
);
</pre>
<p>In this example, and as <a href="http://www.hirdweb.com/2008/08/04/custom-pagination-in-cakephp/">previously noted in my earlier blog posts</a>, the &#8220;Topic&#8221; is an entry in the Posts table, and all replies to that post reside in the same table, but reference that post_id as the parent_topic value. So the first thing I do is get this &#8220;Topic&#8221; information. I do some checks on this (which is outside the scope of this entry). Then I am ready to grab the replies to this topic, and then paginate the results. Since I already referenced the controller to use the paginator, I need to make a call to the paginator, and I need to apply a condition to it:</p>
<pre>
// grab all of the posts for this parent topic, and get the parent topic in the pagintor
$cond = array( 'OR' =>array( 'Post.parent_topic' => $id, 'Post.post_id' => $id ) );
$this->set( 'posts', $this->paginate( "Post", $cond ) );
</pre>
<p>One of the important things to note in this query, is the use of the $cond variable. I set this to use an &#8220;OR&#8221; clause. If nothing is specified, then the find() or paginator() assumes it is an &#8220;AND&#8221; clause, which is not the case here. So I set the conditions to look for the the $id value in either the post_id or the parent_topic columns. Be sure to check out the Cookbook for more information on complex queries. </p>
<p>But that is about it. Real world examples in use today using the new find() methods. The best part about these, is that with a little tweak here or there, you can have queries do what you want them to do, with little coding needed to accomplish the task. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/18/queries-using-cakephp-find/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
