<?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>Derilicious&#187; Posts tagged with CakePHP &#8211; Page  &#8211; Derilicious</title> <atom:link href="http://derickng.com/posts/tag/cakephp/feed" rel="self" type="application/rss+xml" /><link>http://derickng.com</link> <description>A blog on web development technicalities by Derick Ng</description> <lastBuildDate>Sun, 20 Dec 2009 12:18:03 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <item><title>CakePHP&#8217;s HtmlHelper::link() Escaping of Attribute Values Gotcha</title><link>http://derickng.com/posts/80-cakephps-htmlhelperlink-escaping-of-attribute-values-gotcha</link> <comments>http://derickng.com/posts/80-cakephps-htmlhelperlink-escaping-of-attribute-values-gotcha#comments</comments> <pubDate>Wed, 15 Apr 2009 09:18:29 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[HtmlHelper]]></category><guid
isPermaLink="false">http://derickng.com/?p=80</guid> <description><![CDATA[Just updated pHing Classifieds to CakePHP 1.2.2.8120 and that breaks some JavaScript codes for deleting of messages.  Turns out the escape attribute is now passed on to Helper::parseAttributes() so if you have an image link like me, you will have to remember to manually escape the attribute values.&#60;?= $appHtml-&#62;link(
$appHtml-&#62;image(&#039;icons/bin.png&#039;),
[...]]]></description> <content:encoded><![CDATA[<p>Just updated <a
title="pHing Classifieds" href="http://phing.com">pHing Classifieds</a> to <a
href="http://bakery.cakephp.org/articles/view/release-1-2-2-8120">CakePHP 1.2.2.8120</a> and that breaks some JavaScript codes for deleting of messages.  Turns out the escape attribute is now passed on to Helper::parseAttributes() so if you have an image link like me, you will have to remember to manually escape the attribute values.</p><pre class="brush: php">
&lt;?= $appHtml-&gt;link(
   $appHtml-&gt;image(&#039;icons/bin.png&#039;),
   &#039;#&#039;,
   array(
      &#039;escape&#039; =&gt; false,
      &#039;onclick&#039; =&gt; h(&#039;if (confirm(&quot;True?&quot;)) alert (&quot;Yes&quot;); return false;&#039;)
   )
) ?&gt;
</pre><p>Not a big issue and it probably seem more consistent that the escape option is applied to both the link title and the HTML attributes. See ticket <a
href="https://trac.cakephp.org/ticket/6071">#6071</a> for why it was changed and <a
href="https://trac.cakephp.org/changeset/8053/branches/1.2.x.x/cake/libs/view/helpers/html.php">what was changed</a>.</p> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/80-cakephps-htmlhelperlink-escaping-of-attribute-values-gotcha/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Working with Associations using CakePHP</title><link>http://derickng.com/posts/56-working-with-associations-using-cakephp</link> <comments>http://derickng.com/posts/56-working-with-associations-using-cakephp#comments</comments> <pubDate>Sun, 18 Jan 2009 14:14:34 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[Associations]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[ContainableBehavior]]></category> <category><![CDATA[Model]]></category><guid
isPermaLink="false">http://derick.lyniq.com/?p=56</guid> <description><![CDATA[I was asked by Niraja Mulye of Packt Publishing if I would be interested in publishing an article on my blog from the book, CakePHP Application Development. Since it seems relevant to any starting out with CakePHP, I guess why not.
Instead of copying and pasting what was sent, I found two articles which seemed like [...]]]></description> <content:encoded><![CDATA[<p>I was asked by Niraja Mulye of <a
href="http://www.packtpub.com">Packt Publishing</a> if I would be interested in publishing an article on my blog from the book, <a
href="http://www.packtpub.com/cakephp-application-development">CakePHP Application Development</a>. Since it seems relevant to any starting out with CakePHP, I guess why not.</p><p>Instead of copying and pasting what was sent, I found two articles which seemed like the original source. Being properly formatted, I guess it will be more appropriate for me to point them to you. The first article titled, <a
href="http://www.packtpub.com/article/working-with-simple-associations-using-cakephp">Working with Simple Associations using CakePHP</a> talks about the basic belongsTo, hasOne and hasMany assocations while the second article titled, <a
href="http://www.packtpub.com/article/working-with-complex-associations-using-cakephp">Working with Complex Associations using CakePHP</a> tackles the hasAndBelongsToMany association where most beginners have difficulty with.</p><p>The articles will be useful for anyone starting out but unfortunately, CakePHP had gone through lots of changes and the book (published on July 2008) is based on an older version of CakePHP. So now there are actually better ways of dealing with associations using the <a
href="http://book.cakephp.org/view/474/Containable">Containable Behavior</a>. The Containable Behavior binds and unbinds model on the fly, automatically setting the recursive level to suit. This means you no longer have to bother about setting the recursive level as long as you &#8220;contain&#8221; your <code>find()</code> queries. I am mentioning this because I have to warn against the setting of recursive level directly.</p><pre class="brush: php">

// All models have recursive level set to 1 by default
$this-&gt;Author-&gt;recursive = 2;
$this-&gt;Author-&gt;id = 1001;
$this-&gt;Author-&gt;find(&#039;first&#039;); // Return results based on recursive level of 2
// some
// codes
// in
// between
$this-&gt;Author-&gt;find(&#039;all&#039;); // Return results based on recursive level of 2 (as set previously) and not 1!
</pre><p>This causes CakePHP to retrieve more data than it should when it is unintended by you. My suggestion is to have all models default to recursive level -1 by setting it in the AppModel and let &#8220;contain&#8221; handle the rest.</p><pre class="brush: php">

$this-&gt;Author-&gt;id = 1001;
$this-&gt;Author-&gt;find(&#039;first&#039;, array(&#039;contain&#039; =&gt; &#039;Book&#039;)); // Returns author 1001 and all books authored by him/her
$this-&gt;Author-&gt;find(&#039;all&#039;); // Returns all authors only
</pre><p>How nice!</p> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/56-working-with-associations-using-cakephp/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>What a Start to 2009</title><link>http://derickng.com/posts/54-what-a-start-to-2009</link> <comments>http://derickng.com/posts/54-what-a-start-to-2009#comments</comments> <pubDate>Sun, 11 Jan 2009 15:19:27 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[Planet CakePHP]]></category><guid
isPermaLink="false">http://derick.lyniq.com/posts/54-what-a-start-to-2009</guid> <description><![CDATA[5 days of downtime and finally back online. A faulty RAID card leading to all sorts of restoration problems. Totally unacceptable. I have to probably start looking out for a new web hosting provider but what a hassle.
For fellow Planet CakePHP subscribers, I apologise for having you missed 5 days of CakePHP news. [...]]]></description> <content:encoded><![CDATA[<p>5 days of downtime and finally back online. A faulty RAID card leading to all sorts of restoration problems. Totally unacceptable. I have to probably start looking out for a new web hosting provider but what a hassle. <img
src='http://derickng.com/wordpress/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /></p><p>For fellow Planet CakePHP subscribers, I apologise for having you missed 5 days of CakePHP news. Now that it is back, keep reading.</p><p>Happy New Year!</p> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/54-what-a-start-to-2009/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Planet CakePHP With Multiple Feeds</title><link>http://derickng.com/posts/52-planet-cakephp-with-multiple-feeds</link> <comments>http://derickng.com/posts/52-planet-cakephp-with-multiple-feeds#comments</comments> <pubDate>Sat, 20 Dec 2008 04:04:37 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[Planet CakePHP]]></category><guid
isPermaLink="false">http://derick.lyniq.com/?p=52</guid> <description><![CDATA[Short of having an actual announcement feed for Planet CakePHP, this seems like the fastest way to get information to all you subscribers.
If you were wondering about the few non-English items showing up in the feed, you actually have a choice to subscribe to a separate feed which aggregates websites written in English/Portuguese/Spanish. [...]]]></description> <content:encoded><![CDATA[<p>Short of having an actual announcement feed for <a
href="http://planetcakephp.org">Planet CakePHP</a>, this seems like the fastest way to get information to all you subscribers. <img
src='http://derickng.com/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /></p><p>If you were wondering about the few non-English items showing up in the feed, you actually have a choice to subscribe to a separate feed which aggregates websites written in <a
href="http://planetcakephp.org/aggregator/categories/english">English</a>/<a
href="http://planetcakephp.org/aggregator/categories/portuguese">Portuguese</a>/<a
href="http://planetcakephp.org/aggregator/categories/spanish">Spanish</a>. Of course, it ain&#8217;t gonna stop there. The plan is to have all CakePHP-related websites aggregated regardless of language. That&#8217;s why it is called the Planet right?</p><p>Thanks/Obrigado/Gracias to everyone for submitting websites to be added. Keep them coming!</p> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/52-planet-cakephp-with-multiple-feeds/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>CakePHP Losing or Missing Session?</title><link>http://derickng.com/posts/36-cakephp-losing-or-missing-session</link> <comments>http://derickng.com/posts/36-cakephp-losing-or-missing-session#comments</comments> <pubDate>Sat, 13 Dec 2008 05:23:40 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[CakeSession]]></category> <category><![CDATA[Internet Explorer]]></category><guid
isPermaLink="false">http://derick.lyniq.com/?p=36</guid> <description><![CDATA[I have my fair share of problems with session in Cake so I thought I can share the two important configurations in app/config/core.php which affects how Cake handles the session.
Session.checkAgent
Setting this to TRUE means Cake will store the user agent header of a request when a new session is created. On subsequent request, the user [...]]]></description> <content:encoded><![CDATA[<p>I have my fair share of problems with session in Cake so I thought I can share the two important configurations in <code>app/config/core.php</code> which affects how Cake handles the session.</p><p><code>Session.checkAgent</code><br
/> Setting this to <code>TRUE</code> means Cake will store the <a
href="http://en.wikipedia.org/wiki/User_agent">user agent</a> header of a request when a new session is created. On subsequent request, the user agent header sent is compared with the value stored in the session. If it does not match, the current session will be destroyed and a new session gets created.</p><p>This rarely causes problem unless you have embedded Flash or Java objects making separate requests to the application. You must take note to send the user agent string of the browser in that case. If you are using something like Aurigma&#8217;s <a
href="http://www.aurigma.com/Products/ImageUploader/">Image Uploader</a> where the user agent is not configurable, you have to set this to <code>FALSE</code> instead.</p><p><code>Security.level</code><br
/> Besides the session timeout, this will affect whether the session ID gets regenerated between requests and whether <a
href="http://sg.php.net/manual/en/session.configuration.php#ini.session.referer-check">session.referer_check</a> is set.</p><p>With session ID regenerated, there will be problems when your application does any Ajax calls. An Ajax request does not set the cookie as requested by the server which causes the browser to send the session ID of a previous request which will have already been destroyed.</p><p>Referrer check is done on the hostname level in Cake and in theory it should not cause any problems. Weirdly, I have a one time login link which redirects user to another location and it works in Firefox but not Internet Explorer. My guess is that Internet Explorer does not set the referrer header properly if it gets redirected. You can log the <code>HTTP_REFERER</code> headers to verify that though.</p><p>Anyways, the valid values:</p><ul><li>&#8220;<code>high</code>&#8221; &#8211; session ID regenerated and referrer check set</li><li>&#8220;<code>medium</code>&#8221; &#8211; referrer check set</li><li>&#8220;<code>low</code>&#8221; &#8211; none</li></ul> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/36-cakephp-losing-or-missing-session/feed</wfw:commentRss> <slash:comments>14</slash:comments> </item> <item><title>Soft Deletable Behavior and the Model::exists() gotcha</title><link>http://derickng.com/posts/31-soft-deletable-behavior-and-the-modelexists-gotcha</link> <comments>http://derickng.com/posts/31-soft-deletable-behavior-and-the-modelexists-gotcha#comments</comments> <pubDate>Sat, 15 Nov 2008 03:30:00 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[Model]]></category> <category><![CDATA[SoftDeletableBehavior]]></category><guid
isPermaLink="false">http://derick.lyniq.com/?p=31</guid> <description><![CDATA[If you ever used the Soft Deletable Behavior, you will realise that Model::del() always returns a FALSE. This is expected after knowing that the behavior intercepts the delete request by saving the deleted flag and date then returning FALSE so the actual delete don&#8217;t happen.
So since I can&#8217;t rely on the returned value of Model::del(), [...]]]></description> <content:encoded><![CDATA[<p>If you ever used the Soft Deletable Behavior, you will realise that <code>Model::del()</code> always returns a <code>FALSE</code>. This is expected after knowing that the behavior intercepts the delete request by saving the deleted flag and date then returning <code>FALSE </code>so the actual delete don&#8217;t happen.</p><p>So since I can&#8217;t rely on the returned value of <code>Model::del()</code>, this is what I thought will work until one fine day the application returns a failure when the record seems to be soft deleted correctly.</p><pre class="brush: php">

// some action of a controller
$this-&gt;Model-&gt;id = (int) $idPassed;
$this-&gt;Model-&gt;del();

if ($this-&gt;Model-&gt;exists()) {
    // say success!
} else {
    // say failure!
}
</pre><p>Alas, <code>Model::exists()</code> sets callbacks to <code>FALSE</code> in its <code>find('count')</code> call. So this means no <code>beforeFind</code> nor <code>afterFind</code> callbacks gets executed. This is understandable since Model uses <code>exists()</code> in many places where it needs to reflect true existence. So to get the expected results, we have to set callbacks to <code>TRUE</code> instead.</p><pre class="brush: php">

$this-&gt;exists(array(&#039;callbacks&#039; =&gt; true));
</pre>]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/31-soft-deletable-behavior-and-the-modelexists-gotcha/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Multiple Validation Sets in CakePHP</title><link>http://derickng.com/posts/9-multiple-validation-sets-in-cakephp</link> <comments>http://derickng.com/posts/9-multiple-validation-sets-in-cakephp#comments</comments> <pubDate>Wed, 23 Jul 2008 15:19:26 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[Validation]]></category><guid
isPermaLink="false">http://derick.lyniq.com/?p=9</guid> <description><![CDATA[Jonathon Snook wrote about multiple validation sets in CakePHP and it reminded me how often we require rather different sets of validation rules for a single model. I have always enjoyed learning how others approached similar problems so I think I shall share mine too.
A very relevant example is the User model where we usually [...]]]></description> <content:encoded><![CDATA[<p>Jonathon Snook wrote about <a
href="http://snook.ca/archives/cakephp/multiple_validation_sets_cakephp/">multiple validation sets in CakePHP</a> and it reminded me how often we require rather different sets of validation rules for a single model. I have always enjoyed learning how others approached similar problems so I think I shall share mine too.</p><p>A very relevant example is the User model where we usually have multiple forms associated. E.g. sign up, profile updates, password reset, etc. Each form have a different set of fields while some share the same fields. My approach is to select a different set of fields for each &#8220;action&#8221; and modify the rules if required. This means I&#8217;ll keep a master set of rules for all the User model fields and call <code>setValidate() </code> for each &#8220;action&#8221;.</p><pre class="brush: php">
/**
 * Set the default validation rules here.
 *
 * @var array
 */
	protected $_validate = array(
		&#039;username&#039; =&gt; array(
			&#039;empty&#039; =&gt; array(
				&#039;required&#039; =&gt; true,
				&#039;rule&#039; =&gt; VALID_NOT_EMPTY,
				&#039;last&#039; =&gt; true
			),
			&#039;invalid&#039; =&gt; array(
				&#039;rule&#039; =&gt; &#039;/^[\w]{3,30}$/&#039;,
				&#039;last&#039; =&gt; true,
				&#039;on&#039; =&gt; &#039;create&#039;
			),
			&#039;exists&#039; =&gt; array(
				&#039;rule&#039; =&gt; &#039;validateUniqueUsername&#039;,
				&#039;last&#039; =&gt; true,
				&#039;on&#039; =&gt; &#039;create&#039;
			)
		),
		&#039;password&#039; =&gt; array(
			&#039;empty&#039; =&gt; array(
				&#039;required&#039; =&gt; true,
				&#039;rule&#039; =&gt; VALID_NOT_EMPTY,
				&#039;last&#039; =&gt; true
			),
			&#039;invalid&#039; =&gt; array(
				&#039;required&#039; =&gt; true,
				&#039;rule&#039; =&gt; &#039;/^.{6,30}$/&#039;,
				&#039;last&#039; =&gt; true
			)
		),
		...
	);
/**
 * Sets just enough fields for validation.
 *
 * @param array $fields List of field names to validate against. If no param
 *                      passed, all fields will be included.
 * @author Derick
 */
	function setValidate($fields = null) {
		if ($fields === null) {
			$this-&gt;validate = $this-&gt;_validate;
		} else {
			$this-&gt;validate = array();
			foreach ($fields as $f) {
				if (isset($this-&gt;_validate[$f])) {
					$this-&gt;validate[$f] = $this-&gt;_validate[$f];
				}
			}
		}
	}
</pre><p>This is a simplified example in my User model where I have the <code>register()</code> function to validate only the fields required for sign up and the <code>updateProfile()</code> function which uses another set of fields with slight different requirement.</p><pre class="brush: php">
function register($data) {
	$fields = array(&#039;username&#039;, &#039;password&#039;, ...);
	$this-&gt;setValidate($fields);
	$this-&gt;save($data, true, $fields);
}

function updateProfile($data) {
	$fields = array(&#039;password&#039;, ...);
	$this-&gt;setValidate($fields);

	// derick: allow user to left password field empty
	unset($this-&gt;validate[&#039;password&#039;][&#039;empty&#039;]);
	$this-&gt;validate[&#039;password&#039;][&#039;invalid&#039;][&#039;allowEmpty&#039;] = true;
	$this-&gt;save($data, true, $fields);

	// derick: you can also call this again to &quot;reset&quot; to the default set of
	// rules but usually we don&#039;t need this
	$this-&gt;setValidate();
}
</pre><p>In other words, I only update the <code>$validate</code> array in the model when required. Some might think it is dangerous since there is a chance of saving data without validation but this works for me. What do the rest of you do?</p> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/9-multiple-validation-sets-in-cakephp/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Extracting PO file with CakePHP I18n Shell</title><link>http://derickng.com/posts/6-extracting-po-file-with-cakephp-i18n-shell</link> <comments>http://derickng.com/posts/6-extracting-po-file-with-cakephp-i18n-shell#comments</comments> <pubDate>Sat, 05 Jul 2008 16:15:39 +0000</pubDate> <dc:creator>Derick Ng</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[CakePHP]]></category> <category><![CDATA[I18n]]></category><guid
isPermaLink="false">http://derick.lyniq.com/?p=6</guid> <description><![CDATA[I have always been religiously wrapping __() and __n() around my texts knowing that it needs to be localized some day. Then it got to me that I never knew how to actually localize it! Out of curiosity,  I went ahead to extract the PO file using the I18n shell.
What it does is basically [...]]]></description> <content:encoded><![CDATA[<p>I have always been religiously wrapping <code>__()</code> and <code>__n()</code> around my texts knowing that it needs to be localized some day. Then it got to me that I never knew how to actually localize it! Out of curiosity,  I went ahead to extract the PO file using the I18n shell.</p><p>What it does is basically look through your entire app folder for files and within each file extract all instances of <code>__()</code> and gang, then grab the tokens necessarily for building the PO file. Now, this is where it gets picky.</p><pre class="brush: php">
// error! invalid marker content!
__(&#039;Delete post #&#039; . $id);
__n(&#039;comment&#039;, &#039;comments&#039;, $array[0]);
__n(&#039;comment&#039;, &#039;comments&#039;, $object-&gt;noOfComments());
__n(&#039;comment&#039;, &#039;comments&#039;, (int) $noOfComments);

// valid! it makes it easier to translate anyways
sprintf(__(&#039;Delete post #%d&#039;, true), $id);
// just $var will work, nothing funky
sprintf(__n(&#039;%d comment&#039;, &#039;%d comments&#039;, $noOfComments, true), $noOfComments);
</pre><p>So if you are thinking of using the I18n shell, you should take note that the text to be translated should really be one single <em>token</em>. Also, the generated file has an extension of .pot but it should really be renamed to .po instead since Cake expects .po files in the locale folder.</p> ]]></content:encoded> <wfw:commentRss>http://derickng.com/posts/6-extracting-po-file-with-cakephp-i18n-shell/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (user agent is rejected)
Database Caching 6/22 queries in 0.004 seconds using disk

Served from: derickng.com @ 2012-02-05 04:10:38 -->
