<?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 Tricks</title>
	<atom:link href="http://cakealot.com/category/cakephp-general/tricks/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>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>How to overwrite HtmlHelper tags</title>
		<link>http://cakealot.com/2009/02/how-to-overwrite-htmlhelper-tags/</link>
		<comments>http://cakealot.com/2009/02/how-to-overwrite-htmlhelper-tags/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 07:20:44 +0000</pubDate>
		<dc:creator>Kjell</dc:creator>
				<category><![CDATA[CakePHP Tricks]]></category>
		<category><![CDATA[AppHelper]]></category>
		<category><![CDATA[configure]]></category>
		<category><![CDATA[HtmlHelper]]></category>
		<category><![CDATA[overwrite]]></category>
		<category><![CDATA[tags]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://cakealot.com/?p=211</guid>
		<description><![CDATA[Using Configure and AppHelper::__construct to allow HtmlHelper::$tags overwrite. ]]></description>
			<content:encoded><![CDATA[<p>In some cases you find it desirable to overwrite the tag templates used by the HtmlHelper. For example if you put all your assets onto a CDN and don&#8217;t want to put the hostname in front of all paths (messy..). </p>
<p>With this small modification in the AppHelper class you can do that in bootstrap using Configure, which also allows you to make the tags conditional if you want.. In short: flexibility!</p>
<p>The code: </p>
<pre class="sh_php">
class AppHelper extends Helper {
	function __construct() {
		if ($this->toString() == 'HtmlHelper') {
			$tags = Configure::read('HtmlHelper.tags');
			if (is_null($tags)) $tags = array();
			$this->tags = am($this->tags, $tags);
		}
	}
}
</pre>
<p>With this in place (file goes to app root and is called app_helper.php) you can now configure your tags whereever you like passing an array with sprintf templates, like so:</p>
<pre class="sh_php">
Configure::write('HtmlHelper.tags', array(
	'image' => '&lt;img src="http://cdn.domain.com%s" %s/&gt;',
));
</pre>
<p>yay!</p>
<p><small>Footnote: is_null checks if Configure value is set. This way you are not forced to set a empty array to your bootstrap just to avoid warnings.</small></p>
]]></content:encoded>
			<wfw:commentRss>http://cakealot.com/2009/02/how-to-overwrite-htmlhelper-tags/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
