<?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>Jamie Nay &#187; php</title>
	<atom:link href="http://jamienay.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://jamienay.com</link>
	<description>A PHP web developer writing about the web.</description>
	<lastBuildDate>Sat, 21 Aug 2010 21:11:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Zend_Search_Lucene Datasource for CakePHP</title>
		<link>http://jamienay.com/2010/01/zend_search_lucene-datasource-for-cakephp/</link>
		<comments>http://jamienay.com/2010/01/zend_search_lucene-datasource-for-cakephp/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 21:53:33 +0000</pubDate>
		<dc:creator>Jamie</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[data retrieval]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://jamienay.com/?p=512</guid>
		<description><![CDATA[Major update January 22/10: much of the content of this article has been updated to reflect the changes to the datasource, the latest version of which you can download on Github. Just out of the oven &#8211; a Zend_Search_Lucene datasource for CakePHP (built with 1.2 but probably works just fine in 1.3) that I originally wrote for an in-house CMS [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Major update January 22/10:</strong> much of the content of this article has been updated to reflect the changes to the datasource, the latest version of which you can <a href="http://github.com/jamienay/zend_search_lucene_source">download on Github</a>.</p>
<p>Just out of the oven &#8211; a Zend_Search_Lucene datasource for CakePHP (built with 1.2 but probably works just fine in 1.3) that I originally wrote for an in-house CMS site search plugin. I can&#8217;t release the plugin itself (and there&#8217;s so much CMS-specific code that it would need a lot of work to make it generic anyway), but I thought that someone might find the datasource itself useful. It&#8217;s pretty basic at this point and doesn&#8217;t implement some of the fancier Zend_Search_Lucene features such as sorting (it just returns sorted in score order, which is probably what you want anyway).</p>
<p>Zend_Search_Lucene is a text-based search index system for developers who don&#8217;t want to (or can&#8217;t) use a database for search indexing.</p>
<p><a href="http://github.com/jamienay/zend_search_lucene_source">Download the current version of the ZendSearchLuceneDatsource from my Github repository</a>.</p>
<p>I won&#8217;t go into detail about how to add data into the Lucene database since the <a href="http://framework.zend.com/manual/en/zend.search.lucene.html">Zend Framework documention</a> is so good (CakePHP should be jealous!). You&#8217;ll find all the info you need there. There are also a couple of older articles out there that show how you can integrate Zend_Search_Lucene into CakePHP:</p>
<ul>
<li><a href="http://cakephptips.blogspot.com/2008/04/build-your-own-search-engine-in-php_5060.html">Build your own search engine in PHP</a></li>
<li><a href="http://bakery.cakephp.org/articles/view/integrating-zend-framework-lucene-with-your-cake-application">Integrating Zend Framework Lucene with your Cake Application</a></li>
</ul>
<p><strong>Setup</strong></p>
<p><strong>First</strong>, copy zend_search_lucene.php to models/datasources.</p>
<p>Then, you&#8217;ll need to download the Zend_Search_Lucene library from the Zend Framework website and put some files into your /vendors directory:</p>
<ul>
<li>Zend/Search (the directory and all of its contents)</li>
<li>Zend/Exception.php</li>
</ul>
<p>You&#8217;ll also need to update your include path to include app/vendors, since the Zend Framework loads a lot of classes on its own. I also made a little autoload function to make the loading of Zend Framework classes easier. Put the following code somewhere common, such as app/bootstrap.php:</p>
<pre class="brush: php">
ini_set(&#039;include_path&#039;, ini_get(&#039;include_path&#039;) . &#039;:&#039; . CAKE_CORE_INCLUDE_PATH . DS . &#039;/vendors&#039;);
function __autoload($path) {
if (substr($path, 0, 5) == &#039;Zend_&#039;) {
include str_replace(&#039;_&#039;, &#039;/&#039;, $path) . &#039;.php&#039;;
}
return $path;
}
</pre>
<p>You also need to put the DB config for the datasource in config/database.php (<strong>updated Jan 20/2010 for better DebugKit compatibility</strong>):</p>
<pre class="brush: php">
var $zendSearchLucene = array(
	&#039;datasource&#039; =&gt; &#039;ZendSearchLucene&#039;,
	&#039;indexFile&#039; =&gt; &#039;lucene&#039;, // stored in the cache dir.
	&#039;driver&#039; =&gt; &#039;&#039;,
	&#039;source&#039; =&gt; &#039;search_indices&#039;
);
</pre>
<p>Then, in the model that&#8217;ll act as your search index (say, for example, SearchIndex), specify the DB config:</p>
<pre class="brush: php">
&lt;?php class SearchIndex extends AppModel {
var $useDbConfig = &#039;zendSearchLucene&#039;;
}
?&gt;
</pre>
<p><strong>Saving/Indexing</strong></p>
<p>I&#8217;ve tried to keep the datasource functions as simple and familiar as possible. When saving an item to the index, the datasource expects a multidimensional array for each item. For compatibility with CakePHP&#8217;s datasource code, the &#8216;meat&#8217; of the data is nested in the third level of the array. Each sub-array contains information about a field to be stored. For example:</p>
<pre class="brush: php">
$saveData = array(&#039;SearchIndex&#039; =&gt; array(
  	&#039;document&#039; =&gt; array(
		array(
			&#039;key&#039; =&gt; &#039;name&#039;,
			&#039;value&#039; =&gt; $record[$Model-&gt;alias][$this-&gt;settings[$Model-&gt;alias][&#039;name&#039;]],
			&#039;type&#039; =&gt; &#039;Text&#039;
		),
		array(
			&#039;key&#039; =&gt; &#039;description&#039;,
			&#039;value&#039; =&gt; $record[$Model-&gt;alias][$this-&gt;settings[$Model-&gt;alias][&#039;description&#039;]],
			&#039;type&#039; =&gt; &#039;Text&#039;
		),
		array(
			&#039;key&#039; =&gt; &#039;url&#039;,
			&#039;value&#039; =&gt; $this-&gt;__constructUrl($Model, $record),
			&#039;type&#039; =&gt; &#039;Text&#039;
		)
	)
 ));
</pre>
<p>Passing that data in a Model::save() call will in turn execute the following Zend code (more or less &#8211; this is a very simplified version of the actual ZendSearchLuceneSource saving code):</p>
<pre class="brush: php">
$index = Zend_Search_Lucene::open(&#039;/path/to/the/index/set/in/dbConfig&#039;);
$doc = new Zend_Search_Lucene_Document();
foreach ($data as $field) {
$doc-&gt;addField(Zend_Search_Lucene_Field::$field[&#039;type&#039;]($field[&#039;key&#039;], $field[&#039;value&#039;]));
}
$index-&gt;addDocument($doc);
</pre>
<p>Obviously that&#8217;s a basic example; you&#8217;ll probably send a whole bunch of dynamic info to the indexer. But that&#8217;s the gist of it anyway.</p>
<p><strong>Querying</strong></p>
<p>You can search for records just like you would a regular datasource. Pass the search terms as a &#8220;query&#8221; condition. If you want the search terms to be highlighted in the returned results, pass <strong>&#8216;highlight&#8217; =&gt; true</strong> in the array of options. Note that only indexed fields will be highlighted.</p>
<p>You can find all results:</p>
<pre class="brush: php">
function search($term) {
$results = $this-&gt;SearchIndex-&gt;find(&#039;all&#039;, array(&#039;highlight&#039; =&gt; true, &#039;conditions&#039; =&gt; array(&#039;query&#039; =&gt; &#039;best cakephp tutorials&#039;)));
}
</pre>
<p>You can mimic Google&#8217;s I&#8217;m Feeling Lucky with find(&#8216;first&#8217;):</p>
<pre class="brush: php">
function search($term) {
$topResult = $this-&gt;SearchIndex-&gt;find(&#039;first&#039;, array(&#039;conditions&#039; =&gt; array(&#039;query&#039; =&gt; &#039;best cakephp tutorials&#039;)));
}
</pre>
<p>You can even paginate:</p>
<pre class="brush: php">
function search($term) {
$this-&gt;paginate = array(
&#039;limit&#039; =&gt; 10,
&#039;conditions&#039; =&gt; array(&#039;query&#039; =&gt; &#039;best CakePHP tutorials&#039;),
&#039;highlight&#039; =&gt; true
);

$results = $this-&gt;paginate();
}
</pre>
<p>Results are returned in the expected CakePHP way, as a multidimensional array &#8211; <strong>$results[0]['MyModelAlias']</strong> for multiple records, <strong>$results['MyModelAlias']</strong> for one (i.e. with find(&#8216;first&#8217;)).</p>
<p>There you go &#8211; enjoy! As always, comments and suggestions are welcomed.</p>
<p>I used the <a href="http://blog.loadsys.com/2009/06/19/cakephp-rss-feed-datasource/">RSS Feed datasource</a> by Loadsys as a guide to good datasource design. I may have borrowed a function or two. <img src='http://jamienay.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><a href="http://www.neilcrookes.com/2009/11/21/cakephp-searchable-plugin">Neil Crookes&#8217; Searchable plugin</a> also helped.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamienay.com/2010/01/zend_search_lucene-datasource-for-cakephp/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>&#8216;form&#8217; a reserved word for CakePHP 1.2 controller params &#8211; watch out!</title>
		<link>http://jamienay.com/2009/11/form-a-reserved-word-for-cakephp-12-controller-params-watch-out/</link>
		<comments>http://jamienay.com/2009/11/form-a-reserved-word-for-cakephp-12-controller-params-watch-out/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 18:23:50 +0000</pubDate>
		<dc:creator>Jamie</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[gotcha]]></category>
		<category><![CDATA[oops]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://jamienay.com/?p=365</guid>
		<description><![CDATA[Just a quick bit of advice to those who may have been banging their heads against the walls when trying to pass &#8220;form&#8221; as a custom parameter in a CakePHP URL. Apparently &#8216;form&#8217; is a param &#8211; an array, to be specific &#8211; that&#8217;s already set by Cake and using it as a custom parameter won&#8217;t work. While finishing up [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick bit of advice to those who may have been banging their heads against the walls when trying to pass &#8220;form&#8221; as a custom parameter in a CakePHP URL. Apparently &#8216;form&#8217; is a param &#8211; an array, to be specific &#8211; that&#8217;s already set by Cake and using it as a custom parameter won&#8217;t work. While finishing up an online email form builder plugin, I defined this route:</p>
<pre class="brush: php">
Router::connect(&#039;/:form/&#039;, array(&#039;plugin&#039; =&gt; &#039;email_forms&#039;, &#039;controller&#039; =&gt; &#039;email_forms&#039;, &#039;action&#039; =&gt; &#039;view&#039;), array(&#039;form&#039; =&gt; &#039;[a-z0-9_-]+&#039;));
</pre>
<p>This didn&#8217;t work, however; the route would take me to the correct action, but the &#8216;form&#8217; param would always be empty &#8211; or so I thought. After doing some checking, mostly thanks to the Debug Kit plugin, I realized that the &#8216;form&#8217; param is passed with <strong>every request</strong>. So, I just renamed &#8216;form&#8217; to &#8216;emailForm&#8217; and it worked like a charm:</p>
<pre class="brush: php">
Router::connect( &#039;/:emailForm/&#039;, array(&#039;plugin&#039; =&gt; &#039;email_forms&#039;, &#039;controller&#039; =&gt; &#039;email_forms&#039;, &#039;action&#039; =&gt; &#039;view&#039;), array(&#039;emailForm&#039; =&gt; &#039;[a-z0-9_-]+&#039;));
</pre>
<p>So, watch out for those predefined variables.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamienay.com/2009/11/form-a-reserved-word-for-cakephp-12-controller-params-watch-out/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Quick, Dirty and Useful Widget Component for CakePHP</title>
		<link>http://jamienay.com/2009/06/a-quick-dirty-and-useful-widget-component-for-cakephp/</link>
		<comments>http://jamienay.com/2009/06/a-quick-dirty-and-useful-widget-component-for-cakephp/#comments</comments>
		<pubDate>Sun, 14 Jun 2009 03:08:49 +0000</pubDate>
		<dc:creator>Jamie</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://jamienay.com/?p=155</guid>
		<description><![CDATA[In one of my side projects, which I&#8217;m currently refactoring to use CakePHP, I needed to have certain dynamic (i.e. database-retrieved) elements on every page: the three latest entries from the articles section, certain user details, etc. I could add a whole lot of models to the $uses array of my individual models or AppModel, but that results in a [...]]]></description>
			<content:encoded><![CDATA[<p>In one of my side projects, which I&#8217;m currently refactoring to use CakePHP, I needed to have certain dynamic (i.e. database-retrieved) elements on every page: the three latest entries from the articles section, certain user details, etc. I could add a whole lot of models to the $uses array of my individual models or AppModel, but that results in a lot of overhead and it just doesn&#8217;t make sense, since, if I&#8217;m just displaying the latest three articles in a site-wide sidebar, my other models aren&#8217;t really &#8220;using&#8221; Article. So I searched for a better, more fluid solution.</p>
<p>The simplest fix is the requestAction method, but that results in a lot of overhead since it results in an almost-complete page load with every use (basically, it just loads another URL on the fly). I searched around the popular CakePHP blogs for a few hours looking for a good solution, but, after not finding anything I liked, I decided to make my own. I actually got the idea for this component from the comments on <a href="http://debuggable.com/" target="_blank">debuggable.com</a>&#8216;s post &#8216;<a href="http://debuggable.com/posts/requestaction-considered-harmful:48abb514-1f9c-4443-b91c-6d0f4834cda3" target="_blank">requestAction considered harmful</a>&#8216; -<a href="http://rafaelbandeira3.wordpress.com/" target="_blank">Rafael Bandeira</a> suggested a Widget view helper, which I thought was a great idea but decided to go with a controller component instead.</p>
<p>And that&#8217;s where the Widget component comes in. Basically, this component, which I attach to AppController, allows you to retrieve any information from any model, without directly interacting with the model itself and without using $uses, App::import, ClassRegistry, etc. The basic idea is that you write your own findX methods in your models, which you then call via the Widget component.</p>
<p>So, we&#8217;re going to work through implementing a Widget component, and we&#8217;ll use it to get the latest three published entries from the Articles table and display them across the site. Here&#8217;s what we&#8217;ll do:</p>
<ol>
<li>Implement support for custom find methods (<strong>skip this step if you&#8217;ve already done this</strong>)</li>
<li>Write a method to find the latest Articles</li>
<li>Write our Widget Component</li>
<li>Add the Widget Component to AppController and write a function to set site-wide dynamic data</li>
</ol>
<h3>1. Implement support for custom find methods</h3>
<p>Most CakePHP developers who&#8217;ve graduated from the &#8216;novice&#8217; school have done this, but for those who haven&#8217;t: adding custom find methods is a great way to extend your application. And, it&#8217;s easy! I&#8217;m using the method found in <a href="http://pseudocoder.com" target="_blank">Matt Curry</a>&#8216;s excellent (and free!) <a href="http://www.pseudocoder.com/free-cakephp-book/" target="_blank">Super Awesome Advanced CakePHP</a> Tips e-book.</p>
<p>We just need to overwrite the default Model::find() method with a new find() in our AppModel. It looks something like this:</p>
<pre class="brush: php">
// For custom find(&#039;xxx&#039;) methods. The function looks for a __findFindType class method.
function find($type, $options = array()) {
     $method = null;
     if (is_string($type)) {
         $method = sprintf(&#039;__find%s&#039;, Inflector::camelize($type));
     }

     if ($method &amp;&amp; method_exists($this, $method)) {
         return $this-&gt;{$method}($options);
     } else {
        $args = func_get_args();
        return call_user_func_array(array(&#039;parent&#039;, &#039;find&#039;), $args);
     }
}
</pre>
<p>Basically, whenever we call find(), we&#8217;re going to look in the model doing the finding for a __findXXX method that matches find(&#8216;XXX&#8217;). If the method doesn&#8217;t exist then we fall back on the default find() method.</p>
<h3>2. Write a sample custom find method</h3>
<p>Now we&#8217;ll write a method in the Article model &#8211; /app/models/article.php &#8211; class to find the latest articles:</p>
<pre class="brush: php">
function __findLatest($limit = 3) {
    return $this-&gt;find(&#039;all&#039;, array(&#039;limit&#039; =&gt; 3, &#039;published&#039; =&gt; true, &#039;order&#039; =&gt; &#039;Article.begin_publishing DESC&#039;));
}
</pre>
<p>Pretty simple. To use it, we just call: $this-&gt;Article-&gt;find(&#8216;latest&#8217;);</p>
<h3>Write our Widget component</h3>
<p>Finally, the good stuff! The Widget component is simple too; it only has one method (of course, expand as you see fit). Put this in /app/controllers/components/widget.php:</p>
<pre class="brush: php">
&lt;?php
class WidgetComponent extends Object {

    function retrieve($modelName, $findType, $options = NULL) {
        $model = ClassRegistry::init($modelName);
        return $model-&gt;find($findType, $options);
    }

}
?&gt;
</pre>
<p>As you can see, we&#8217;re using a method called &#8216;retrieve&#8217; to find our data. Its first argument is the name of the model from which you want to grab data, while the second argument denotes the name of the findXXX method. The third argument is any optional data you want to pass along. You&#8217;ll see an example usage in the next section. Speaking of which&#8230;</p>
<h3>Add the Widget Component to AppController and write a function to set site-wide dynamic data</h3>
<p>So now that we&#8217;ve written our custom find method and Widget Component, the only thing left to do is add the functionality to AppController. First, add it to the $components array in /app/app_controller.php:</p>
<pre class="brush: php">
var $components = array(&#039;Widget&#039;);
</pre>
<p>Next, write a function in AppController to set your common (site-wide) widgets. I like to call it &#8220;_setCommonWidgets()&#8221;:</p>
<pre class="brush: php">
function _setCommonWidgets()
{
    $this-&gt;set(&#039;latestArticles&#039;, $this-&gt;Widget-&gt;retrieve(&#039;Article&#039;, &#039;latest&#039;));
}
</pre>
<p>And there&#8217;s the Widget Component in action. We call the retrieve() method, pass along the model name we want &#8211; Article &#8211; and the find type, &#8216;latest&#8217;. We set the resulting array as view variable, so it&#8217;ll be available in any view as $latestArticles. But wait! </p>
<p>We forgot one step: we need to invoke the _setCommonWidgets() function. Easy stuff: just call it in AppController::beforeRender():</p>
<pre class="brush: php">
// Set any common &#039;widget&#039; variables.
$this-&gt;_setCommonWidgets();
</pre>
<p>And that&#8217;s it. Now you can use _setCommonWidgets to give your views access to any data you&#8217;d like, without resorting to requestAction, $uses, manual calls to App::import or ClassRegistry, etc. </p>
<p>I&#8217;d love feedback on this feature. Improvements especially are welcome. <img src='http://jamienay.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://jamienay.com/2009/06/a-quick-dirty-and-useful-widget-component-for-cakephp/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Lightweight Autoloading in the Zend Framework</title>
		<link>http://jamienay.com/2009/03/lightweight-autoloading-in-the-zend-framework/</link>
		<comments>http://jamienay.com/2009/03/lightweight-autoloading-in-the-zend-framework/#comments</comments>
		<pubDate>Tue, 31 Mar 2009 01:00:56 +0000</pubDate>
		<dc:creator>Jamie</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://www.jamienay.com/?p=46</guid>
		<description><![CDATA[The Zend Framework is one of the best things to happen to PHP since the introduction of objects. But one area that&#8217;s always bugged me has been Zend_Loader, specifically its autoloader. For a framework with an extremely rigid class naming structure, you&#8217;d think the autoloader would be light and intuitive. Yet it&#8217;s a lot more complex than it needs to [...]]]></description>
			<content:encoded><![CDATA[<p>The Zend Framework is one of the best things to happen to PHP since the introduction of objects. But one area that&#8217;s always bugged me has been Zend_Loader, specifically its autoloader. For a framework with an extremely rigid class naming structure, you&#8217;d think the autoloader would be light and intuitive. Yet it&#8217;s a lot more complex than it needs to be for most developers, leading to some inefficient code and a lot of &#8216;require_once&#8217; statements everywhere, most of which, if we play our cards right, can be deleted. So, here&#8217;s a little autoloader that I wrote for a current project that does the job in nearly every case. Assuming you&#8217;re going to make a method of your Bootstrap class, it&#8217;ll look something like:</p>
<pre class="brush: php">
public static function autoload($path)
{
    include str_replace(&#039;_&#039;, &#039;/&#039;, $path) . &#039;.php&#039;;
    return $path;
}
</pre>
<p>Then when you&#8217;re running the bootstrap, change your default registerAutoload() call to:</p>
<pre class="brush: php">
require_once &#039;Zend/Loader.php&#039;;
Zend_Loader::registerAutoload(&#039;Bootstrap&#039;);
</pre>
<p>And that&#8217;s it! Erase or comment out those annoying and inefficient require_once statementse. I know, slightly ironic that we need a require_once since the goal is to get rid of them. I never said it was perfect &#8211; almost. <img src='http://jamienay.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://jamienay.com/2009/03/lightweight-autoloading-in-the-zend-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
