<?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>cakealot &#187; CakePHP</title>
	<atom:link href="http://cakealot.com/category/cakephp-general/feed/" rel="self" type="application/rss+xml" />
	<link>http://cakealot.com</link>
	<description>cakephp and stuff</description>
	<lastBuildDate>Sat, 13 Mar 2010 23:20:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>All your $base are belong to Ajax</title>
		<link>http://cakealot.com/2010/03/all-your-base-are-belong-to-ajax/</link>
		<comments>http://cakealot.com/2010/03/all-your-base-are-belong-to-ajax/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 23:13:38 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[CakePHP Tricks]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[base]]></category>
		<category><![CDATA[here]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[paths]]></category>
		<category><![CDATA[router]]></category>
		<category><![CDATA[routes]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=488</guid>
		<description><![CDATA[We have custom routes, completly dynamic. We can even move the whole app to a subdirectory and still it works! So nice! But how to deal with that in static Javascript files? What about the Ajax and maybe some JS asset configs like image folders and such? In this small post i will tell you [...]]]></description>
			<content:encoded><![CDATA[<p>We have custom routes, completly dynamic. We can even move the whole app to a subdirectory and still it works! So nice! But how to deal with that in static Javascript files? What about the Ajax and maybe some JS asset configs like image folders and such? In this small post i will tell you a good practice of mine which allows me to forget about that problem.<br />
<span id="more-488"></span><br />
In CakePHP you have two handy properties in the controller, views and helpers. They are called <code>$this->base</code> and <code>$this->here</code>. They are basicly all you will ever need, but most importantly <code>$this->base</code>. </p>
<p>The <code>$base</code> property tells you the current directory of the application (roughly put).  If you application runs in <code>http://example/app/</code> the <code>$base</code> property has the value <code>/app</code>.</p>
<p>The <code>$here</code> property tells you the current directory + the current action path. If you request <code>http://example/app/admin/users/home</code> the <code>$here</code> property has the value <code>/app/admin/users/home</code>.</p>
<p>We can use this info to our advantage when writing Ajax request in our external Javascript files. What i always do is using the JavascriptHelper to generate a code block with exactly these two values.</p>
<pre class="php">$javascript->codeBlock("var base = '{$this->base}, here = '{$this->here}';'");</pre>
<p>I usually throw that line in my layout before i add anythings else, so that this info is available in all my scripts.</p>
<p>Now whenever i want to call something with Ajax i can either use <code>Ajax.Request(base + '/controller/action.json');</code> or simply <code>Ajax.Request(here + '.json')</code>. If i ever decide to move the application i no longer need to worry about the base path. </p>
<p>Same goes for our webroot folder of course: <code>$imgFolder = base + '/img/';</code></p>
<p>Another practice i found useful is when you want to submit a CakePHP form with Ajax. Instead of figuring out what path you need to POST to, just query the action attribute of the form. Much easier than writing the url yourself, even easier than using <code>base</code>.</p>
<pre class="js"><code>// ajax post on all forms, just for demo
$$('form').invoke('observe', 'submit', function(evt){

  var form = evt.element();
  new Ajax.Request(form.readAttribute('action') + '.json', {
    parameters: form.serialize(),
    onComplete: function(xhr) {
      // added .json for fun
      // maybe do something neat with validationErrors
    }
  });

});
</code></pre>
<p>This should help you keeping your Javascript codebase lean. </p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2010/03/all-your-base-are-belong-to-ajax/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>QuickTip: Pesky missing layout when requesting extensions</title>
		<link>http://cakealot.com/2010/03/quicktip-pesky-missing-layout-when-requesting-extensions/</link>
		<comments>http://cakealot.com/2010/03/quicktip-pesky-missing-layout-when-requesting-extensions/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 22:21:20 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[CakePHP Tricks]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[layouts]]></category>
		<category><![CDATA[RequestHandler]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=477</guid>
		<description><![CDATA[In CakePHP you can use a different layout (other than default.ctp) for all your views by simply changing the $layout property in your controller. I use this to deliver a different layout for, let&#8217;s say, the admin panel of the application &#8211; or maybe a member area. 
Let&#8217;s stick with the admin panel example:
$this->layout = [...]]]></description>
			<content:encoded><![CDATA[<p>In CakePHP you can use a different layout (other than default.ctp) for all your views by simply changing the <code>$layout</code> property in your controller. I use this to deliver a different layout for, let&#8217;s say, the admin panel of the application &#8211; or maybe a member area. </p>
<p>Let&#8217;s stick with the admin panel example:</p>
<pre class="php"><code>$this->layout = 'admin';</code></pre>
<p>Now we all do some neat Ajax or XML here and there sometimes, and for Ajax we probably end up delivering JSON from the very same actions (&#8221;Yes, CakePHP is smart like that&#8221;). For that you usually start by adding <code>Router::parseExtensions('json')</code> to the routes.php file.<br />
<span id="more-477"></span><br />
This works fine as long as you don&#8217;t call the action for JSON while it is using a different <code>$layout</code>. If we, for example, call <code>/admin/users/index.json</code>, CakePHP will tell us that it is missing the layout view file: <code>APP/views/layouts/json/admin.ctp</code>. Meh! </p>
<p>I am not saying that this is bad. It is actually quiet useful in some scenarios, but in general most people will be happy sharing the same old <code>APP/views/layouts/json/default.ctp</code> with all parts of the application. So&#8230; how to fix this?</p>
<p>Add the RequestHandler component to your app and add the following code to your <code>AppController::beforeFilter()</code> method (create the method if needed):</p>
<pre class="php"><code>if ($this->RequestHandler->isAjax() &#038;&#038; $this->RequestHandler->prefers('json')) {
 	$this->layout = 'default';
}</code></pre>
<p>Now everytime the browser (client) prefers &#8220;json&#8221; the layout is switched back to &#8220;default&#8221;. Simple as that.</p>
<p>You can extend the checks to other formats.</p>
<pre class="php"><code>if ($this->RequestHandler->isAjax() || $this->RequestHandler->isRss() || $this->RequestHandler->isXml()) {
 	$this->layout = 'default';
}</code></pre>
<p>Hope this helps</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2010/03/quicktip-pesky-missing-layout-when-requesting-extensions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Force download a custom view using MediaView</title>
		<link>http://cakealot.com/2009/10/force-download-a-custom-view-using-mediaview/</link>
		<comments>http://cakealot.com/2009/10/force-download-a-custom-view-using-mediaview/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 15:17:50 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP Hints]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[exporting]]></category>
		<category><![CDATA[files]]></category>
		<category><![CDATA[force-download]]></category>
		<category><![CDATA[mediaview]]></category>
		<category><![CDATA[mime]]></category>
		<category><![CDATA[render]]></category>
		<category><![CDATA[tmp]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=468</guid>
		<description><![CDATA[Generally you would need to force-download the file, probably using MediaView. Problem is that it isn't actually a real file for MediaView to work with. Here's a workaround to that.]]></description>
			<content:encoded><![CDATA[<p><strong>Just some quick hint:</strong> Let&#8217;s assume you generate a non-html file using a view, layout and custom extension (sql, xml, json, etc..) and you want to offer the displayed result as a download. &#8211; Generally you would need to force-download the file, probably using MediaView. Problem is that it isn&#8217;t actually a real file for MediaView to work with. </p>
<p>Here&#8217;s a quick workaround to that, using two calls to render() in a single action (comments welcome):</p>
<pre class="sh_php">
public function export() {
  $data = $this->{$this->modelClass}->find('all');
  $this->set(compact('data'));
  $rendered = $this->render();
  $fileext = 'xml'; // optional: $this->params['url']['ext'];
  $filepath = TMP.'rendered'.DS;
  $filename = md5(String::uuid()).'.'.$fileext;
  file_put_contents($filepath.$filename, $rendered); // php5 func
  $this->view = 'Media';
  $params = array(
    'id' => $filename,
    'path' => $filepath,
    'extension' => $fileext,
    'download' => true, // force download
    'name' => low($this->name).'-export' // fancy name
  );
  $this->set($params);
  $this->render(); // init download
}
</pre>
<p>That&#8217;s it. First you render the .ctp using all the fancy helpers, temporarly save the result on your (ram)disk, change the view to Media, reuse almost same variables for the params array and simply call render again. Since we change $this->view in between renders, we can use both view renderer in a row.</p>
<p>DRY: For the extension you could grab the current extension from <code>$this->params['url']['ext']</code> if you used <code>array('ext' => '...')</code> in the <code>HtmlHelper::link()</code> url param. This makes the action even more generic.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/10/force-download-a-custom-view-using-mediaview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Environment: Support methods in param matching</title>
		<link>http://cakealot.com/2009/07/environment-class-support-methods-in-param-matching/</link>
		<comments>http://cakealot.com/2009/07/environment-class-support-methods-in-param-matching/#comments</comments>
		<pubDate>Sun, 19 Jul 2009 06:29:51 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP Tricks]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[domains]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[http_host]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=435</guid>
		<description><![CDATA[Some of you probably remember the fine Environment Class developed by Rafael Bandeira. I still use and love it for handling dev, staging and production environments. And it&#8217;s super awesome that you may create a AppEnvironment class to tweak the config and param mapping. However, i found one thing missing and that&#8217;s support for arrays [...]]]></description>
			<content:encoded><![CDATA[<p>Some of you probably remember the fine <strong>Environment Class</strong> developed <a href="http://rafaelbandeira3.wordpress.com/2008/12/05/handling-multiple-enviroments-on-cakephp/">by Rafael Bandeira</a>. I still use and love it for handling dev, staging and production environments. And it&#8217;s super awesome that you may create a <strong>AppEnvironment</strong> class to tweak the config and param mapping. However, i found one thing missing and that&#8217;s support for arrays when matching the mapped params.</p>
<p>For example: You have one &#8220;development&#8221; environment but you have multiple domains pointing to it and the app needs to behave differently based on that (language preset based on domain extension, vanity urls for user profiles, .. that kind of stuff).<br />
<span id="more-435"></span></p>
<p>There are of course alot of other reasons why that&#8217;s a good a idea. In general to avoid duplicate code and conflicts. To get around all that i needed support for arrays.</p>
<p>One approach to support arrays would be to just add it to the <code>_match($param, $value)</code> method in the Environment class, but it may not have been appropiate in all occassions. So i just followed Rafael&#8217;s lead and simply added support for instance methods. Since we may have our own class for environment config/param mapping (just create <code>app_environment.php</code> in /config/), it&#8217;s a good place to also add some helper methods. </p>
<p>That was the previous code (around line 90). </p>
<pre class="sh_php">if (function_exists($param)) {
	$match = call_user_func($param, $value);
} else {
	$match = (env($param) === $value);
}
if (!$match) {
	return false;
}
</pre>
<p>I just added another &#8220;if-condition&#8221; and used <code>getInstance</code> to get the object.</p>
<pre class="sh_php">$instance = self::getInstance();
if (method_exists($instance, low($param))) {
	$match = call_user_method(low($param), $instance, $value);
} elseif (function_exists($param)) {
	$match = call_user_func($param, $value);
} else {
// ... as above
</pre>
<p>Note the &#8220;<code>low($param)</code>&#8220;. I&#8217;ve set the value of <code>$param</code> to lower-case because param would be HTTP_HOST which doesn&#8217;t makes up for a good method name. Maybe could have used Inflector to make it camelcase just to enforce conventions here &#8211; but that would be overkill. ;-) </p>
<p><strong>Okay.. so what happens here and how can we use that?</strong></p>
<ol>
<li>The <code>getInstance</code> method returns the <code>AppEnvironment</code> object, if present. So it&#8217;s imperative to have it, because we don&#8217;t want to mess with the original class.</li>
<li><code>method_exists</code> looks in <code>AppEnvironment</code> for a lower-case method name of whatever is in <code>$param</code>. In our case this results to &#8220;http_host&#8221;.</li>
<li>If found, it calls the method on the <code>$instance</code> and returns the result. The result should be <code>boolean</code>.</li>
</ol>
<p>I&#8217;ve edited my <code>app_environment.php</code> and added the following method:</p>
<pre class="sh_php">
/**
 * Support Arrays in HTTP_HOST param matching
 *
 * @param mixed $value string or array of hostnames
 * @return boolean
 */
public function http_host($value) {
	if (is_array($value)) {
		foreach ($value as $host) {
			if (env('HTTP_HOST') == $host) {
				return true;
			}
		}
	} else {
		if (env('HTTP_HOST') == $value) {
			return true;
		}
	}
	return false;
}
</pre>
<p>Should be pretty self explaining. Default to false. If <code>$value</code> is an array, walk through it and return true on the first match. If it&#8217;s not an array just check if $value matches the current HTTP_HOST. </p>
<p>With that in place i can now tweak my &#8217;server&#8217; config in the environment setup.</p>
<pre class="sh_php">App::import('Vendor', 'Environment');

Environment::configure('development',
	array(
		'server' => array('localhost', 'testapp-local.com') // there we go!
	),
	array(
		'debug' => Configure::read('Env.development.debug'),
		'security' => Configure::read('Env.development.security')
	)
);
Environment::start();
</pre>
<p>That&#8217;s it. From now on we have the &#8220;development&#8221; environment running if the current HTTP_HOST is either &#8220;localhost&#8221; or &#8220;testapp-local.com&#8221;. </p>
<p><strong>Edit:</strong> Oh.. btw. This is not just about http_host. You can of course add helper methods for any other param.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/07/environment-class-support-methods-in-param-matching/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>QLColorCode and CakePHP Templates</title>
		<link>http://cakealot.com/2009/07/qlcolorcode-and-cakephp-templates/</link>
		<comments>http://cakealot.com/2009/07/qlcolorcode-and-cakephp-templates/#comments</comments>
		<pubDate>Sat, 18 Jul 2009 07:37:19 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP Hints]]></category>
		<category><![CDATA[highlight]]></category>
		<category><![CDATA[leopard]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[quicklook]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=410</guid>
		<description><![CDATA[Mac OSX "Leopard" HowTo: Add CakePHP View extensions to the QLColorCode QuickLook Plugin.]]></description>
			<content:encoded><![CDATA[<p><strong>Mac OSX Hint</strong>: If you use the <a href="http://code.google.com/p/qlcolorcode/" target="_blank">QLColorCode</a> plugin for <strong>QuickLook</strong> to get fancy highlight when viewing a file, you might want to have the same when viewing CakePHP <code>*.ctp</code> and <code>*.thtml</code> files.</p>
<p>It involves a bit of hacking, but not much.<br />
<span id="more-410"></span></p>
<h3>Edit Info.plist</h3>
<p><img src="http://static.cakealot.com/wp-content/uploads/2009/07/filestochange-300x188.png" alt="filestochange" title="filestochange" width="300" height="188" class="alignleft size-medium wp-image-417" />First you need to tell the Plugin about the custom file-types. For that you need to view the package contents of <code>QLColorCode.qlgenerator</code> file.</p>
<p>It should be in <code>/Library/QuickLook</code> or in your home directory <code>~/Library/QuickLook</code>.</p>
<p>Open the &#8220;Contents&#8221; folder and open the <code>Info.plist</code> file. Any decent texteditor will do. Now scroll down to line 270 or so. There you will find the <code>UTTypeConformsTo</code> sections. </p>
<p>I just copied the &#8220;css&#8221; block (from &lt;dict&gt; to &lt;/dict&gt;) and placed it right under it.</p>
<p>- Change the <code>UTTypeDescription</code> to &#8220;PHP File&#8221;.<br />
- Change the <code>UTTypeIdentifier</code> to &#8220;public.php&#8221;. </p>
<p>Then theres a dict-subsection with <code>public.filename-extension</code> as key.<br />
If you followed my steps it should contain &#8220;css&#8221; (if so, replace &#8220;css&#8221; with &#8220;php&#8221;).</p>
<p>- Duplicate the <code>&lt;string&gt;</code> part a couple times and add &#8220;ctp&#8221; and &#8220;thtml&#8221; to the array. </p>
<p>The complete section should then look like this:</p>
<pre class="sh_html"><code>
&lt;dict>
	&lt;key>UTTypeConformsTo&lt;/key>
	&lt;array>
		&lt;string>public.source-code&lt;/string>
	&lt;/array>
	&lt;key>UTTypeDescription&lt;/key>
	&lt;string>PHP File&lt;/string>
	&lt;key>UTTypeIdentifier&lt;/key>
	&lt;string>public.php&lt;/string>
	&lt;key>UTTypeTagSpecification&lt;/key>
	&lt;dict>
		&lt;key>public.filename-extension&lt;/key>
		&lt;array>
			&lt;string>php&lt;/string>
			&lt;string>ctp&lt;/string>
			&lt;string>thtml&lt;/string>
		&lt;/array>
	&lt;/dict>
&lt;/dict>
</code></pre>
<p>Save and close the file. Your QuickLook plugin now recognizes ctp and thtml files. That&#8217;s great, but you need to do one more thing to actually get PHP syntax coloring.</p>
<h3>Edit colorize.sh</h3>
<p>Back in your Finder with the &#8220;package contents&#8221; navigate into the &#8220;Resources&#8221; folder and open the contained &#8220;colorize.sh&#8221;. That&#8217;s a shellscript which does a bit of evaluation before it actually calls the highlight program. </p>
<p>Around line 36 you&#8217;ll find something like a switch-block. Here it&#8217;s called &#8220;case&#8221;&#8230; Anyway. You might recognize the schema here and see that each &#8220;case&#8221; corresponds to a file extension. This is where we jump in and add our <code>.ctp</code> and <code>.thtml</code> sections. </p>
<p>Note that there is no &#8220;break&#8221; statement like in PHP. Each case ends with a double semicolon instead. </p>
<pre class="sh_php"><code>    *.ctp )
        lang=php
        ;;
    *.thtml )
        lang=php
        ;;
</code></pre>
<p>You can put these somewhere in the middle. As said, watch out for the semicolons. Save and close the file. Since you&#8217;ve modified the Info.plist in the first step you might have to let your system know about the changes. Execute the following two commands on your Terminal/shell to refresh the QuickLook service.</p>
<pre class="sh_php">qlmanage -r
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f -v /Library/QuickLook/QLColorCode.qlmanager</pre>
<p>Make sure it&#8217;s pointing to the correct plugin path (at the end of the long command..).<br />
After refreshing QL it should work right away. Go to your &#8220;views&#8221; folder and try it out.</p>
<p><a href="http://static.cakealot.com/wp-content/uploads/2009/07/quicklook-for-ctp.png" class="highslide-image" onclick="return hs.expand(this);" target="_blank" title="opens a new window"><img src="http://static.cakealot.com/wp-content/uploads/2009/07/quicklook-for-ctp-300x235.png" alt="quicklook-for-ctp" title="quicklook-for-ctp" width="300" height="235" class="size-medium wp-image-431" /></a></p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/07/qlcolorcode-and-cakephp-templates/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quickie: SecurityComponent, Ajax and input.disabled</title>
		<link>http://cakealot.com/2009/04/quickie-securitycomponent-ajax-and-inputdisabled/</link>
		<comments>http://cakealot.com/2009/04/quickie-securitycomponent-ajax-and-inputdisabled/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 12:59:05 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP Hints]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[blackhole]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=306</guid>
		<description><![CDATA[Watch out for input.disabled = true when using SecurityComponent. A short story about what went wrong and why, plus a sidenote about SecurityComponent and Ajax.]]></description>
			<content:encoded><![CDATA[<p><strong>Don&#8217;t mess wit teh formz.</strong></p>
<p>I thought it&#8217;s cool to disable a field simply by using the <code>disabled</code> Element property. Being distracted by other parts in the app i just applied it and left it alone &#8211; &#8220;How can this be bad, right?&#8221;. After some more time i did test the form again and found myself being blackholed all of a sudden &#8211; whaaa? &#8211; Took me some time to find out what the problem was (grrr).</p>
<h3>Here&#8217;s the reason</h3>
<blockquote><p>If you disable a field using Javascript, the field name and its value never reaches the server. This of course invalidates the Security Token and thus leads to a blackhole.</p></blockquote>
<p>I must admit that this was kinda stupid but that&#8217;s how things can go after some hours in CakePHP-land. :-)</p>
<p>Some &#8220;validation scripts&#8221; also apply disable. So look out for that too. Just don&#8217;t mess around with the fields (..much), and avoid prefilled values using <code>array('value' => 'bla')</code> if plan to change the value with Javascript. A good workaround to that is to set the &#8220;initial value&#8221; on page load using Javascript. SecurityComponent and Ajax then shouldn&#8217;t be a problem at all.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/04/quickie-securitycomponent-ajax-and-inputdisabled/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eventful &#8211; A CakePHP Event System</title>
		<link>http://cakealot.com/2009/04/eventful-a-cakephp-event-system/</link>
		<comments>http://cakealot.com/2009/04/eventful-a-cakephp-event-system/#comments</comments>
		<pubDate>Sat, 18 Apr 2009 13:27:12 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Behaviors]]></category>
		<category><![CDATA[Callbacks]]></category>
		<category><![CDATA[components]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[models]]></category>
		<category><![CDATA[opensource]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=343</guid>
		<description><![CDATA[As promised in the comments of the most recent entry i created a repo for my event system. 
It&#8217;s currently under heavy development, yet ready to use. I don&#8217;t think the interface will change much from here on out. The installation is similar to the DebugKit. Put the &#8220;eventful&#8221; plugin into your plugins folder and [...]]]></description>
			<content:encoded><![CDATA[<p>As promised in the comments of the <a href="http://cakealot.com/2009/04/more-on-possible-events-in-cakephp/" title="More on possible events in CakePHP">most recent entry</a> i created a repo for my event system. </p>
<p>It&#8217;s currently under heavy development, yet ready to use. I don&#8217;t think the interface will change much from here on out. The installation is similar to the DebugKit. Put the &#8220;eventful&#8221; plugin into your plugins folder and add the Behavior or Component to your app. This will include all dependencies and the system is ready to use.</p>
<p>Only one thing is different from regular plugins. There is a seperate &#8220;events&#8221; folder which is a empty layout for the system and the place for your event listener classes. </p>
<p>The System is also plugin aware. If you want to enrich your base application with event handlers from plugins just copy the &#8220;events&#8221; folder layout into the plugin directory and prefix the class filenames with the plugin name. (just like app_controller).</p>
<pre class="sh_php"># /app/plugins/pizza/events/controller/pizza_users_controller_events.php
class PizzaUsersControllerEvents extends AppControllerEvents ...</pre>
<p>I&#8217;ve created a (messy) README which goes on about how to use it. Basicly the workflow is: <strong>a)</strong> add the component/behavior, <strong>b)</strong> use the dispatch/dispatchEvent method in your actions/methods, <strong>c)</strong> create or modify the event listener class and add a matching &#8220;on&#8221; method. <strong>d)</strong> go nuts.</p>
<pre class="sh_php">class UsersController extends AppController {
   var $components = array('Eventful.Event');
}</pre>
<pre class="sh_php">class UsersController extends AppController {
   var $components = array('Eventful.Event');
   function logout() {
      $this->Event->dispatch('UserLogout', array(
           'auth' => $this->Auth->user()
      ));
   }
}</pre>
<p>File: /app/events/controller/users_controller_events.php</p>
<pre class="sh_php">class UsersControllerEvents extends AppControllerEvents {
   function onUserLogout() {
      $this->log('User logged out...')
   }
}</pre>
<p>Unlike the original implementation the plugin triggers all handlers of the same name. So if you have a &#8220;userLogout&#8221; event fired from your UsersController::logout() action the dispatchEvent method will trigger all possible candidates. Regardless in which listener class the method is. </p>
<pre class="sh_php">class MembersControllerEvents extends AppControllerEvents {
   function onUserLogout($event) {
      if ($event->auth['isMember'])
          $this->log('Member logged out...')
   }
}</pre>
<p>Enjoy. You can find it on github:</p>
<p><a href=" http://github.com/m3nt0r/eventful-cakephp" title="GitHub.com Repository">http://github.com/m3nt0r/eventful-cakephp</a></p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/04/eventful-a-cakephp-event-system/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>More on possible Events in CakePHP</title>
		<link>http://cakealot.com/2009/04/more-on-possible-events-in-cakephp/</link>
		<comments>http://cakealot.com/2009/04/more-on-possible-events-in-cakephp/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 18:38:52 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[actions]]></category>
		<category><![CDATA[controllers]]></category>
		<category><![CDATA[dashboard]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[examples]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[listener]]></category>
		<category><![CDATA[scenarios]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=53</guid>
		<description><![CDATA[As a follow up to: Events in CakePHP &#8211; I really like it 
Let&#8217;s say you have unkown entities in your project &#8211; totally dynamic. Let it be a plugin, another model, not associated at all. Getting new functionality into an existing app can be a pain. 
Events do help alot in this case, depending [...]]]></description>
			<content:encoded><![CDATA[<p><em>As a follow up to: <a href="http://cakealot.com/2008/12/events-in-cakephp-i-really-like-it/">Events in CakePHP &#8211; I really like it</a></em> </p>
<p>Let&#8217;s say you have unkown entities in your project &#8211; totally dynamic. Let it be a plugin, another model, not associated at all. Getting new functionality into an existing app can be a pain. </p>
<p>Events do help alot in this case, depending on how you layed out the triggers. Events notify all possible candidates (&#8221;can u handle?&#8221;) every time something interesting is happening, like &#8220;user logged in&#8221;, &#8220;new image was uploaded&#8221;, &#8220;post has been edited by xyz&#8221;, and so forth.</p>
<p>In this post i want to explain more about the benefits and how events could make your life alot easier in the long run.  </p>
<h3>Some example</h3>
<p>Think of a users dashboard: A dashboard usually has alot of links to various aspects of the application, often categorized in blocks. You have a block for the user account itself, a block for the latest comments, a block to upload a new image, etc.. </p>
<p>Now maybe user XYZ has access to post blogs, but maybe not. And maybe there is no blogging function at all. We could now bake our blogging MVC and write it into the dashboard action. No problem, right? But the more you add, you more have to maintain and watch out for. I know many projects with complicated group setups and stuff so this isn&#8217;t always that simple. </p>
<p>This is where Events come in handy. Let&#8217;s scratch the above and think our dashboard action is empty and there&#8217;s a single call to the EventDispatcher (the thing i use). If we now simply fire a &#8220;dashboardView&#8221; event <strong>any</strong> part of the codebase that can handle this event will perform its designated task independently. </p>
<pre class="sh_php">
function dashboard() {
    $data = $this->Events->dispatch('dashboardView', array(
        'user_id' => $this->Auth->user('id')
    ));
    $this->set('data', $data);
}
</pre>
<p>This allows the blog-facility (for example) to run code and add data to the dashboard() action, so that the action itself remains clean. </p>
<p>Normally you would load up some settings array with true/false, or you would just add a if/else in the <code>dashboard()</code> action. </p>
<pre class="sh_php">
function dashboard() {
   if ($mayAuthorBlog) ..
   if ($mayPostNews) ..
   if ($justRegistered) ..
   ...
}
</pre>
<p>All this is not necessary when using events, since events usually don&#8217;t care if they are handled. They are just fired and poke around and execute whatever responds. </p>
<p>With &#8220;poking-around&#8221; i mean that you may have multiple handlers for a single event. So the Post, Image, Blog, Friend MVC .. all of them can respond to the current action. Even if they are out of scope.</p>
<h3>The other way around</h3>
<p>If we decide to drop any functionality later on, we just delete the event-listener, or delete the method that usually would respond. A common task may be: &#8220;The blogging dashboard item should not be intergrated into the dashboard anymore&#8221;. Remove the listener from your Blog-MVC and you&#8217;re done. Not touching the working <code>dashboard()</code> action at all.</p>
<p>See, if we wrote this without Events the removal of this functionality would require that we delete the if/else (or what have you) from the <code>dashboard()</code> action, which is destructive and eventually leads to bugs and headaches. Removal of event-listeners don&#8217;t harm your app. </p>
<h3>&#8230;for the non believers</h3>
<p>One can argue: &#8220;Why not simply add a private method for that?&#8221; </p>
<p>Well.. the keyword is <strong>&#8220;unkown&#8221;</strong>. Events enrich a function by providing an <strong>open interface</strong> to hook up to (so to speak). If you wrote something new you just provide the listener for your current/core app and be done with it. </p>
<pre class="sh_php">
class UserControllerEvents extends AppControllerEvents {
   var $name = 'UserController';
   function onDashboardView($event) {
       $event->Controller->User->logVisit($event->user_id);
   }
}

class BlogControllerEvents extends AppControllerEvents {
   var $name = 'BlogController';
   function onDashboardView($event) {
       return $event->Controller->Blog->getMostRecent();
   }
}
</pre>
<p>Private Methods or &#8220;helping&#8221; methods are bound to the main codebase and scope and as such quickly become obsolete or hard to manage. It&#8217;s also not so easy to call other parts of your cake app &#8220;just like that&#8221;. The system described works as one huge layer and has access to everything. </p>
<h3>What do you think?</h3>
<p>Let me know in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/04/more-on-possible-events-in-cakephp/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Adding &#8220;empty&#8221; to list-find, for the lazy</title>
		<link>http://cakealot.com/2009/04/adding-empty-to-list-find/</link>
		<comments>http://cakealot.com/2009/04/adding-empty-to-list-find/#comments</comments>
		<pubDate>Mon, 13 Apr 2009 17:32:04 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP Snippets]]></category>
		<category><![CDATA[AppModel]]></category>
		<category><![CDATA[empty]]></category>
		<category><![CDATA[find]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[list]]></category>
		<category><![CDATA[list-find]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[select]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=317</guid>
		<description><![CDATA[Currently i use the scaffold views alot to bake a simple admin interface. What annoyed me was that 'empty' is not set on select inputs. I could of course go through all add/edit views and add it, but i thought i rather modify the result to include a empty entry.]]></description>
			<content:encoded><![CDATA[<p>Currently i use the scaffold views alot to bake a simple admin interface. What annoyed me was that &#8216;empty&#8217; is not set on select inputs. I could of course go through all add/edit views and add it, but i thought i rather modify the result to include a empty entry.</p>
<h3>Always add a &#8220;empty&#8221; entry to the result</h3>
<pre class="sh_php">
function find($conditions = null, $fields = array(), $order = null, $recursive = null) {
	if (is_array($conditions)) {
		return parent::find($conditions, $fields, $order, $recursive); // old interface
	} else {
		switch ($conditions) {
			case 'list':
				$result = parent::find($conditions, $fields, $order, $recursive);
				$return = $result; // default

				if (!empty($result)) {
					$return = aa('', __("-- please select --", true));
					foreach ($result as $id => $name)
						$return[$id] = $name;
				}

				return $return;
			break;

			default:
				return parent::find($conditions, $fields, $order, $recursive);
			break;
		}
	}
}
</pre>
<p>Okay, that works and i don&#8217;t have to add &#8216;empty&#8217; everywhere. I modified the method a little further (not actually using it, but maybe someone likes it..) for you to grab. It will still require that you modify all files, but this way you have more control.</p>
<h3>Adding &#8220;empty&#8221; to the find() options array</h3>
<pre class="sh_php">
function find($conditions = null, $fields = array(), $order = null, $recursive = null) {

	if (is_array($conditions)) {
		return parent::find($conditions, $fields, $order, $recursive); // old interface
	} else {
		switch ($conditions) {
			case 'list':
				$result = parent::find($conditions, $fields, $order, $recursive);
				$return = $result; // default

				if (!empty($result) &#038;&#038; isset($fields['empty']) &#038;&#038; $fields['empty'] != false) {
					$return = aa('', $fields['empty']); // begin with whatever is in 'empty'
					foreach ($result as $id => $name)
						$return[$id] = $name;
				}

				return $return;
			break;

			default:
				return parent::find($conditions, $fields, $order, $recursive);
			break;
		}
	}
}
</pre>
<p>Everything above goes to <code>app_model.php</code> of course. With the last snippet you are able to move the &#8220;empty&#8221; option to the controller and go like this:</p>
<pre class="sh_php">
$categories = $this->Category->find('list', array('empty' => __("-- please select --", true)));
</pre>
<p>Enjoy &#038; Happy Easter!</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/04/adding-empty-to-list-find/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Probably watching too many RoR demos lately</title>
		<link>http://cakealot.com/2009/03/probably-watching-too-many-ror-demos-lately/</link>
		<comments>http://cakealot.com/2009/03/probably-watching-too-many-ror-demos-lately/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 12:12:24 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[CakePHP Snippets]]></category>
		<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[Behaviors]]></category>
		<category><![CDATA[Experiments]]></category>
		<category><![CDATA[funstuff]]></category>
		<category><![CDATA[Model]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=310</guid>
		<description><![CDATA[Somewhat ActivRecord'ish for CakePHP.. ]]></description>
			<content:encoded><![CDATA[<p>Not sure why, but this ActiveRecord thing appealed to me and so i wrote a short behavior (nothing to release, really..) that kinda emulates RoR a little more&#8230; However, i think this is something for the bin. Or does anyone see a need or benefit of something like this:</p>
<pre class="sh_php">
$this->User->find('first');
pr ($this->User->record); // has the full record

$this->User->record->username = 'BlaBlubb';
$this->User->record->email = 'bla@blubb.com';
$this->User->save(); // saves full record 

$this->User->find('first');
pr ($this->User->record); // jup, that worked.
</pre>
<p>Useful? hmm.. maybe. It was fun to explore though. If you are interested in the Behavior, i&#8217;ve <a href="http://gist.github.com/80504">put it into a gist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/03/probably-watching-too-many-ror-demos-lately/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
