<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>PHP and Stuff</title>
	
	<link>http://www.phpandstuff.com</link>
	<description>PHP, JS, CSS, jQuery, CodeIgniter, Doctrine</description>
	<lastBuildDate>Fri, 05 Mar 2010 23:15:05 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PhpAndStuff" /><feedburner:info uri="phpandstuff" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>CodeIgniter from Scratch: (Day 10) The Calendar Library</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/HHY95WXiyuM/codeigniter-from-scratch-day-10-the-calendar-library</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-10-the-calendar-library#comments</comments>
		<pubDate>Fri, 05 Mar 2010 23:15:05 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Screencasts]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=880</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_from_scratch.jpg" alt="ci_from_scratch" title="ci_from_scratch" width="200" height="200" class="alignleft size-full wp-image-864" />Here is my next <a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-the-calendar-library/" rel="nofollow">screencast on CodeIgniter.</a>

<em>In this tenth episode of the CodeIgniter From Scratch screencast series, we will be exploring the Calendar library. We are also going to utilize the database class and jQuery AJAX. I will show you how to build a simple and CSS-styled calendar page, which will have the ability to store and display content for each day. </em>

<a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-the-calendar-library/" rel="nofollow">Click Here to Watch</a>

<div class="clear"></div>

<img src="http://www.phpandstuff.com/wp-content/uploads/2010/03/ss.png" alt="ss" title="ss" width="641" height="400" class="aligncenter size-full wp-image-881" />]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-from-scratch-day-10-the-calendar-library"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-from-scratch-day-10-the-calendar-library" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_from_scratch.jpg" alt="ci_from_scratch" title="ci_from_scratch" width="200" height="200" class="alignleft size-full wp-image-864" />Here is my next <a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-the-calendar-library/" rel="nofollow">screencast on CodeIgniter.</a></p>
<p><em>In this tenth episode of the CodeIgniter From Scratch screencast series, we will be exploring the Calendar library. We are also going to utilize the database class and jQuery AJAX. I will show you how to build a simple and CSS-styled calendar page, which will have the ability to store and display content for each day. </em></p>
<p><a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-the-calendar-library/" rel="nofollow">Click Here to Watch</a></p>
<div class="clear"></div>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/03/ss.png" alt="ss" title="ss" width="641" height="400" class="aligncenter size-full wp-image-881" /></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/HHY95WXiyuM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-10-the-calendar-library/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-10-the-calendar-library</feedburner:origLink></item>
		<item>
		<title>CodeIgniter from Scratch: Day 9 – File Uploading and Image Manipulation</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/f-MnGLAWsMk/codeigniter-from-scratch-day-9-file-uploading-and-image-manipulation</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-9-file-uploading-and-image-manipulation#comments</comments>
		<pubDate>Sun, 21 Feb 2010 23:52:39 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Screencasts]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=872</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_from_scratch.jpg" alt="ci_from_scratch" title="ci_from_scratch" width="200" height="200" class="alignleft size-full wp-image-864" /> Nettuts+ published my next <a href="http://net.tutsplus.com/videos/screencasts/codeigniter-from-scratch-file-uploading-and-image-manipulation/" rel="nofollow">screencast on CodeIgniter.</a>

<em>In lesson nine of our CodeIgniter series, we'll build a small image gallery that allows you to upload files, and automatically create thumbnails.
</em>

<a href="http://net.tutsplus.com/videos/screencasts/codeigniter-from-scratch-file-uploading-and-image-manipulation/" rel="nofollow">Click Here to Watch</a>

<div class="clear"></div>
<img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ss.png" alt="ss" title="ss" width="611" height="516" class="aligncenter size-full wp-image-876" />]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-from-scratch-day-9-file-uploading-and-image-manipulation"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-from-scratch-day-9-file-uploading-and-image-manipulation" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_from_scratch.jpg" alt="ci_from_scratch" title="ci_from_scratch" width="200" height="200" class="alignleft size-full wp-image-864" /> Nettuts+ published my next <a href="http://net.tutsplus.com/videos/screencasts/codeigniter-from-scratch-file-uploading-and-image-manipulation/" rel="nofollow">screencast on CodeIgniter.</a></p>
<p><em>In lesson nine of our CodeIgniter series, we&#8217;ll build a small image gallery that allows you to upload files, and automatically create thumbnails.<br />
</em></p>
<p><a href="http://net.tutsplus.com/videos/screencasts/codeigniter-from-scratch-file-uploading-and-image-manipulation/" rel="nofollow">Click Here to Watch</a></p>
<div class="clear"></div>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ss.png" alt="ss" title="ss" width="611" height="516" class="aligncenter size-full wp-image-876" /></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/f-MnGLAWsMk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-9-file-uploading-and-image-manipulation/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-9-file-uploading-and-image-manipulation</feedburner:origLink></item>
		<item>
		<title>CodeIgniter from Scratch: Day 8 – AJAX</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/gnR4G1R1BGw/codeigniter-from-scratch-day-8-ajax</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-8-ajax#comments</comments>
		<pubDate>Thu, 11 Feb 2010 17:33:31 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Screencasts]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=863</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_from_scratch.jpg" alt="ci_from_scratch" title="ci_from_scratch" width="200" height="200" class="alignleft size-full wp-image-864" /> Today Nettuts+ published my <a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-day-8-ajax/" rel="nofollow">screencast on CodeIgniter.</a>

<em>The CodeIgniter from Scratch series was unexpectedly, and significantly popular. Today, I’m pleased to announce that, with the help of one of my best authors, Burak, we’ll be continuing the series! Additionally, the most often requested topic is the subject for today’s screencast: combining CodeIgniter and jQuery.</em>

<a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-day-8-ajax/" rel="nofollow">Click Here to Watch</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-from-scratch-day-8-ajax"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-from-scratch-day-8-ajax" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_from_scratch.jpg" alt="ci_from_scratch" title="ci_from_scratch" width="200" height="200" class="alignleft size-full wp-image-864" /> Today Nettuts+ published my <a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-day-8-ajax/" rel="nofollow">screencast on CodeIgniter.</a></p>
<p><em>The CodeIgniter from Scratch series was unexpectedly, and significantly popular. Today, I’m pleased to announce that, with the help of one of my best authors, Burak, we’ll be continuing the series! Additionally, the most often requested topic is the subject for today’s screencast: combining CodeIgniter and jQuery.</em></p>
<p><a href="http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-day-8-ajax/" rel="nofollow">Click Here to Watch</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/gnR4G1R1BGw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-8-ajax/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-from-scratch-day-8-ajax</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch. Day 11 – Record Hooks</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/pU6gTvyl7gA/codeigniter-doctrine-scratch-day-11-record-hooks</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks#comments</comments>
		<pubDate>Mon, 08 Feb 2010 21:24:33 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=824</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this tutorial we will be looking into <strong>Doctrine Record Hooks</strong>. This will allow us to trigger certain actions in our Models. 

We are going to use this feature to simplify a few things in the existing code, and even gain some performance benefits.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-11-record-hooks"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-11-record-hooks" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this tutorial we will be looking into <strong>Doctrine Record Hooks</strong>. This will allow us to trigger certain actions in our Models. </p>
<p>We are going to use this feature to simplify a few things in the existing code, and even gain some performance benefits.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_doctrine_day11.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<h3>Record Hooks</h3>
<p>In the <a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8 article</a> we talked about CodeIgniter Hooks. This time we are going to look at <strong>Record Hooks</strong> with Doctrine.</p>
<p>Hooks are used to execute certain code when a certain event is triggered. Record Hooks are used when something happens with a Doctrine Record. For example we can use the <strong>postInsert</strong> hook to do some task every time a new record is inserted.</p>
<p>Here is a list of all available Record Hooks:</p>
<ul>
<li>preSave</li>
<li>postSave</li>
<li>preUpdate</li>
<li>postUpdate</li>
<li>preInsert</li>
<li>postInsert</li>
<li>preDelete</li>
<li>postDelete</li>
<li>preValidate</li>
<li>postValidate</li>
</ul>
<p>To use a one of these hooks, simply add a method with that name into the Doctrine_Record model:</p>
<pre class="brush: php; highlight: [11,12,13,14];">
class Post extends Doctrine_Record {

	public function setTableDefinition() {
		// ...
	}

	public function setUp() {
		// ...
	}

	public function postInsert() {
		// a new record was inserted
		// you can put some code here
	}

}
</pre>
<p>Let&#8217;s look at what we are going to be doing today to utilize this feature.</p>
<h3>Forum Display Page Improvements</h3>
<p>In the <a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9 article</a> we built a page for displaying all Threads under a Forum.</p>
<p><img height="291" width="590" class="aligncenter size-full wp-image-744" title="ci_doctrine_day9_5" alt="ci_doctrine_day9_5" src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_5.png"/></p>
<p>Let&#8217;s look at the code we used for getting the list of threads:</p>
<pre class="brush: php;">
// from the Forum model

// ...
	public function getThreadsArray($offset, $limit) {

		$threads = Doctrine_Query::create()
			-&gt;select('t.title')
			-&gt;addSelect('p.id, (COUNT(p.id) - 1) as num_replies')
			-&gt;addSelect('MIN(p.id) as first_post_id')
			-&gt;addSelect('MAX(p.created_at) as last_post_date')
			-&gt;from('Thread t, t.Posts p')
			-&gt;where('t.forum_id = ?', $this-&gt;id)
			-&gt;groupBy('t.id')
			-&gt;orderBy('last_post_date DESC')
			-&gt;limit($limit)
			-&gt;offset($offset)
			-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
			-&gt;execute();

		foreach ($threads as &amp;$thread) {

			$post = Doctrine_Query::create()
				-&gt;select('p.created_at, u.username')
				-&gt;from('Post p, p.User u')
				-&gt;where('p.id = ?', $thread['Posts'][0]['first_post_id'])
				-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
				-&gt;fetchOne();

			$thread['num_replies'] = $thread['Posts'][0]['num_replies'];
			$thread['created_at'] = $post['created_at'];
			$thread['username'] = $post['User']['username'];
			$thread['user_id'] = $post['User']['id'];
			unset($thread['Posts']);

		}

		return $threads;

	}
// ...
</pre>
<p>There are two main DQL queries. The first one for fetching the Threads, and the second one, inside of a loop, for fetching further details about each Thread, such as number of replies, the username etc&#8230; </p>
<p>There is quite a bit going on in there. With the changes we will make today, we will be able to reduce that into a single DQL call.</p>
<h3>Adding a &#8220;First_Post&#8221; Relationship</h3>
<p>We first had to get the id of the first post, and then get information on that post in another DQL query. If we had a direct relationship with a &#8220;First_Post&#8221; record, it would simplify things.</p>
<ul>
<li>Edit: <strong>system/application/models/thread.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Thread extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('title', 'string', 255);
		$this-&gt;hasColumn('forum_id', 'integer', 4);
		$this-&gt;hasColumn('first_post_id', 'integer', 4);
	}

	public function setUp() {
		$this-&gt;hasOne('Forum', array(
			'local' =&gt; 'forum_id',
			'foreign' =&gt; 'id'
		));
		$this-&gt;hasMany('Post as Posts', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'thread_id'
		));

		$this-&gt;hasOne('Post as First_Post', array(
			'local' =&gt; 'first_post_id',
			'foreign' =&gt; 'id'
		));
	}

}
</pre>
<p>The highlighted lines have been added. Now each Thread will have a relationship with a Post record, which will be the first Post in that Thread.</p>
<h4>Setting up the Hook</h4>
<p>When a new Post is added, if it is the first Post in that Thread, it needs to be assigned to the First_Post relationship. This will be done with the following &#8220;postInsert&#8221; <strong>Record Hook</strong>.</p>
<ul>
<li>Edit: <strong>system/application/models/post.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Post extends Doctrine_Record {

// ...
	public function postInsert() {

		// is this the first post?
		if (!$this['Thread']['First_Post']-&gt;exists()) {
			$this['Thread']['First_Post'] = $this;
			$this['Thread']-&gt;save();
		}

	}

}
</pre>
<p>Note that &#8220;postInsert&#8221; means, &#8220;after&#8221; insert. It has nothing to do with the class name &#8220;Post&#8221;.</p>
<p>This function gets invoked right after a new Post record was created. </p>
<p>First we check if a First_Post relationship exists, with the <strong>exist()</strong> function. If not, we assign &#8220;$this&#8221;, which is the current Post record, to this relationship with the corresponding Thread record.</p>
<h3>Rebuild the Database</h3>
<ul>
<li>Drop all tables.</li>
</ul>
<p>You may use this query:</p>
<pre>
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE category, forum, post, thread, user;
</pre>
<p>Now we need to rebuild it all.</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/doctrine_tools/create_tables" rel="nofollow">http://localhost/ci_doctrine/doctrine_tools/create_tables</a> and click the button.</li>
<li>Go to: <a href="http://localhost/ci_doctrine/doctrine_tools/load_fixtures" rel="nofollow">http://localhost/ci_doctrine/doctrine_tools/load_fixtures</a> and click the button.</li>
</ul>
<p>Now all the tables are rebuilt and the fixture data is reloaded.</p>
<p>Take a look at your thread table:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_doctrine_day11_1.png" alt="ci_doctrine_day11_1" title="ci_doctrine_day11_1" width="581" height="850" class="aligncenter size-full wp-image-852" /></p>
<p>You can see the new column. And thanks to the Record Hook, the values have been assigned already.</p>
<h3>Simplify Things</h3>
<p>Now we can go ahead and simplify the &#8220;getThreadsArray&#8221; method under the Forum Model.</p>
<ul>
<li>Edit: <strong>system/application/models/forum.php</strong></li>
</ul>
<pre class="brush: php; highlight: [12,13,25,26,27];">
&lt;?php
class Forum extends Doctrine_Record {

// ...

	public function getThreadsArray($offset, $limit) {

		$threads = Doctrine_Query::create()
			-&gt;select('t.title')
			-&gt;addSelect('p.id, (COUNT(p.id) - 1) as num_replies')
			-&gt;addSelect('MAX(p.created_at) as last_post_date')
			-&gt;addSelect('fp.created_at, u.username')
			-&gt;from('Thread t, t.Posts p, t.First_Post fp, fp.User u')
			-&gt;where('t.forum_id = ?', $this-&gt;id)
			-&gt;groupBy('t.id')
			-&gt;orderBy('last_post_date DESC')
			-&gt;limit($limit)
			-&gt;offset($offset)
			-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
			-&gt;execute();

		foreach ($threads as &amp;$thread) {

			$thread['num_replies'] = $thread['Posts'][0]['num_replies'];
			$thread['created_at'] = $thread['First_Post']['created_at'];
			$thread['username'] = $thread['First_Post']['User']['username'];
			$thread['user_id'] = $thread['First_Post']['User']['id'];

			unset($thread['Posts']);

		}

		return $threads;

	}

}
</pre>
<p><strong>Line 13:</strong> Now we have 2 more relationships in the from() call. First_Post and the User for the First_Post.<br />
<strong>Line 12:</strong> We select the created_at and username fields from these new relationships.<br />
<strong>Line 25,26,27:</strong> These lines have been changed to use the new fields.<br />
Also the <strong>DQL query</strong> inside the loop is now gone. This should have a positive impact on performance.</p>
<p>Note that the loop now is only being used to simplify the <strong>$threads</strong> array structure, so it&#8217;s actually optional.</p>
<h4>Testing the Results</h4>
<p>We haven&#8217;t really changed anything on the actual pages. So everything should look the same as before.</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/02/ci_doctrine_day11_2.png" alt="ci_doctrine_day11_2" title="ci_doctrine_day11_2" width="600" height="321" class="aligncenter size-full wp-image-855" /></p>
<h3>Stay Tuned</h3>
<p>There are many things you can do with Hooks and Listeners in Doctrine. Make sure to <a href="http://www.doctrine-project.org/documentation/manual/1_2/en/event-listeners#record-hooks" rel="nofollow">read the documentation</a>.</p>
<p>I hope you enjoyed this tutorial. See you next time!</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/pU6gTvyl7gA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks/feed</wfw:commentRss>
		<slash:comments>36</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks</feedburner:origLink></item>
		<item>
		<title>Scheduling Tasks with Cron Jobs</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/mWX4SoG2B88/scheduling-tasks-with-cron-jobs</link>
		<comments>http://www.phpandstuff.com/articles/scheduling-tasks-with-cron-jobs#comments</comments>
		<pubDate>Wed, 27 Jan 2010 22:42:27 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=846</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-847" /><em>Cron Jobs are used for scheduling tasks to run on the server. They're most commonly used for automating system maintenance or administration. However, they are also relevant to web application development. There are many situations when a web application may need certain tasks to run periodically. Today we are going to explore the fundamentals of Cron Jobs.</em>

<a href="http://net.tutsplus.com/tutorials/other/scheduling-tasks-with-cron-jobs/" rel="nofollow">Read the full article at Nettuts</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fscheduling-tasks-with-cron-jobs"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fscheduling-tasks-with-cron-jobs" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-847" /><em>Cron Jobs are used for scheduling tasks to run on the server. They&#8217;re most commonly used for automating system maintenance or administration. However, they are also relevant to web application development. There are many situations when a web application may need certain tasks to run periodically. Today we are going to explore the fundamentals of Cron Jobs.</em></p>
<p><a href="http://net.tutsplus.com/tutorials/other/scheduling-tasks-with-cron-jobs/" rel="nofollow">Read the full article at Nettuts</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/mWX4SoG2B88" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/scheduling-tasks-with-cron-jobs/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/scheduling-tasks-with-cron-jobs</feedburner:origLink></item>
		<item>
		<title>SQL For Beginners: Part 3 – Database Relationships</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/WsM3i3mTNdE/sql-for-beginners-part-3-database-relationships</link>
		<comments>http://www.phpandstuff.com/articles/sql-for-beginners-part-3-database-relationships#comments</comments>
		<pubDate>Thu, 21 Jan 2010 17:00:20 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=838</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-768" /> <em>Today, we continue our journey into the world of SQL and relational database systems. In this part three of the series, we’ll learn how to work with multiple tables that have relationships with each other. First, we will go over some core concepts, and then will begin working with JOIN queries in SQL.</em>

<a href="http://net.tutsplus.com/tutorials/databases/sql-for-beginners-part-3-database-relationships/" rel="nofollow">Read More at Nettuts.com</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fsql-for-beginners-part-3-database-relationships"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fsql-for-beginners-part-3-database-relationships" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-768" /> <em>Today, we continue our journey into the world of SQL and relational database systems. In this part three of the series, we’ll learn how to work with multiple tables that have relationships with each other. First, we will go over some core concepts, and then will begin working with JOIN queries in SQL.</em></p>
<p><a href="http://net.tutsplus.com/tutorials/databases/sql-for-beginners-part-3-database-relationships/" rel="nofollow">Read More at Nettuts.com</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/WsM3i3mTNdE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/sql-for-beginners-part-3-database-relationships/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/sql-for-beginners-part-3-database-relationships</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch. Day 10 – Pagination</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/Xd3VQs71vHE/codeigniter-doctrine-scratch-day-10-pagination</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination#comments</comments>
		<pubDate>Wed, 20 Jan 2010 07:42:19 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=793</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> Today we will be working on <strong>Pagination</strong>.

<div class="clear"></div>

<img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_15.png" alt="ci_doctrine_day10_15" title="ci_doctrine_day10_15" width="600" height="313" class="aligncenter size-full wp-image-818" />]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-10-pagination"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-10-pagination" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> Today we will be working on <strong>Pagination</strong>.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<h3>Upgrading Doctrine</h3>
<p>Before we get started, let&#8217;s upgrade Doctrine.</p>
<p>When I wrote the first article in this series, Doctrine 1.1 was the current stable version at the time. Since then, 1.2 has come out. Luckily it is backwards compatible with 1.1.</p>
<p>So, if you are like me and have been using Doctrine 1.1, just follow these steps to upgrade to 1.2.</p>
<ul>
<li>Delete folder: <strong>system/application/plugins/doctrine/lib</strong></li>
<li>Download <a href="http://www.doctrine-project.org/download" rel="nofollow">Doctrine 1.2</a> and extract.</li>
<li>Copy the lib folder to <strong>system/application/plugins/doctrine</strong></li>
</ul>
<h4>One Small Fix</h4>
<p>At some point I did find an issue that wasn&#8217;t backwards compatible. I modified the previous articles to fix that issue but some of you may not have done this if you read those articles before I changed them. </p>
<ul>
<li>Edit: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php; highlight: [8];">
&lt;?php
class Home extends Controller {

	public function index() {

		$vars['categories'] = Doctrine_Query::create()
			-&gt;select('c.title, f.title, f.description')
			-&gt;addSelect('t.id, COUNT(t.id) as num_threads')
			-&gt;from('Category c, c.Forums f')
			-&gt;leftJoin('f.Threads t')
			-&gt;groupBy('f.id')
			-&gt;execute();

		$vars['title'] = 'Home';
		$vars['content_view'] = 'forum_list';
		$vars['container_css'] = 'forums';

		$this-&gt;load-&gt;view('template', $vars);
	}

}
</pre>
<p>It&#8217;s just the highlighted line. The &#8216;t.id&#8217; needed to be added to the addselect() or COUNT(t.id) did not work properly.</p>
<p>That is all. If your website is loading without errors, everything should be fine.</p>
<h3>What is Pagination?</h3>
<p>Displaying data in multiple pages is <strong>Pagination</strong>. </p>
<p>There are two main parts to this. First we need to generate links to the pages.</p>
<h4>Pagination Links</h4>
<p>Here is an example from CodeIgniter Forums:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_11.png" alt="ci_doctrine_day10_1" title="ci_doctrine_day10_1" width="324" height="58" class="aligncenter size-full wp-image-799" /></p>
<p>That looks simple, but we also need to consider what happens when we start going to other pages:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_21.png" alt="ci_doctrine_day10_2" title="ci_doctrine_day10_2" width="318" height="58" class="aligncenter size-full wp-image-798" /></p>
<p>Now there is a &#8220;Prev&#8221; link which we didn&#8217;t have before. And we see links to 5 page numbers instead of 3.</p>
<p>Things change even more if we go deeper:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_3.png" alt="ci_doctrine_day10_3" title="ci_doctrine_day10_3" width="361" height="69" class="aligncenter size-full wp-image-800" /></p>
<p>Now there is also a &#8220;<< First" link, because the link for Page 1 is no longer visible.</p>
<p>One more:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_4.png" alt="ci_doctrine_day10_4" title="ci_doctrine_day10_4" width="328" height="53" class="aligncenter size-full wp-image-801" /></p>
<p>The &#8220;Last >>&#8221; link disappeared because we already have a link to Page 89, which is the last page.</p>
<p>Another example from Digg.com:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_5.png" alt="ci_doctrine_day10_5" title="ci_doctrine_day10_5" width="449" height="40" class="aligncenter size-full wp-image-802" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_6.png" alt="ci_doctrine_day10_6" title="ci_doctrine_day10_6" width="568" height="49" class="aligncenter size-full wp-image-803" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_7.png" alt="ci_doctrine_day10_7" title="ci_doctrine_day10_7" width="604" height="35" class="aligncenter size-full wp-image-804" /></p>
<p>As you can see they are doing it quite differently. It&#8217;s all a matter of preference.</p>
<p>Let&#8217;s look at the way they do the links.</p>
<p>CodeIgniter Forums:</p>
<pre>
http://codeigniter.com/forums/viewforum/59/
http://codeigniter.com/forums/viewforum/59/P25/
http://codeigniter.com/forums/viewforum/59/P50/
</pre>
<p>Those were the links for the first, second and third page. The first page gets no parameter as it works with default values. But the second and third pages have these &#8220;P25&#8243; and &#8220;P50&#8243; parameters at the end. Strangely enough these are not page numbers. They actually represent the <strong>offset</strong> value for the records instead, as they display 25 records per page.</p>
<p>Digg.com:</p>
<pre>
http://digg.com/all/upcoming
http://digg.com/all/upcoming/page2
http://digg.com/all/upcoming/page3
</pre>
<p>Again, we see a difference between the two websites. Digg.com prefers to use actual page numbers instead of offset numbers.</p>
<h4>Paginating Data</h4>
<p>This is the second part to this Pagination subject. Our code needs to be responsible for displaying the correct set of data on each page.</p>
<p>In terms of raw SQL, here is how you can get a set of records for a given page:</p>
<pre>
SELECT * FROM table LIMIT 50, 25
</pre>
<p>The LIMIT clause does the job. In this particular query, we fetch 25 records, starting after the first 50 records. So, 50 is the <strong>offset</strong> and 25 is the <strong>limit</strong>, i.e. the number of records.</p>
<p>With Doctrine we will be using DQL rather than raw SQL queries.</p>
<p>Let&#8217;s say we have a URL like they do on CodeIgniter forums:</p>
<pre>
http://codeigniter.com/forums/viewforum/59/P125/
</pre>
<p>That would translate into having the <strong>offset</strong> 125. And the <strong>limit</strong> would always be 25, because internally we decide to display 25 threads per page.</p>
<p>If we have a Digg style pagination URL:</p>
<pre>
http://digg.com/all/upcoming/page7
</pre>
<p>We need to multiply 7 with the &#8220;per page&#8221; count. So it could be 175 (7*25) offset and 25 limit, if the per page limit is set to 25. But we are not going to be using this method.</p>
<h3>CodeIgniter Pagination Library</h3>
<p>CodeIgniter comes with a nice simple <strong>Pagination Library</strong>, which we will be using. First, I will explain it briefly.</p>
<p>Let&#8217;s put some code in a test Controller.</p>
<ul>
<li>Edit: <strong>system/application/controllers/test.php</strong></li>
</ul>
<pre class="brush: php;">
class Test extends Controller {

	function paginate() {

		$this-&gt;load-&gt;library('pagination');

		$config['base_url'] = base_url() . &quot;test/paginate&quot;;
		$config['total_rows'] = '200';
		$config['per_page'] = '10';

		$this-&gt;pagination-&gt;initialize($config);

		echo $this-&gt;pagination-&gt;create_links();

	}

}
</pre>
<p>The code is very simple. We just provide the base url, number of total records, and the number of records per page.</p>
<p>The results look like this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_8.png" alt="ci_doctrine_day10_8" title="ci_doctrine_day10_8" width="137" height="42" class="aligncenter size-full wp-image-806" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_9.png" alt="ci_doctrine_day10_9" title="ci_doctrine_day10_9" width="171" height="39" class="aligncenter size-full wp-image-807" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_10.png" alt="ci_doctrine_day10_10" title="ci_doctrine_day10_10" width="193" height="45" class="aligncenter size-full wp-image-808" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_111.png" alt="ci_doctrine_day10_11" title="ci_doctrine_day10_11" width="181" height="43" class="aligncenter size-full wp-image-809" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_12.png" alt="ci_doctrine_day10_12" title="ci_doctrine_day10_12" width="165" height="49" class="aligncenter size-full wp-image-810" /></p>
<p>And the links look like this:</p>
<pre>
http://localhost/ci_doctrine/test/paginate/
http://localhost/ci_doctrine/test/paginate/10
http://localhost/ci_doctrine/test/paginate/20
http://localhost/ci_doctrine/test/paginate/30
http://localhost/ci_doctrine/test/paginate/40
</pre>
<p>So this library puts the <strong>offset</strong> number, rather than the page number at the end of the URL&#8217;s.</p>
<p>Also, with this library you can customize the HTML structure of the links. You can see more information about that in the <a href="http://codeigniter.com/user_guide/libraries/pagination.html" ref="nofollow">documentation</a>.</p>
<h3>Adding More Data</h3>
<p>First we are going to add some more data to our database so we have something to paginate.</p>
<p>All we have to do is add more stuff to the fixture file we have been using before:</p>
<ul>
<li>Edit: <strong>system/fixtures/data.yml</strong></li>
</ul>
<pre class="brush: yaml;">
User:
  Admin:
    username: Administrator
    password: testing
    email: programming@gmail.com
  Test:
    username: TestUser
    password: mypass
    email: test@test.com
  Foo:
    username: Foobar
    password: mypass
    email: test2@test2.com

Forum:
  Forum_1:
    title: Introduce Yourself!
    description: &gt;
      Use this forum to introduce yourself to the CodeIgniter community,
      or to announce your new CI powered site.
  Forum_2:
    title: The Lounge
    description: &gt;
      CodeIgniter's social forum where you can discuss anything not related
      to development. No topics off limits... but be civil.
  Forum_3:
    title: CodeIgniter Discussion
    description: This forum is for general topics related to CodeIgniter.
  Forum_4:
    title: Code and Application Development
    description: &gt;
      Use the forum to discuss anything related to
      programming and code development.
  Forum_5:
    title: Ignited Code
    description: &gt;
      Use this forum to post plugins, libraries, or other code contributions,
      or to ask questions about any of them.

Category:
  Lounge:
    title: The CodeIgniter Lounge
    Forums: [Forum_1, Forum_2]
  Dev:
    title: CodeIgniter Development Forums
    Forums: [Forum_3, Forum_4, Forum_5]

Thread:
  Thread_1:
    title: Hi there!
    Forum: Forum_1
  Thread_2:
    title: Greetings to all
    Forum: Forum_1
  Thread_3:
    title: Sed vitae ligula erat
    Forum: Forum_3
  Thread_4:
    title: Vivamus laoreet quam vitae mauris tempus
    Forum: Forum_3
  Thread_5:
    title: Maecenas vel dolor odio
    Forum: Forum_3
  Thread_6:
    title: In nec justo at orci fermentum
    Forum: Forum_3
  Thread_7:
    title: Nullam volutpat laoreet orci
    Forum: Forum_3
  Thread_8:
    title: Sed sodales augue vel elit
    Forum: Forum_3
  Thread_9:
    title: Integer posuere luctus metus
    Forum: Forum_3
  Thread_10:
    title: Maecenas ut mauris eget odio pharetra
    Forum: Forum_3
  Thread_11:
    title: Pellentesque lacinia nibh vel lacus
    Forum: Forum_3
  Thread_12:
    title: Nunc facilisis nibh a nulla laoreet in ultricies
    Forum: Forum_3
  Thread_13:
    title: Maecenas pretium nisi eget nunc rutrum quis
    Forum: Forum_3
  Thread_14:
    title: Etiam at ligula leo
    Forum: Forum_3
  Thread_15:
    title: Vivamus tempus semper libero
    Forum: Forum_3
  Thread_16:
    title: Phasellus venenatis consectetur quam
    Forum: Forum_3
  Thread_17:
    title: Nam sagittis elementum turpis
    Forum: Forum_3
  Thread_18:
    title: Sed at odio id ante rutrum sodales
    Forum: Forum_3
  Thread_19:
    title: Praesent eget lorem nec odio
    Forum: Forum_3
  Thread_20:
    title: Donec at enim sit amet quam
    Forum: Forum_3
  Thread_21:
    title: Ut sit amet ante nec leo volutpat
    Forum: Forum_3
  Thread_22:
    title: Pellentesque accumsan orci nec
    Forum: Forum_3
  Thread_23:
    title: Curabitur convallis sapien in dolor feugiat
    Forum: Forum_3
  Thread_24:
    title: Aenean sodales massa in dui ultrices
    Forum: Forum_3

Post:
  Post_1:
    Thread: Thread_1
    User: Test
    created_at: '2009-11-20 01:20:30'
    updated_at: '2009-11-20 01:20:30'
    content: &gt;
      Hello everyone! My name is Test, and I go to school at
      Test Institute of Technology in the US.
      I just found CodeIgniter some time last week and have been
      reading through the documentation trying to get myself acquainted.

      Hopefully the forums will be a great help! I already have some questions.
      Thanks!
  Post_2:
    Thread: Thread_1
    User: Admin
    created_at: '2009-11-20 02:15:33'
    updated_at: '2009-11-20 02:15:33'
    content: Welcome Test! Nice to meet you.
  Post_3:
    Thread: Thread_2
    User: Foo
    created_at: '2009-11-19 12:14:50'
    updated_at: '2009-11-19 12:14:50'
    content: I am new here. Just wanted to say hi.
  Post_4:
    Thread: Thread_3
    User: Foo
    created_at: '2009-12-01 12:14:50'
    updated_at: '2009-12-01 12:14:50'
    content: Vivamus ultricies hendrerit justo, sit amet semper nulla scelerisque pulvinar.
  Post_5:
    Thread: Thread_4
    User: Foo
    created_at: '2009-12-02 12:14:50'
    updated_at: '2009-12-02 12:14:50'
    content: Sed luctus enim ut magna pellentesque mollis.
  Post_6:
    Thread: Thread_5
    User: Foo
    created_at: '2009-12-03 12:14:50'
    updated_at: '2009-12-03 12:14:50'
    content: Nam id nisi dolor, vel interdum turpis.
  Post_7:
    Thread: Thread_6
    User: Foo
    created_at: '2009-12-04 12:14:50'
    updated_at: '2009-12-04 12:14:50'
    content: Donec volutpat accumsan lorem, at euismod metus lobortis viverra.
  Post_8:
    Thread: Thread_7
    User: Foo
    created_at: '2009-12-05 12:14:50'
    updated_at: '2009-12-05 12:14:50'
    content: Nulla vestibulum erat ac nisi convallis rutrum.
  Post_9:
    Thread: Thread_8
    User: Foo
    created_at: '2009-12-06 12:14:50'
    updated_at: '2009-12-06 12:14:50'
    content: Nulla pharetra tortor id ante sollicitudin sodales.
  Post_10:
    Thread: Thread_9
    User: Foo
    created_at: '2009-12-07 12:14:50'
    updated_at: '2009-12-07 12:14:50'
    content: Cras id metus a elit mattis blandit et aliquet diam.
  Post_11:
    Thread: Thread_10
    User: Foo
    created_at: '2009-12-08 12:14:50'
    updated_at: '2009-12-08 12:14:50'
    content: Nunc non felis vitae dolor posuere aliquam non et augue.
  Post_12:
    Thread: Thread_11
    User: Foo
    created_at: '2009-12-09 12:14:50'
    updated_at: '2009-12-09 12:14:50'
    content: Nam et velit ac tellus interdum adipiscing.
  Post_13:
    Thread: Thread_12
    User: Foo
    created_at: '2009-12-10 12:14:50'
    updated_at: '2009-12-10 12:14:50'
    content: Donec viverra leo mauris, ac convallis turpis.
  Post_14:
    Thread: Thread_13
    User: Foo
    created_at: '2009-12-11 12:14:50'
    updated_at: '2009-12-11 12:14:50'
    content: Integer sagittis nisl ut nisi euismod in dignissim massa sagittis.
  Post_15:
    Thread: Thread_14
    User: Foo
    created_at: '2009-12-12 12:14:50'
    updated_at: '2009-12-12 12:14:50'
    content: Integer vel lectus mollis quam sollicitudin porta.
  Post_16:
    Thread: Thread_15
    User: Foo
    created_at: '2009-12-13 12:14:50'
    updated_at: '2009-12-13 12:14:50'
    content: Etiam tempor luctus sem, at consequat enim posuere in.
  Post_17:
    Thread: Thread_16
    User: Foo
    created_at: '2009-12-14 12:14:50'
    updated_at: '2009-12-14 12:14:50'
    content: Proin placerat lectus dolor, quis viverra ante.
  Post_18:
    Thread: Thread_17
    User: Foo
    created_at: '2009-12-15 12:14:50'
    updated_at: '2009-12-15 12:14:50'
    content: Maecenas ullamcorper commodo leo, lobortis molestie turpis cursus sit amet.
  Post_19:
    Thread: Thread_18
    User: Foo
    created_at: '2009-12-16 12:14:50'
    updated_at: '2009-12-16 12:14:50'
    content: Integer tincidunt facilisis dolor, vitae pellentesque turpis rutrum sed.
  Post_20:
    Thread: Thread_19
    User: Foo
    created_at: '2009-12-17 12:14:50'
    updated_at: '2009-12-17 12:14:50'
    content: Donec eget lacus a nibh volutpat venenatis quis a felis.
  Post_21:
    Thread: Thread_20
    User: Foo
    created_at: '2009-12-18 12:14:50'
    updated_at: '2009-12-18 12:14:50'
    content: Nam fringilla tellus quis augue elementum eleifend.
  Post_22:
    Thread: Thread_21
    User: Foo
    created_at: '2009-12-19 12:14:50'
    updated_at: '2009-12-19 12:14:50'
    content: Nullam sollicitudin nulla at orci accumsan eget ultrices felis vehicula.
  Post_23:
    Thread: Thread_22
    User: Foo
    created_at: '2009-12-20 12:14:50'
    updated_at: '2009-12-20 12:14:50'
    content: Nullam sit amet purus nec mauris convallis tincidunt sodales eget nunc.
  Post_24:
    Thread: Thread_23
    User: Foo
    created_at: '2009-12-21 12:14:50'
    updated_at: '2009-12-21 12:14:50'
    content: Praesent in eros non elit ultricies tincidunt a nec tellus.
  Post_25:
    Thread: Thread_24
    User: Foo
    created_at: '2009-12-22 12:14:50'
    updated_at: '2009-12-22 12:14:50'
    content: Aenean ac nisl a sapien pulvinar gravida et quis metus.
</pre>
<p>Now load this fixture:</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/doctrine_tools/load_fixtures" rel="nofollow">http://localhost/ci_doctrine/doctrine_tools/load_fixtures</a></li>
<li>Hit the button.</li>
<li>Go home: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
</ul>
<p>You should see this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_13.png" alt="ci_doctrine_day10_13" title="ci_doctrine_day10_13" width="600" height="434" class="aligncenter size-full wp-image-812" /></p>
<ul>
<li>Click the &#8220;CodeIgniter Discussion&#8221; link</li>
</ul>
<p>You should see:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_14.png" alt="ci_doctrine_day10_14" title="ci_doctrine_day10_14" width="600" height="869" class="aligncenter size-full wp-image-813" /></p>
<h3>Sorting By Last Post Date</h3>
<p>As it is, the Threads are not being sorted by a specific column, because we did not add that to the DQL query last time. They need to be sorted by the &#8220;created_at&#8221; date of the last Post in that Thread, in descending order. Let&#8217;s fix that now.</p>
<ul>
<li>Edit: <strong>system/application/models/forum.php</strong></li>
</ul>
<pre class="brush: php; highlight: [11,15];">
class Forum extends Doctrine_Record {

// ...

	public function getThreadsArray() {

		$threads = Doctrine_Query::create()
			-&gt;select('t.title')
			-&gt;addSelect('p.id, (COUNT(p.id) - 1) as num_replies')
			-&gt;addSelect('MIN(p.id) as first_post_id')
			-&gt;addSelect('MAX(p.created_at) as last_post_date')
			-&gt;from('Thread t, t.Posts p')
			-&gt;where('t.forum_id = ?', $this-&gt;id)
			-&gt;groupBy('t.id')
			-&gt;orderBy('last_post_date DESC')
			-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
			-&gt;execute();

		foreach ($threads as &amp;$thread) {

			$post = Doctrine_Query::create()
				-&gt;select('p.created_at, u.username')
				-&gt;from('Post p, p.User u')
				-&gt;where('p.id = ?', $thread['Posts'][0]['first_post_id'])
				-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
				-&gt;fetchOne();

			$thread['num_replies'] = $thread['Posts'][0]['num_replies'];
			$thread['created_at'] = $post['created_at'];
			$thread['username'] = $post['User']['username'];
			$thread['user_id'] = $post['User']['id'];
			unset($thread['Posts']);

		}

		return $threads;

	}

}
</pre>
<p>The highlighted lines have been added. They should be self-explanatory.</p>
<p>We should also update the View so it shows that date.</p>
<ul>
<li>Edit: <strong>system/application/views/forum.php</strong></li>
</ul>
<pre class="brush: php; highlight: [14]; html-script: true;">
&lt;h2&gt;&lt;?php echo $title ?&gt;&lt;/h2&gt;

&lt;?php foreach($threads as $thread): ?&gt;
&lt;div class=&quot;thread&quot;&gt;

	&lt;h3&gt;
		&lt;?php echo anchor('threads/display/'.$thread['id'], $thread['title']) ?&gt;
		(&lt;?php echo $thread['num_replies']; ?&gt; replies)
	&lt;/h3&gt;

	&lt;div&gt;
		Author: &lt;em&gt;&lt;?php echo anchor('profile/display/'.$thread['user_id'],
								$thread['username']); ?&gt;&lt;/em&gt;,
		Last Post: &lt;em&gt;&lt;?php echo $thread['last_post_date']; ?&gt;&lt;/em&gt;
	&lt;/div&gt;

&lt;/div&gt;
&lt;?php endforeach; ?&gt;
</pre>
<h3>Pagination Links</h3>
<p>Now, to do pagination, we need 3 pieces of information:</p>
<ul>
<li><strong>Total number of records.</strong> In our case, number of Threads.</li>
<li><strong>Number of records per page.</strong> We can pick any number. I will set it to 4 for now so we can have several pages.</li>
<li><strong>Current page number or record offset.</strong> Since CodeIgniter Pagination library works with the offset number, rather than page number, that&#8217;s what we will use.</li>
</ul>
<p>We need to edit the View, the Model and the Controller.</p>
<h4>The View</h4>
<p>Let&#8217;s set the output of the pagination links in the View.</p>
<ul>
<li>Edit: <strong>system/application/views/forum.php</strong></li>
</ul>
<pre class="brush: php; highlight: [20,21,22,23,24]; html-script: true;">
&lt;h2&gt;&lt;?php echo $title ?&gt;&lt;/h2&gt;

&lt;?php foreach($threads as $thread): ?&gt;
&lt;div class=&quot;thread&quot;&gt;

	&lt;h3&gt;
		&lt;?php echo anchor('threads/display/'.$thread['id'], $thread['title']) ?&gt;
		(&lt;?php echo $thread['num_replies']; ?&gt; replies)
	&lt;/h3&gt;

	&lt;div&gt;
		Author: &lt;em&gt;&lt;?php echo anchor('profile/display/'.$thread['user_id'],
								$thread['username']); ?&gt;&lt;/em&gt;,
		Last Post: &lt;em&gt;&lt;?php echo $thread['last_post_date']; ?&gt;&lt;/em&gt;
	&lt;/div&gt;

&lt;/div&gt;
&lt;?php endforeach; ?&gt;

&lt;?php if (isset($pagination)): ?&gt;
	&lt;div class=&quot;pagination&quot;&gt;
		Pages: &lt;?php echo $pagination; ?&gt;
	&lt;/div&gt;
&lt;?php endif; ?&gt;
</pre>
<p>At line 20, we check to see if the $pagination variable is set, which will contain the pagination links, because sometimes there won&#8217;t be enough records to paginate.</p>
<h4>The Model</h4>
<p>Now let&#8217;s modify the Forum Model.</p>
<ul>
<li>Edit: <strong>system/application/models/forum.php</strong></li>
</ul>
<pre class="brush: php; highlight: [21,30,34,45,46];">
&lt;?php
class Forum extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('title', 'string', 255);
		$this-&gt;hasColumn('description', 'string', 255);
		$this-&gt;hasColumn('category_id', 'integer', 4);
	}

	public function setUp() {
		$this-&gt;hasOne('Category', array(
			'local' =&gt; 'category_id',
			'foreign' =&gt; 'id'
		));
		$this-&gt;hasMany('Thread as Threads', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'forum_id'
		));
	}

	public function numThreads() {

		$result = Doctrine_Query::create()
			-&gt;select('COUNT(*) as num_threads')
			-&gt;from('Thread')
			-&gt;where('forum_id = ?', $this-&gt;id)
			-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
			-&gt;fetchOne();

		return $result['num_threads'];

	}

	public function getThreadsArray($offset, $limit) {

		$threads = Doctrine_Query::create()
			-&gt;select('t.title')
			-&gt;addSelect('p.id, (COUNT(p.id) - 1) as num_replies')
			-&gt;addSelect('MIN(p.id) as first_post_id')
			-&gt;addSelect('MAX(p.created_at) as last_post_date')
			-&gt;from('Thread t, t.Posts p')
			-&gt;where('t.forum_id = ?', $this-&gt;id)
			-&gt;groupBy('t.id')
			-&gt;orderBy('last_post_date DESC')
			-&gt;limit($limit)
			-&gt;offset($offset)
			-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
			-&gt;execute();

		foreach ($threads as &amp;$thread) {

			$post = Doctrine_Query::create()
				-&gt;select('p.created_at, u.username')
				-&gt;from('Post p, p.User u')
				-&gt;where('p.id = ?', $thread['Posts'][0]['first_post_id'])
				-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
				-&gt;fetchOne();

			$thread['num_replies'] = $thread['Posts'][0]['num_replies'];
			$thread['created_at'] = $post['created_at'];
			$thread['username'] = $post['User']['username'];
			$thread['user_id'] = $post['User']['id'];
			unset($thread['Posts']);

		}

		return $threads;

	}

}
</pre>
<p><strong>Line 21:</strong> Added new method named &#8220;numThreads&#8221;, since we are going to need the total number of Threads. </p>
<p>Note: I know that it would have been simpler to just use this code: &#8220;$this->Threads->count()&#8221;. However, unfortunately Doctrine creates a very inefficient query when we do that, that&#8217;s why I used a DQL query instead.</p>
<p><strong>Line 34:</strong> Just added 2 parameters to the existing function, since we are only interested in the Thread records for a given page.</p>
<p><strong>Lines 45-46:</strong> Here we use the given $offset and $limit parameters to limit the DQL query results.</p>
<h4>The Controller</h4>
<p>Finally we update the Forums Controller.</p>
<ul>
<li>Edit: <strong>system/application/controllers/forums.php</strong></li>
</ul>
<pre class="brush: php; highlight: [4,6,12,13,18,21,22,23,24,25,26,27,28,29,30,31];">
&lt;?php
class Forums extends Controller {

	public function display($id, $offset = 0) {

		$per_page = 4;

		$forum = Doctrine::getTable('Forum')-&gt;find($id);

		$vars['title'] = $forum['title'];
		$vars['threads'] = $forum-&gt;getThreadsArray(
			$offset,
			$per_page
		);
		$vars['content_view'] = 'forum';
		$vars['container_css'] = 'forum';

		$num_threads = $forum-&gt;numThreads();

		// do we have enough to paginate
		if ($num_threads &gt; $per_page) {
			// PAGINATION
			$this-&gt;load-&gt;library('pagination');
			$config['base_url'] = base_url() . &quot;forums/display/$id&quot;;
			$config['total_rows'] = $num_threads;
			$config['per_page'] = $per_page;
			$config['uri_segment'] = 4;
			$this-&gt;pagination-&gt;initialize($config);

			$vars['pagination'] = $this-&gt;pagination-&gt;create_links();
		}

		$this-&gt;load-&gt;view('template', $vars);

	}

}
</pre>
<p>Updated lines are highlighted.</p>
<p><strong>Line 4:</strong> Now there is a second parameter named $offset, because the paginated URL&#8217;s will contain the offset after the Forum id.</p>
<p><strong>Line 6:</strong> Here we pick a number of Threads per page. Normally it could be 10, 20 or 25, but for this test we are picking a smaller number.</p>
<p><strong>Lines 12-13:</strong> We send the 2 parameters that the getThreadsArray method is expecting.</p>
<p><strong>Line 21:</strong> We only do pagination if there are more records than the $per_page number.</p>
<p><strong>Line 27:</strong> We have to set the &#8216;uri_segment&#8217; setting for the Pagination library. This is the uri segment that will carry the offset number. If not set, it defaults to uri segment 3. For example the URL will look like this:</p>
<pre>
http://localhost/ci_doctrine/forums/display/53/8
</pre>
<p>&#8220;forums&#8221; is uri segment 1, &#8220;display&#8221; is uri segment 2, &#8220;53&#8243; is uri segment 3 and the Forum id, &#8220;8&#8243; is the URI segment 4 and the $offset variable.</p>
<h4>The Result</h4>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
<li>Click the forum name: &#8220;CodeIgniter Discussion&#8221;</li>
</ul>
<p>You should see:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_15.png" alt="ci_doctrine_day10_15" title="ci_doctrine_day10_15" width="600" height="313" class="aligncenter size-full wp-image-818" /></p>
<p>Continue clicking on the pagination links:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_16.png" alt="ci_doctrine_day10_16" title="ci_doctrine_day10_16" width="185" height="35" class="aligncenter size-full wp-image-819" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_17.png" alt="ci_doctrine_day10_17" title="ci_doctrine_day10_17" width="183" height="34" class="aligncenter size-full wp-image-820" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/ci_doctrine_day10_18.png" alt="ci_doctrine_day10_18" title="ci_doctrine_day10_18" width="148" height="30" class="aligncenter size-full wp-image-821" /></p>
<p>Seems to be working <img src='http://www.phpandstuff.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Stay Tuned</h3>
<p>Thank you for reading, and sorry about the delay. We still have more work to do. See you next time!</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/Xd3VQs71vHE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination/feed</wfw:commentRss>
		<slash:comments>33</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination</feedburner:origLink></item>
		<item>
		<title>Mastering cURL</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/GFZxSDOSqn4/mastering-curl</link>
		<comments>http://www.phpandstuff.com/articles/mastering-curl#comments</comments>
		<pubDate>Sat, 16 Jan 2010 07:27:07 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=786</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/preview.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-789" /> <em><a href="http://curl.haxx.se/" rel="nofollow">cURL</a> is a tool for transferring files and data with URL syntax, supporting many protocols including HTTP, FTP, TELNET and more. Initially, cURL was designed to be a command line tool. Lucky for us, the cURL library is also <a href="http://us3.php.net/manual/en/book.curl.php" rel="nofollow">supported by PHP</a>. In this article, we will look at some of the advanced features of cURL, and how we can use them in our PHP scripts.</em>

<a href="http://net.tutsplus.com/tutorials/php/techniques-and-resources-for-mastering-curl/">Read the rest of the article at Nettuts</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fmastering-curl"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fmastering-curl" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2010/01/preview.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-789" /> <em><a href="http://curl.haxx.se/" rel="nofollow">cURL</a> is a tool for transferring files and data with URL syntax, supporting many protocols including HTTP, FTP, TELNET and more. Initially, cURL was designed to be a command line tool. Lucky for us, the cURL library is also <a href="http://us3.php.net/manual/en/book.curl.php" rel="nofollow">supported by PHP</a>. In this article, we will look at some of the advanced features of cURL, and how we can use them in our PHP scripts.</em></p>
<p><a href="http://net.tutsplus.com/tutorials/php/techniques-and-resources-for-mastering-curl/">Read the rest of the article at Nettuts</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/GFZxSDOSqn4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/mastering-curl/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/mastering-curl</feedburner:origLink></item>
		<item>
		<title>SQL For Beginners Part 2</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/L6LTFqCi5SA/sql-for-beginners-part-2</link>
		<comments>http://www.phpandstuff.com/articles/sql-for-beginners-part-2#comments</comments>
		<pubDate>Tue, 22 Dec 2009 23:32:54 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=779</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-768" />Another article published on Nettuts

<a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners-part-2/" rel="nofollow">http://net.tutsplus.com/tutorials/other/sql-for-beginners-part-2/</a>

<em>It is important for every web developer to be familiar with database interactions. In part two of the series, we will continue exploring the SQL language and apply what we’ve learned on a MySQL database. We will learn about Indexes, Data Types and more complex query structures.
</em>
<a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners-part-2/" rel="nofollow">Read More</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fsql-for-beginners-part-2"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fsql-for-beginners-part-2" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-768" />Another article published on Nettuts</p>
<p><a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners-part-2/" rel="nofollow">http://net.tutsplus.com/tutorials/other/sql-for-beginners-part-2/</a></p>
<p><em>It is important for every web developer to be familiar with database interactions. In part two of the series, we will continue exploring the SQL language and apply what we’ve learned on a MySQL database. We will learn about Indexes, Data Types and more complex query structures.<br />
</em><br />
<a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners-part-2/" rel="nofollow">Read More</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/L6LTFqCi5SA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/sql-for-beginners-part-2/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/sql-for-beginners-part-2</feedburner:origLink></item>
		<item>
		<title>SQL for Beginners</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/TlTL_yl8RCc/sql-for-beginners</link>
		<comments>http://www.phpandstuff.com/articles/sql-for-beginners#comments</comments>
		<pubDate>Thu, 17 Dec 2009 06:52:31 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=767</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-768" />Another article published on Nettuts

<a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners/" rel="nofollow">http://net.tutsplus.com/tutorials/other/sql-for-beginners/</a>

Most modern web applications today interact with databases, usually with a language called SQL. Lucky for us, this language is quite easy to learn. In this article, we are going to start with some basic SQL queries and use them to interact with a MySQL database.

<a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners/" rel="nofollow">Read More</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fsql-for-beginners"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fsql-for-beginners" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview1.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-768" />Another article published on Nettuts</p>
<p><a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners/" rel="nofollow">http://net.tutsplus.com/tutorials/other/sql-for-beginners/</a></p>
<p><em>Most modern web applications today interact with databases, usually with a language called SQL. Lucky for us, this language is quite easy to learn. In this article, we are going to start with some basic SQL queries and use them to interact with a MySQL database.<br />
</em><br />
<a href="http://net.tutsplus.com/tutorials/other/sql-for-beginners/" rel="nofollow">Read More</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/TlTL_yl8RCc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/sql-for-beginners/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/sql-for-beginners</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch. Day 9 – Templates &amp; Data Hydrators</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/q0rfn_TrIWE/codeigniter-doctrine-scratch-day-9-templates-data-hydrators</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators#comments</comments>
		<pubDate>Mon, 14 Dec 2009 00:04:45 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=704</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this article we are going to create <strong>Templates</strong> (with CodeIgniter) to keep our Views organized, and avoid repeating the same HTML code. Also we are going to learn about <strong>Doctrine Data Hydrators</strong> to see alternative ways to structure the data returned from the database.

<div class="clear"></div><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_2.png" alt="ci_doctrine_day9_2" title="ci_doctrine_day9_2" width="580" height="369" class="aligncenter size-full wp-image-720" />]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-9-templates-data-hydrators"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-9-templates-data-hydrators" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this article we are going to create <strong>Templates</strong> (with CodeIgniter) to keep our Views organized, and avoid repeating the same HTML code. Also we are going to learn about <strong>Doctrine Data Hydrators</strong> to see alternative ways to structure the data returned from the database.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<h3>Templates</h3>
<h4>What and Why?</h4>
<p>The term <strong>Template</strong> might be a little ambiguous right now. Maybe you are already thinking of <strong>Views</strong> as Templates. Which is mostly true. However, there is a problem with using separate Views for every single page in our application. There will be headers, footers and other content that will be repeated everywhere. That&#8217;s why there is a need for actual Templates for our Views.</p>
<p>For example, we will be creating a new View for the Forum pages. It will look mostly the same as the home page, using the same css stylesheet, same header, same user control panel, etc&#8230; There will be other Views later that will be the same way. If we ever make a change to any of these common parts, we don&#8217;t want to go through every single View. There should be Views that have the common html output that we can quickly edit. Using Templates will enable us to do just that, and maybe more.</p>
<h4>Creating a Template</h4>
<p>Let&#8217;s create our first Template, which is actually going to be a View itself. The idea is to keep all the common elements in one file, and take out the variable stuff.</p>
<p>For example, take a look at this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_2.png" alt="ci_doctrine_day9_2" title="ci_doctrine_day9_2" width="580" height="369" class="aligncenter size-full wp-image-720" /></p>
<p>The content section is definitely going to change from page to page. Also, I would like to take out the user controls section, so it can have its own View. We&#8217;re going to replace these with some code instead.</p>
<ul>
<li>Create: <strong>system/application/views/template.php</strong></li>
</ul>
<pre class="brush: php; highlight: [5,11,14,19]; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;&lt;?php echo $title; ?&gt; | CI+Doctrine Message Board&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div class=&quot;&lt;?php echo $container_css; ?&gt; container&quot;&gt;

	&lt;div class=&quot;user_controls&quot;&gt;
		&lt;?php $this-&gt;load-&gt;view('user_controls'); ?&gt;
	&lt;/div&gt;

	&lt;h1&gt;CI+Doctrine Message Board&lt;/h1&gt;

	&lt;?php $this-&gt;load-&gt;view($content_view); ?&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>I have copied the contents of the Home View we created before, and replaced a few things.</p>
<p><strong>Line 14:</strong> The code for the user_controls div will now be found in a View named user_controls.php.<br />
<strong>Line 19:</strong> $content_view is the name of the View that will be loaded to fill up the content area. For example, we will use a View named forum_list for the home page. The controller will have to pass this variable.<br />
<strong>Line 5:</strong> Now the page title can be passed as a $title variable.<br />
<strong>Line 11:</strong> We can apply a different css class for the container div on every page.</p>
<p>As you can see, a View can load other Views. That&#8217;s a big help in creating Templates. Now, all Controllers can just load this Template View, and they can pass the name for a content View that will be loaded in the middle of the page.</p>
<p>Now let&#8217;s create the <strong>user_controls</strong> View.</p>
<ul>
<li>Create: <strong>system/application/views/user_controls.php</strong></li>
</ul>
<pre class="brush: php; html-script: true;">
&lt;?php if ($user = Current_User::user()): ?&gt;
	Hello, &lt;em&gt;&lt;?php echo $user-&gt;username; ?&gt;&lt;/em&gt; &lt;br/&gt;
	&lt;?php echo anchor('logout', 'Logout'); ?&gt;
&lt;?php else: ?&gt;
	&lt;?php echo anchor('login','Login'); ?&gt; |
	&lt;?php echo anchor('signup', 'Register'); ?&gt;
&lt;?php endif; ?&gt;
</pre>
<p>Basically it&#8217;s the same code as before, but now it is in its own View file.</p>
<p>Now let&#8217;s create the forum_list View.</p>
<ul>
<li>Create: <strong>system/application/views/forum_list.php</strong></li>
</ul>
<pre class="brush: php; html-script: true;">
&lt;?php foreach($categories as $category): ?&gt;
&lt;div class=&quot;category&quot;&gt;

	&lt;h2&gt;&lt;?php echo $category-&gt;title; ?&gt;&lt;/h2&gt;

	&lt;?php foreach($category-&gt;Forums as $forum): ?&gt;
	&lt;div class=&quot;forum&quot;&gt;

		&lt;h3&gt;
			&lt;?php echo anchor('forums/display/'.$forum-&gt;id, $forum-&gt;title) ?&gt;
			(&lt;?php echo $forum-&gt;Threads[0]-&gt;num_threads; ?&gt; threads)
		&lt;/h3&gt;

		&lt;div class=&quot;description&quot;&gt;
			&lt;?php echo $forum-&gt;description; ?&gt;
		&lt;/div&gt;

	&lt;/div&gt;
	&lt;?php endforeach; ?&gt;

&lt;/div&gt;
&lt;?php endforeach; ?&gt;
</pre>
<p>This code is also taken from the middle section of the old Home View. (I only made a small change to the link at line 10.)</p>
<p>Now we can get rid of the Home View file.</p>
<ul>
<li>Delete: <strong>system/application/views/home.php</strong></li>
</ul>
<h4>Updating the Home Controller</h4>
<p>This new Template needs to know what content to load, what the title of the page is, etc&#8230; So we need to update the Home Controller.</p>
<ul>
<li>Edit: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php; highlight: [14,15,16,18];">
&lt;?php
class Home extends Controller {

	public function index() {

		$vars['categories'] = Doctrine_Query::create()
			-&gt;select('c.title, f.title, f.description')
			-&gt;addSelect('t.id, COUNT(t.id) as num_threads')
			-&gt;from('Category c, c.Forums f')
			-&gt;leftJoin('f.Threads t')
			-&gt;groupBy('f.id')
			-&gt;execute();

		$vars['title'] = 'Home';
		$vars['content_view'] = 'forum_list';
		$vars['container_css'] = 'forums';

		$this-&gt;load-&gt;view('template', $vars);
	}	

}
</pre>
<p>The changes are only the highlighted lines. We are now passing the page title, name of the content View, and a CSS class name for styling purposes. Then we load the View named &#8216;template&#8217; instead of &#8216;home&#8217; (since we deleted that one).</p>
<h4>See the Results</h4>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
</ul>
<p>The page should look exactly the same as before:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_1.png" alt="ci_doctrine_day9_1" title="ci_doctrine_day9_1" width="590" height="416" class="aligncenter size-full wp-image-707" /></p>
<p>Later in this article we are going to use this Template to build the Forum page, that lists Threads in a Forum.</p>
<h3>Data Hydrators (Doctrine)</h3>
<p>Our Doctrine Models extend the <strong>Doctrine_Record</strong> class. We have been using instances of this class for representing and persisting the database records. Also, we have been using instances of the <strong>Doctrine_Collection</strong> class when dealing with multiple records (e.g. fetching multiple rows with DQL).</p>
<p>With <strong>Data Hydrators</strong>, we can work with the data in other structure formats. For example, with DQL we can have it return the results of a SELECT query as an <strong>Array</strong> instead of Doctrine_Collection.</p>
<h4>HYDRATE_SCALAR</h4>
<p>This returns an array similar to what you would get from doing raw SQL queries.</p>
<pre class="brush: php; highlight: [5];">
$category = Doctrine_Query::create()
	-&gt;select('c.*, f.*')
	-&gt;from('Category c, c.Forums f')
	-&gt;where('c.id = ?', 1)
	-&gt;setHydrationMode(Doctrine::HYDRATE_SCALAR)
	-&gt;execute();

print_r($category);
/* output:
Array
(
    [0] =&gt; Array
        (
            [c_id] =&gt; 1
            [c_title] =&gt; The CodeIgniter Lounge
            [f_id] =&gt; 1
            [f_title] =&gt; Introduce Yourself!
            [f_description] =&gt; Use this forum to introduce yourself to the CodeIgniter community, or to announce your new CI powered site.

            [f_category_id] =&gt; 1
        )

    [1] =&gt; Array
        (
            [c_id] =&gt; 1
            [c_title] =&gt; The CodeIgniter Lounge
            [f_id] =&gt; 2
            [f_title] =&gt; The Lounge
            [f_description] =&gt; CodeIgniter's social forum where you can discuss anything not related to development. No topics off limits... but be civil.

            [f_category_id] =&gt; 1
        )

)
*/
</pre>
<p>We fetched the Category with id 1, and it&#8217;s associated Forums. There were 2 Forums under that Category, so the result contains 2 rows of data.</p>
<p>If I run the same raw query from phpMyAdmin, it looks like this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_4.png" alt="ci_doctrine_day9_4" title="ci_doctrine_day9_4" width="590" height="414" class="aligncenter size-full wp-image-739" /></p>
<p>Note that the Category title is repeated in both rows, because of the nature of JOIN queries. That is also the case in the Array that was returned by DQL.</p>
<h4>HYDRATE_ARRAY</h4>
<p>This also returns an Array. But this time, it will have a nice multi-tier structure based on the Model relationships.</p>
<pre class="brush: php; highlight: [5];">
$category = Doctrine_Query::create()
	-&gt;select('c.*, f.*')
	-&gt;from('Category c, c.Forums f')
	-&gt;where('c.id = ?', 1)
	-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
	-&gt;execute();

print_r($category);
/* output:
Array
(
    [0] =&gt; Array
        (
            [id] =&gt; 1
            [title] =&gt; The CodeIgniter Lounge
            [Forums] =&gt; Array
                (
                    [0] =&gt; Array
                        (
                            [id] =&gt; 1
                            [title] =&gt; Introduce Yourself!
                            [description] =&gt; Use this forum to introduce yourself to the CodeIgniter community, or to announce your new CI powered site.

                            [category_id] =&gt; 1
                        )

                    [1] =&gt; Array
                        (
                            [id] =&gt; 2
                            [title] =&gt; The Lounge
                            [description] =&gt; CodeIgniter's social forum where you can discuss anything not related to development. No topics off limits... but be civil.

                            [category_id] =&gt; 1
                        )

                )

        )

)
*/
</pre>
<p>Now we have a multidimensional Array. As you can see, this time the Category info is not repeated. And Forums is a sub-array under the Category. Also the keys of the array retain their original names, like &#8216;title&#8217;, instead of &#8216;c_title&#8217;.</p>
<h4>Other Hydrators</h4>
<p>By default Doctrine is using HYDRATE_RECORD, that causes objects to be returned. And there are a few other Hydrators you can read about here: <a href="http://www.doctrine-project.org/documentation/manual/1_2/en/data-hydrators" rel="nofollow">http://www.doctrine-project.org/documentation/manual/1_2/en/data-hydrators</a></p>
<h4>Why?</h4>
<p>Hydrators can have certain performance benefits. Creating an array is faster than creating an object that has lots of overhead. And arrays take less memory too.</p>
<p>Also there are things you can do with arrays that you cannot do with a Doctrine object. If you prefer to handle the data as an array, Hydration is the way to go.</p>
<p>We are going to be using HYDRATE_ARRAY to fetch a list of Threads in the following sections, to demonstrate the usage.</p>
<h3>CSS Changes</h3>
<p>Before we move on, I want to make some CSS changes, so the new pages we build will be styled.</p>
<ul>
<li>Edit: <strong>css/style.css</strong></li>
</ul>
<pre class="brush: css;">
body {
	font-family: &quot;Trebuchet MS&quot;,Arial;
	font-size: 14px;
	background-color: #212426;
	color: #B9AA81;
}
a			{color: #FFF;}
a:hover		{color: #B9AA81;}
input, textarea, select {
	font-family:inherit; font-size:inherit;	font-weight:inherit;
}
.container	{width: 720px; margin: auto;}
/* FORUMS -----------------------------------------*/
.forums.container h2 {
	font-size: 16px;
	color: #000;
	padding: 5px 10px 5px 10px;
	margin: 0px;
	background-color: #BBB;
	-moz-border-radius-topleft: 6px;
	-moz-border-radius-topright: 6px;
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
}
.forums.container h3			{font-size: 15px; margin: 0px;}
.forums.container .category 	{margin-bottom: 40px;}
.forums.container .forum 		{border-bottom: 1px solid #666;	padding: 10px;}
.forums.container .forum .description	{font-size: 14px;}
/* FORUM -----------------------------------------*/
.forum.container h2 {
	font-size: 16px;
	color: #000;
	padding: 5px 10px 5px 10px;
	margin: 0px;
	background-color: #BBB;
	-moz-border-radius-topleft: 6px;
	-moz-border-radius-topright: 6px;
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
}
.forum.container h3			{font-size: 15px; margin: 0px 0px 5px 0px;}
.forum.container .thread	{border-bottom: 1px solid #666;	padding: 10px;}
/* SIGNUP FORM ------------------------------------*/
#signup_form	{margin: auto; width: 360px; font-size: 16px;}
#signup_form .heading {
	text-align: center;	font-size: 22px; font-weight: bold;	color: #B9AA81;
}
#signup_form form {
	background-color: #B9AA81;
	padding: 10px;
	-moz-border-radius: 8px;
	-webkit-border-radius: 8px;
}
#signup_form form label {font-weight: bold;	color: #11151E;}
#signup_form form input[type=text],input[type=password] {
	width: 316px;
	font-weight: bold;
	padding: 8px;
	border: 1px solid #FFF;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
}
#signup_form form input[type=submit] {
	display: block;
	margin: auto;
	width: 200px;
	font-size: 18px;
	background-color: #FFF;
	border: 1px solid #BBB;
}
#signup_form form input[type=submit]:hover {border-color: #000;}
#signup_form .error {font-size: 13px; color: #690C07; font-style: italic; }
/* USER CONTROL BOX -------------------------------*/
.user_controls {float: right; text-align: right;}
</pre>
<h3>Forum Pages</h3>
<p>Now, let&#8217;s use what we have, to build the Forum Pages. These pages will list all the Threads, in a given Forum.</p>
<p>Currently, on the Home page we have links like this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_3.png" alt="ci_doctrine_day9_3" title="ci_doctrine_day9_3" width="585" height="235" class="aligncenter size-full wp-image-727" /></p>
<p>We created these links, because we expect to have a Controller named &#8216;Forums&#8217; that has a function named &#8216;Display&#8217;. </p>
<p>There is also an ID number at the end of the URL. That is passed to the Controller function as a parameter.</p>
<p>This Controller is supposed to load a page that lists all the Threads in that particular Forum.</p>
<h4>Forums Controller</h4>
<p>The skeleton structure first:</p>
<ul>
<li>Create: <strong>system/application/controllers/forums.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Forums extends Controller {

	public function display($id) {

	}

}
</pre>
<p>It looks like any other Controller. But this time we are expecting a parameter being passed to the <strong>display()</strong> method. The string that comes after <strong>/forums/display/</strong> in the URL automatically gets passed as the first parameter to that method.</p>
<p>For example: </p>
<pre>
http://localhost/ci_doctrine/forums/display/1
</pre>
<p>Will call <strong>display(1)</strong> in the Forums Class. We are going to use that parameter as the Forum ID. Then we need to display the Forum page.</p>
<p>The Controller needs to obtain the following pieces of data, and pass them on to the View:</p>
<ul>
<li>The <strong>title</strong> of the Forum.</li>
<li>Each <strong>Thread</strong> under the Forum.</li>
<li>For each Thread, we need Thread <strong>title</strong>, <strong>create date</strong>, <strong>author name</strong> and <strong>number of replies</strong>.</li>
</ul>
<p>Please note that the create date of the Thread is not part of the Thread Model (or table), because of the way we designed the Models. The first Post inside of the Thread carries a create date already, so we did not want to duplicate that data again. Same thing goes for the author (or user_id) of the Thread.</p>
<p>Now let&#8217;s add some code to make this happen:</p>
<pre class="brush: php; highlight: [9];">
&lt;?php
class Forums extends Controller {

	public function display($id) {

		$forum = Doctrine::getTable('Forum')-&gt;find($id);

		$vars['title'] = $forum['title'];
		$vars['threads'] = $forum-&gt;getThreadsArray();
		$vars['content_view'] = 'forum';
		$vars['container_css'] = 'forum';

		$this-&gt;load-&gt;view('template', $vars);

	}

}
</pre>
<p>First we get an instance of the Forum object with the id $id. Then we create the array of variables that will be passed to the template View.</p>
<p>At line 9 you can see that I am attempting to call a method named <strong>getThreadsArray()</strong>. This does not exist yet, so let&#8217;s build it.</p>
<p>The idea is to create a method that can return all associated Threads in an array structure. But we also want each Thread to have information such as: number of replies, date (of first post), author of (first post).</p>
<ul>
<li>Edit: <strong>system/application/models/forum.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Forum extends Doctrine_Record {

// ...

	public function getThreadsArray() {

		$threads = Doctrine_Query::create()
			-&gt;select('t.title')
			-&gt;addSelect('p.id, (COUNT(p.id) - 1) as num_replies')
			-&gt;addSelect('MIN(p.id) as first_post_id')
			-&gt;from('Thread t, t.Posts p')
			-&gt;where('t.forum_id = ?', $this-&gt;id)
			-&gt;groupBy('t.id')
			-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
			-&gt;execute();

		foreach ($threads as &amp;$thread) {

			$post = Doctrine_Query::create()
				-&gt;select('p.created_at, u.username')
				-&gt;from('Post p, p.User u')
				-&gt;where('p.id = ?', $thread['Posts'][0]['first_post_id'])
				-&gt;setHydrationMode(Doctrine::HYDRATE_ARRAY)
				-&gt;fetchOne();

			$thread['num_replies'] = $thread['Posts'][0]['num_replies'];
			$thread['created_at'] = $post['created_at'];
			$thread['username'] = $post['User']['username'];
			$thread['user_id'] = $post['User']['id'];
			unset($thread['Posts']);

		}

		return $threads;

	}
</pre>
<p>In the first DQL query:</p>
<p>Look at the <strong>from()</strong> call first. We are joining 2 Models (Thread, Post) because we need information from both. </p>
<p>Now look at the <strong>select()</strong> and <strong>addSelect()</strong> calls to see what we are getting:<br />
- We select the title for every Thread.<br />
- Then we select the number of Posts under each Thread by using <strong>COUNT(p.id)</strong>, and subtract 1 to get number of replies.<br />
- Finally we are also getting the ID for the first Post in that Thread using <strong>MIN(p.id)</strong>. That will be used later in the second DQL query.</p>
<p><strong>where(&#8217;t.forum_id = ?&#8217;, $this->id)</strong> indicates which Forum id we are looking up.</p>
<p><strong>groupBy(&#8217;t.id&#8217;)</strong> groups the results by the Thread id, so the Post count works properly.</p>
<p>Then, we loop through the Threads to get some more data into each Thread:</p>
<p>In the first query we fetched the ID of the first post on each Thread and stored it as <strong>first_post_id</strong>. So this DQL query now gets data for that Post and also the <strong>username</strong> of its author by joining to the related User Model.</p>
<p>The rest of the code, I just arranged all the values in $thread so it has a nice structure when returned.</p>
<p>Just to give you a better picture, if you were to print_r <strong>$threads</strong> , it would look this this:</p>
<pre>
Array
(
    [0] => Array
        (
            [id] => 1
            [title] => Hi there!
            [num_replies] => 1
            [first_post_id] => 1
            [created_at] => 2009-12-13 13:00:09
            [username] => TestUser
            [user_id] => 2
        )

    [1] => Array
        (
            [id] => 2
            [title] => Greetings to all
            [num_replies] => 0
            [first_post_id] => 3
            [created_at] => 2009-12-13 13:00:09
            [username] => Foobar
            [user_id] => 3
        )

)
</pre>
<p>I did <strong>unset($thread['Posts'])</strong> in the code just to keep the resulting array cleaner.</p>
<p>Note that we used HYDRATE_ARRAY, like we talked about earlier. This allowed us to do 2 things that we couldn&#8217;t have done with Doctrine_Collection objects:<br />
- When we <strong>foreach()</strong> the Threads, we are able to get each element by reference (<strong>&#038;$thread</strong>), and modify them.<br />
- We are able to create new array elements and assign values to them, like this:<br />
<strong> $thread['username'] = $post['User']['username'];</strong>.</p>
<p>Now, we need to create the View that will be for the content section of this page. </p>
<h4>Forum View</h4>
<p>In the Controller we passed this: <strong>$vars['content_view'] = &#8216;forum&#8217;;</strong><br />
So the Template will look for a View named &#8216;forum&#8217;.</p>
<ul>
<li>Create: <strong>system/application/views/forum.php</strong></li>
</ul>
<pre class="brush: php; html-script: true;">
&lt;h2&gt;&lt;?php echo $title ?&gt;&lt;/h2&gt;

&lt;?php foreach($threads as $thread): ?&gt;
&lt;div class=&quot;thread&quot;&gt;

	&lt;h3&gt;
		&lt;?php echo anchor('threads/display/'.$thread['id'], $thread['title']) ?&gt;
		(&lt;?php echo $thread['num_replies']; ?&gt; replies)
	&lt;/h3&gt;

	&lt;div&gt;
		Author: &lt;em&gt;&lt;?php echo anchor('profile/display/'.$thread['user_id'],
								$thread['username']); ?&gt;&lt;/em&gt;,
		Posted: &lt;em&gt;&lt;?php echo $thread['created_at']; ?&gt;&lt;/em&gt;
	&lt;/div&gt;

&lt;/div&gt;
&lt;?php endforeach; ?&gt;
</pre>
<p>There is nothing new here. Just putting the data into HTML.</p>
<h4>The Result</h4>
<ul>
<li>Go to the Home Page and click on the first Forum.</li>
</ul>
<p>You should see this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day9_5.png" alt="ci_doctrine_day9_5" title="ci_doctrine_day9_5" width="590" height="291" class="aligncenter size-full wp-image-744" /></p>
<p>Seems to be working!</p>
<h3>Stay Tuned</h3>
<p>We built another page in our project and explored two more important subjects along the way. Stay tuned for the next article, there is still plenty of work to do <img src='http://www.phpandstuff.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Thank you for reading. </p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/q0rfn_TrIWE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators/feed</wfw:commentRss>
		<slash:comments>52</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators</feedburner:origLink></item>
		<item>
		<title>Top 15+ Best Practices for Writing Super Readable Code</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/eE0r5vI6S7g/top-15-best-practices-for-writing-super-readable-code</link>
		<comments>http://www.phpandstuff.com/articles/top-15-best-practices-for-writing-super-readable-code#comments</comments>
		<pubDate>Thu, 10 Dec 2009 03:31:24 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=711</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-713" /> My third article for <a href="http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/" rel="nofollow">Nettuts</a> was just published:

<em>"Code readability is a universal subject in the world of computer programming. It's one of the first things we learn as developers. Readable and maintainable code is something to be proud of in a finished product. We can share it with others, contribute to other projects, and reuse code from applications we wrote months or even years ago.

This article will detail the fifteen most important best practices when writing readable code."</em>

Read More: <a href="http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/" rel="nofollow">http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Ftop-15-best-practices-for-writing-super-readable-code"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Ftop-15-best-practices-for-writing-super-readable-code" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-713" /> My third article for <a href="http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/" rel="nofollow">Nettuts</a> was just published:</p>
<p><em>&#8220;Code readability is a universal subject in the world of computer programming. It&#8217;s one of the first things we learn as developers. Readable and maintainable code is something to be proud of in a finished product. We can share it with others, contribute to other projects, and reuse code from applications we wrote months or even years ago.</p>
<p>This article will detail the fifteen most important best practices when writing readable code.&#8221;</em></p>
<p>Read More: <a href="http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/" rel="nofollow">http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/eE0r5vI6S7g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/top-15-best-practices-for-writing-super-readable-code/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/top-15-best-practices-for-writing-super-readable-code</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch. Day 8 – Hooks, Profiling &amp; DQL</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/kM1ulA7TBG8/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql#comments</comments>
		<pubDate>Fri, 04 Dec 2009 04:52:10 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=649</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this article we are going to look at 3 main subjects: Hooks (with CodeIgniter), Doctrine Profiling and DQL. And we are going to see how we can use these to optimize some of our database interactions.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-8-hooks-profiling-dql"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-8-hooks-profiling-dql" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this article we are going to look at 3 main subjects: <strong>Hooks</strong> (with CodeIgniter), Doctrine <strong>Profiling</strong> and <strong>DQL</strong>. And we are going to see how we can use these to optimize some of our database interactions.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day8.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<p>Before we start going into Hooks, Profiling and DQL, let&#8217;s make a small addition to our Message Board home page.</p>
<h3>User Controls</h3>
<p>In Message Boards, there is usually a section in the top right, with user specific info and links. I am not sure if there is a better name for it, but I&#8217;m going to call it &#8220;User Controls&#8221;.</p>
<p>On the <a href="http://codeigniter.com/forums/" rel="nofollow">CodeIgniter Forums</a> it looks like this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day8_1.png" alt="ci_doctrine_day8_1" title="ci_doctrine_day8_1" width="454" height="179" class="aligncenter size-full wp-image-650" /></p>
<p>And if you are not logged in, it looks like this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day8_2.png" alt="ci_doctrine_day8_2" title="ci_doctrine_day8_2" width="466" height="183" class="aligncenter size-full wp-image-651" /></p>
<p>Now we are going add something similar, but simpler, to our Message Board.</p>
<h4>Home View</h4>
<ul>
<li>Edit: <strong>system/application/views/home.php</strong></li>
</ul>
<pre class="brush: php; highlight: [13,14,15,16,17,18,19,20,21];">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Home&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div class=&quot;forums&quot;&gt;

	&lt;div class=&quot;user_controls&quot;&gt;
		&lt;?php if ($user = Current_User::user()): ?&gt;
			Hello, &lt;em&gt;&lt;?php echo $user-&gt;username; ?&gt;&lt;/em&gt; &lt;br/&gt;
			&lt;?php echo anchor('logout', 'Logout'); ?&gt;
		&lt;?php else: ?&gt;
			&lt;?php echo anchor('login','Login'); ?&gt; |
			&lt;?php echo anchor('signup', 'Register'); ?&gt;
		&lt;?php endif; ?&gt;
	&lt;/div&gt;

	&lt;h1&gt;CI+Doctrine Message Board&lt;/h1&gt;

	&lt;?php foreach($categories as $category): ?&gt;

		&lt;div class=&quot;category&quot;&gt;

			&lt;h2&gt;&lt;?php echo $category-&gt;title; ?&gt;&lt;/h2&gt;

			&lt;?php foreach($category-&gt;Forums as $forum): ?&gt;

				&lt;div class=&quot;forum&quot;&gt;

					&lt;h3&gt;
						&lt;?php echo anchor('forums/'.$forum-&gt;id, $forum-&gt;title) ?&gt;
						(&lt;?php echo $forum-&gt;Threads-&gt;count(); ?&gt; threads)
					&lt;/h3&gt;

					&lt;div class=&quot;description&quot;&gt;
						&lt;?php echo $forum-&gt;description; ?&gt;
					&lt;/div&gt;

				&lt;/div&gt;

			&lt;?php endforeach; ?&gt;

		&lt;/div&gt;

	&lt;?php endforeach; ?&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>We just added the highlighted lines. </p>
<p><strong>Line 13:</strong> We are using the <strong>Current_User</strong> class, to see if the user is logged in. If they are logged in, we will get an instance of the <strong>User Model</strong>. If not, it will return false.</p>
<p><strong>Lines 15-16:</strong> We display the username, and link to the <strong>Logout Controller</strong>.</p>
<p><strong>Lines 18-19:</strong> This section is for people who are not logged in. We link to the <strong>Login Controller</strong> and <strong>Signup Controller</strong>.</p>
<p>So we pretty much have just utilized Models and Controllers we have built before.</p>
<p>We need to make a small addition to the css.</p>
<ul>
<li>Edit: <strong>css/style.css</strong></li>
<li>Add this to the end of the file.</li>
</ul>
<pre class="brush: css;">
/* USER CONTROL BOX -------------------------------*/
.user_controls {
	float: right;
	text-align: right;
}
</pre>
<h4>Testing</h4>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day8_3.png" alt="ci_doctrine_day8_3" title="ci_doctrine_day8_3" width="580" height="411" class="aligncenter size-full wp-image-661" /></p>
<p>The links are showing up at the top right corner.</p>
<ul>
<li>Click Login.</li>
<li>Login as Testuser:mypass .</li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day8_4.png" alt="ci_doctrine_day8_4" title="ci_doctrine_day8_4" width="411" height="343" class="aligncenter size-full wp-image-662" /></p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/ci_doctrine_day8_5.png" alt="ci_doctrine_day8_5" title="ci_doctrine_day8_5" width="590" height="418" class="aligncenter size-full wp-image-663" /></p>
<p>Now we can see the username and the Logout link.</p>
<p>We will add more features to this later in other tutorials.</p>
<h3>Profiling with Doctrine</h3>
<p>Using Doctrine, our code is cleaner, smaller and easier to read and maintain. But it is sometimes a good idea to look at a few things that are going on behind the scenes. </p>
<p>For example, Doctrine executes several SQL queries for us, while we use our Models. It would be nice to know what these queries are, so we can see if there is more room for optimization. This can be accomplished by <strong>Profiling</strong>.</p>
<p>For this, we are going to be using a Doctrine component called <strong>Doctrine_Connection_Profiler</strong>.</p>
<h4>Profiling the Home Page</h4>
<p>Let&#8217;s look at what queries are executed on the home page. We are going to make a quick and dirty test for now. Later in the article we&#8217;ll make a more re-usable version.</p>
<p>There is going to be lots of new code here, but I will explain them line by line:</p>
<ul>
<li>Edit: <strong>system/application/controllers/test.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Test extends Controller {

//...

	function home_profiler() {

		// set up the profiler
		$profiler = new Doctrine_Connection_Profiler();
		foreach (Doctrine_Manager::getInstance()-&gt;getConnections() as $conn) {
			$conn-&gt;setListener($profiler);
		}

		// copied from home controller
		$vars['categories'] = Doctrine::getTable('Category')-&gt;findAll();

		$this-&gt;load-&gt;view('home', $vars);

		// analyze the profiler data
		$time = 0;
		$events = array();
		foreach ($profiler as $event) {
		    $time += $event-&gt;getElapsedSecs();
			if ($event-&gt;getName() == 'query' || $event-&gt;getName() == 'execute') {
				$event_details = array(
					&quot;type&quot; =&gt; $event-&gt;getName(),
					&quot;query&quot; =&gt; $event-&gt;getQuery(),
					&quot;time&quot; =&gt; sprintf(&quot;%f&quot;, $event-&gt;getElapsedSecs())
				);
				if (count($event-&gt;getParams())) {
					$event_details[&quot;params&quot;] = $event-&gt;getParams();
				}
				$events []= $event_details;
			}
		}
		print_r($events);
		echo &quot;\nTotal Doctrine time: &quot; . $time  . &quot;\n&quot;;
		echo &quot;Peak Memory: &quot; . memory_get_peak_usage() . &quot;\n&quot;;
	}

}
</pre>
<p><strong>Lines 15-17</strong> are just copied from the home Controller. Before that, we set up the Profiler, and after that we look at the data gathered by the Profiler.</p>
<p><strong>Lines 9-12</strong>: First we create a Profiler object. Then we attach it to every Doctrine connection. In our case, it will be just one connection. Now it&#8217;s ready to listen and record all Doctrine events.</p>
<p><strong>Line 22</strong>: The Profiler object let&#8217;s us loop through it and get each Event object. Events can be executed queries and also other things like fetching row data etc.. But we are only going to look at query events.</p>
<p><strong>Lines 20,23 and 37</strong>: Each Event has information on how much time it took. So we will add them up in $time variable and display it at the end.</p>
<p><strong>Line 24</strong>: We are only interested in SQL queries. These can be types &#8216;query&#8217; or &#8216;execute&#8217;. If a query has assigned parameters (for example &#8216;WHERE id = ?&#8217;), then it is of type &#8216;execute&#8217;, otherwise it is &#8216;query&#8217;.</p>
<p><strong>Lines 25-32</strong>: We create an array ($event_details) with information about the query. The type, the query SQL, and the time it took to run. Also if there were any parameters, we add that too.</p>
<p><strong>Lines 33 and 36</strong>: We add it all into the $events array, and just dump it at the end with print_r().</p>
<p><strong>Line 38</strong>: We use the memory_get_peak_usage() PHP function to find out what the maximum memory usage was during the script execution.</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/test/home_profiler" rel="nofollow">http://localhost/ci_doctrine/test/home_profiler</a></li>
<li>View Source:</li>
</ul>
<pre>
Array
(
    [0] => Array
        (
            [type] => query
            [query] => SELECT c.id AS c__id, c.title AS c__title FROM category c
            [time] => 0.000220
        )

    [1] => Array
        (
            [type] => execute
            [query] => SELECT u.id AS u__id, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM user u WHERE u.id = ? LIMIT 1
            [time] => 0.000310
            [params] => Array
                (
                    [0] => 2
                )

        )

    [2] => Array
        (
            [type] => execute
            [query] => SELECT f.id AS f__id, f.title AS f__title, f.description AS f__description, f.category_id AS f__category_id FROM forum f WHERE f.category_id IN (?)
            [time] => 0.000322
            [params] => Array
                (
                    [0] => 1
                )

        )

    [3] => Array
        (
            [type] => execute
            [query] => SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] => 0.000208
            [params] => Array
                (
                    [0] => 1
                )

        )

    [4] => Array
        (
            [type] => execute
            [query] => SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] => 0.000169
            [params] => Array
                (
                    [0] => 2
                )

        )

    [5] => Array
        (
            [type] => execute
            [query] => SELECT f.id AS f__id, f.title AS f__title, f.description AS f__description, f.category_id AS f__category_id FROM forum f WHERE f.category_id IN (?)
            [time] => 0.000322
            [params] => Array
                (
                    [0] => 2
                )

        )

    [6] => Array
        (
            [type] => execute
            [query] => SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] => 0.000238
            [params] => Array
                (
                    [0] => 3
                )

        )

    [7] => Array
        (
            [type] => execute
            [query] => SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] => 0.000171
            [params] => Array
                (
                    [0] => 4
                )

        )

    [8] => Array
        (
            [type] => execute
            [query] => SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] => 0.000160
            [params] => Array
                (
                    [0] => 5
                )

        )

)

Total Doctrine time: 0.013517618179321
Peak Memory: 5849232
</pre>
<p>As you can see, there were 9 queries executed by Doctrine. That seems too many. This happens because of the way Doctrine does &#8216;lazy loading&#8217;. It fetches data from the database as we access the objects and their parameters.</p>
<p>Later in the article, we are going to see how we can optimize this with DQL.</p>
<p>Let&#8217;s see how we can use the Profiler for the entire application, in a re-usable way. For that, we&#8217;re going to look at CodeIgniter Hooks.</p>
<h3>CodeIgniter Hooks</h3>
<p>With <strong>Hooks</strong>, we can tell CodeIgniter to perform an operation, at a given point in the application flow.</p>
<p>For example, we are going to initialize the Profiler, before any Controller function is called.</p>
<h4>Enabling Hooks</h4>
<p>Hooks are disabled by default, so we must first enable them.</p>
<ul>
<li>Edit: <strong>system/application/config/config.php</strong></li>
</ul>
<pre class="brush: php;">
// ...

/*
|--------------------------------------------------------------------------
| Enable/Disable System Hooks
|--------------------------------------------------------------------------
|
| If you would like to use the &quot;hooks&quot; feature you must enable it by
| setting this variable to TRUE (boolean).  See the user guide for details.
|
*/
$config['enable_hooks'] = TRUE;

// ...
</pre>
<p>Just changed it from FALSE to TRUE. Now we can use Hooks.</p>
<h4>Creating a Profiler Hook</h4>
<p>Let&#8217;s create the functions that will be called for this hook.</p>
<ul>
<li>Create: <strong>system/application/hooks/doctrine_profiler_hooks.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Doctrine_Profiler_Hooks {

	public static $profiler;

	public function profiler_start() {

		self::$profiler = new Doctrine_Connection_Profiler();
		foreach (Doctrine_Manager::getInstance()-&gt;getConnections() as $conn) {
			$conn-&gt;setListener(self::$profiler);
		}

	}

	public function profiler_end() {

		// analyze the profiler data
		$time = 0;
		$events = array();
		foreach (self::$profiler as $event) {
		    $time += $event-&gt;getElapsedSecs();
			if ($event-&gt;getName() == 'query' || $event-&gt;getName() == 'execute') {
				$event_details = array(
					&quot;type&quot; =&gt; $event-&gt;getName(),
					&quot;query&quot; =&gt; $event-&gt;getQuery(),
					&quot;time&quot; =&gt; sprintf(&quot;%f&quot;, $event-&gt;getElapsedSecs())
				);
				if (count($event-&gt;getParams())) {
					$event_details[&quot;params&quot;] = $event-&gt;getParams();
				}
				$events []= $event_details;
			}
		}

		$output = &quot;&lt;&quot;.&quot;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?&quot;.&quot;&gt;\n\n&quot;;
		$output .= print_r($events,1);
		$output .= &quot;\nTotal Doctrine time: &quot; . $time  . &quot;\n&quot;;
		$output .= &quot;Peak Memory: &quot; . memory_get_peak_usage() . &quot;&quot;;

		file_put_contents(BASEPATH.&quot;/logs/doctrine_profiler.php&quot;, $output);
	}
}
</pre>
<p>The code is mostly the same as before. This time we are storing the $profiler as a static variable in this class. Also, we are writing the output to a log file instead of dumping it into the browser.</p>
<h4>Adding the Hooks</h4>
<p>Now we need to add the hooks to the config so they get executed.</p>
<ul>
<li>Edit: <strong>system/application/config/hooks.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| Hooks
| -------------------------------------------------------------------------
| This file lets you define &quot;hooks&quot; to extend CI without hacking the core
| files.  Please see the user guide for info:
|
|	http://codeigniter.com/user_guide/general/hooks.html
|
*/

$hook['post_controller_constructor'][] = array(
	'class'    =&gt; 'Doctrine_Profiler_Hooks',
	'function' =&gt; 'profiler_start',
	'filename' =&gt; 'doctrine_profiler_hooks.php',
	'filepath' =&gt; 'hooks',
	);

$hook['post_controller'][] = array(
	'class'    =&gt; 'Doctrine_Profiler_Hooks',
	'function' =&gt; 'profiler_end',
	'filename' =&gt; 'doctrine_profiler_hooks.php',
	'filepath' =&gt; 'hooks',
	);

/* End of file hooks.php */
/* Location: ./system/application/config/hooks.php */
</pre>
<p>So we store the hooks inside the $hook array. The index of the array is name of the hook. In this case we used the &#8216;post_controller_constructor&#8217; and &#8216;post_controller&#8217; Hooks.</p>
<p>The array structure should be easy to understand. We point to the class name, function, file path, file name, so that CodeIgniter can find our code for execution.</p>
<p>(Note: I would have preferred to use the &#8220;pre_controller&#8221; Hook, because it happens before even the Controller constructor is called. However, the plug-ins are not initialized at that point, including Doctrine, so we need to use &#8220;post_controller_constructor&#8221; instead.)</p>
<h4>Testing</h4>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
</ul>
<p>You should just see the homepage with no errors. If you are getting file access errors, make sure the system/logs folder is writable.</p>
<ul>
<li>Open: <strong>system/logs/doctrine_profiler.php</strong></li>
</ul>
<p>You should see something like this:</p>
<pre class="brush: php;">
&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?&gt;

Array
(
    [0] =&gt; Array
        (
            [type] =&gt; query
            [query] =&gt; SELECT c.id AS c__id, c.title AS c__title FROM category c
            [time] =&gt; 0.000220
        )

    [1] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT u.id AS u__id, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM user u WHERE u.id = ? LIMIT 1
            [time] =&gt; 0.000310
            [params] =&gt; Array
                (
                    [0] =&gt; 2
                )

        )

    [2] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT f.id AS f__id, f.title AS f__title, f.description AS f__description, f.category_id AS f__category_id FROM forum f WHERE f.category_id IN (?)
            [time] =&gt; 0.000322
            [params] =&gt; Array
                (
                    [0] =&gt; 1
                )

        )

    [3] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000208
            [params] =&gt; Array
                (
                    [0] =&gt; 1
                )

        )

    [4] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000169
            [params] =&gt; Array
                (
                    [0] =&gt; 2
                )

        )

    [5] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT f.id AS f__id, f.title AS f__title, f.description AS f__description, f.category_id AS f__category_id FROM forum f WHERE f.category_id IN (?)
            [time] =&gt; 0.000322
            [params] =&gt; Array
                (
                    [0] =&gt; 2
                )

        )

    [6] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000238
            [params] =&gt; Array
                (
                    [0] =&gt; 3
                )

        )

    [7] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000171
            [params] =&gt; Array
                (
                    [0] =&gt; 4
                )

        )

    [8] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000160
            [params] =&gt; Array
                (
                    [0] =&gt; 5
                )

        )

)

Total Doctrine time: 0.013517618179321
Peak Memory: 5849232
</pre>
<p>Let&#8217;s see how we can optimize this and reduce the number of queries executed.</p>
<h3>Optimizing with DQL</h3>
<p>In the Day 5 &#8211; CRUD article, we had a first look at DQL. Now we are going to use it in our application.</p>
<p>If you are familiar with the CodeIgniter Active Records class, there are some similarities. However DQL is much more powerful.</p>
<h4>Reducing the Number of Queries</h4>
<ul>
<li>Edit: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Home extends Controller {

	public function index() {

		// $vars['categories'] = Doctrine::getTable('Category')-&gt;findAll();
		$vars['categories'] = Doctrine_Query::create()
			-&gt;select('c.title, f.title, f.description')
			-&gt;from('Category c, c.Forums f')
			-&gt;execute();

		$this-&gt;load-&gt;view('home', $vars);
	}	

}
</pre>
<p>We just commented out the <strong>findAll()</strong> line, and added a DQL call instead.</p>
<p>In the <strong>select()</strong> call we specify which fields we want to fetch.</p>
<p>In the <strong>from()</strong> call, we put the Models and use short aliases for them (c and f). Note that, we used c.Forums instead c.Forum, even though the Model was named Forum. This is because we are joining two models here, and in the Category Model definition, we referred to the Forum model as Forums:</p>
<pre class="brush: php; highlight: [12];">
&lt;?php

// models/category.php

class Category extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('title', 'string', 255);
	}

	public function setUp() {
		$this-&gt;hasMany('Forum as Forums', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'category_id'
		));
	}
}
</pre>
<p>It was just more suitable to name in plural since it&#8217;s a one-to-many relationship.</p>
<p>Another thing to note is that we did not specify an ON clause in DQL. Normally when you join tables in SQL, you would specify the columns you are joining on. But since our model definitions know how these relationships are set up, ON clause is not necessary in this case.</p>
<p>Finally, we run <strong>execute()</strong> to fetch the Doctrine_Collection object.</p>
<p>Let&#8217;s load the home page again, and then look at the profiler output.</p>
<ul>
<li>First go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
<li>Then open: <strong>system/logs/doctrine_profiler.php</strong></li>
</ul>
<p>You should see something like this:</p>
<pre class="brush: php;">
&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?&gt;

Array
(
    [0] =&gt; Array
        (
            [type] =&gt; query
            [query] =&gt; SELECT c.id AS c__id, c.title AS c__title, f.id AS f__id, f.title AS f__title, f.description AS f__description FROM category c LEFT JOIN forum f ON c.id = f.category_id
            [time] =&gt; 0.000311
        )

    [1] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT u.id AS u__id, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM user u WHERE u.id = ? LIMIT 1
            [time] =&gt; 0.000307
            [params] =&gt; Array
                (
                    [0] =&gt; 2
                )

        )

    [2] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000274
            [params] =&gt; Array
                (
                    [0] =&gt; 1
                )

        )

    [3] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000172
            [params] =&gt; Array
                (
                    [0] =&gt; 2
                )

        )

    [4] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000214
            [params] =&gt; Array
                (
                    [0] =&gt; 3
                )

        )

    [5] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000154
            [params] =&gt; Array
                (
                    [0] =&gt; 4
                )

        )

    [6] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT t.id AS t__id, t.title AS t__title, t.forum_id AS t__forum_id FROM thread t WHERE t.forum_id IN (?)
            [time] =&gt; 0.000311
            [params] =&gt; Array
                (
                    [0] =&gt; 5
                )

        )

)

Total Doctrine time: 0.012369155883789
Peak Memory: 5856440
</pre>
<p>Now we went down to 7 queries instead of 9. However, there is still room for improvement.</p>
<h4>Getting Count</h4>
<p>Currently, most of these queries are caused by the count() call in our Home View.</p>
<pre class="brush: php;">
(&lt;?php echo $forum-&gt;Threads-&gt;count(); ?&gt; threads)
</pre>
<p>Now we are going to fetch the thread count with DQL so that these extra queries do not need to run.</p>
<ul>
<li>Edit: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php; highlight: [9,11,12];">
&lt;?php
class Home extends Controller {

	public function index() {

		// $vars['categories'] = Doctrine::getTable('Category')-&gt;findAll();
		$vars['categories'] = Doctrine_Query::create()
			-&gt;select('c.title, f.title, f.description')
			-&gt;addSelect('t.id, COUNT(t.id) as num_threads')
			-&gt;from('Category c, c.Forums f')
			-&gt;leftJoin('f.Threads t')
			-&gt;groupBy('f.id')
			-&gt;execute();
		$this-&gt;load-&gt;view('home', $vars);
	}	

}
</pre>
<p>Highlighted lines are where the changes are.</p>
<p><strong>Line 11:</strong> Now we are selecting from the Threads Model too, so we can count them. I could have added the &#8216;Threads&#8217; model into the from() call in Line 10. But I wanted to demonstrate another way you can do joins in DQL. There is also innerjoin() if you need it.</p>
<p><strong>Line 9:</strong> COUNT(t.id) will give us the number of threads. I could have added this into the select() in Line 8, but for demonstration purposes again, I used the addSelect() function.</p>
<p><strong>Line 12:</strong> Since we want individual Forums returned, and also are counting the Threads per Forum, we are grouping the results by the Forum id field.</p>
<p>If you wanted to do the same thing in raw SQL, the query would look like this:</p>
<pre>
SELECT c.id, c.title, f.id, f.title, f.description, COUNT(t.id) AS num_threads FROM category c LEFT JOIN forum f ON c.id = f.category_id LEFT JOIN thread t ON f.id = t.forum_id GROUP BY f.id
</pre>
<h4>One More Change</h4>
<p>Now we need to do one more change. Since we are going to use the returned &#8216;num_threads&#8217; value instead of calling $forum->Threads->count(), we need to change a line in the Home View.</p>
<ul>
<li>Edit: <strong>system/application/views/home.php</strong> around line #37</li>
<li>Just change the highlighted line.</li>
</ul>
<pre class="brush: php; highlight: [6]; html-script: true;">
&lt;!-- --&gt;
&lt;div class=&quot;forum&quot;&gt;

	&lt;h3&gt;
		&lt;?php echo anchor('forums/'.$forum-&gt;id, $forum-&gt;title) ?&gt;
		(&lt;?php echo $forum-&gt;Threads[0]-&gt;num_threads; ?&gt; threads)
	&lt;/h3&gt;

	&lt;div class=&quot;description&quot;&gt;
		&lt;?php echo $forum-&gt;description; ?&gt;
	&lt;/div&gt;

&lt;/div&gt;
&lt;!-- --&gt;
</pre>
<p>At the first glance, the structure might seem a bit odd. Why not &#8216;$forum->Threads->num_threads&#8217;? or even &#8216;$forum->num_threads&#8217;?</p>
<p>This has to do with the way the query is structured. We called COUNT() on the <strong>Threads.id</strong> field. Therefore the returned data belongs to the Threads relationship, and not to the $forum object directly.</p>
<p>Also, the relationship is <strong>one-to-many</strong>. Therefore $forum->Threads is a <strong>Doctrine_Collection</strong> by default, instead of a Doctrine_Record. So we treat it like an array, and add the [0] index first before we can get the data in num_threads.</p>
<p>The result is: <strong>$forum->Threads[0]->num_threads</strong></p>
<p>If you are ever unsure about the structure of the returned Doctrine_Collection object, you can convert it to an array using <strong>toArray(true)</strong> and dump it on the screen. Passing &#8216;true&#8217; makes it &#8216;deep&#8217;, otherwise you only get the outermost object.</p>
<p>For example, if you do this:</p>
<pre class="brush: php; highlight: [8];">
$vars['categories'] = Doctrine_Query::create()
	-&gt;select('c.title, f.title, f.description')
	-&gt;addSelect('COUNT(t.id) as num_threads')
	-&gt;from('Category c, c.Forums f')
	-&gt;leftJoin('f.Threads t')
	-&gt;groupBy('f.id')
	-&gt;execute();
print_r($vars['categories']-&gt;toArray(true));
</pre>
<p>You can get an output like this:</p>
<pre>
Array
(
    [0] => Array
        (
            [id] => 1
            [title] => The CodeIgniter Lounge
            [Forums] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [title] => Introduce Yourself!
                            [description] => Use this forum to introduce yourself to the CodeIgniter community, or to announce your new CI powered site.

                            [category_id] => 1
                            [Category] =>
                            [Threads] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] =>
                                            [title] =>
                                            [forum_id] => 1
                                            [Forum] =>
                                            [num_threads] => 2
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 2
                            [title] => The Lounge
                            [description] => CodeIgniter's social forum where you can discuss anything not related to development. No topics off limits... but be civil.

                            [category_id] => 1
                            [Category] =>
                            [Threads] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] =>
                                            [title] =>
                                            [forum_id] => 2
                                            [Forum] =>
                                            [num_threads] => 0
                                        )

                                )

                        )

                )

            [num_threads] => 2
        )

    [1] => Array
        (
            [id] => 2
            [title] => CodeIgniter Development Forums
            [Forums] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [title] => CodeIgniter Discussion
                            [description] => This forum is for general topics related to CodeIgniter.
                            [category_id] => 2
                            [Category] =>
                            [Threads] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] =>
                                            [title] =>
                                            [forum_id] => 3
                                            [Forum] =>
                                            [num_threads] => 0
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 4
                            [title] => Code and Application Development
                            [description] => Use the forum to discuss anything related to programming and code development.

                            [category_id] => 2
                            [Category] =>
                            [Threads] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] =>
                                            [title] =>
                                            [forum_id] => 4
                                            [Forum] =>
                                            [num_threads] => 0
                                        )

                                )

                        )

                    [2] => Array
                        (
                            [id] => 5
                            [title] => Ignited Code
                            [description] => Use this forum to post plugins, libraries, or other code contributions, or to ask questions about any of them.

                            [category_id] => 2
                            [Category] =>
                            [Threads] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] =>
                                            [title] =>
                                            [forum_id] => 5
                                            [Forum] =>
                                            [num_threads] => 0
                                        )

                                )

                        )

                )

            [num_threads] => 0
        )

)
</pre>
<h4>Profile Again</h4>
<p>Let&#8217;s look at the profiling results again to see how the new DQL performed.</p>
<ul>
<li>First go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
<li>Then open: <strong>system/logs/doctrine_profiler.php</strong></li>
</ul>
<p>You should see something like this:</p>
<pre class="brush: php;">
&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?&gt;

Array
(
    [0] =&gt; Array
        (
            [type] =&gt; query
            [query] =&gt; SELECT c.id AS c__id, c.title AS c__title, f.id AS f__id, f.title AS f__title, f.description AS f__description, COUNT(t.id) AS t__0 FROM category c LEFT JOIN forum f ON c.id = f.category_id LEFT JOIN thread t ON f.id = t.forum_id GROUP BY f.id
            [time] =&gt; 0.000493
        )

    [1] =&gt; Array
        (
            [type] =&gt; execute
            [query] =&gt; SELECT u.id AS u__id, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM user u WHERE u.id = ? LIMIT 1
            [time] =&gt; 0.000354
            [params] =&gt; Array
                (
                    [0] =&gt; 2
                )

        )

)

Total Doctrine time: 0.011896848678589
Peak Memory: 6010440
</pre>
<p>Nice, we are all the way down to 2 queries! </p>
<p>The first one is for fetching all Categories, their Forums, and Thread counts all at once. And the second query was done by the Current_User class for getting user details. You can&#8217;t go much lower than this.</p>
<h3>Conclusions</h3>
<p>I admit that our code became a little more complicated when we switched from using findAll() to DQL. But if your web application is expecting a significant amount of traffic, you might need to utilize such optimizations. Also, with DQL you can achieve more complicated queries that would not be practical with the magic functions like findAll() or findBy*().</p>
<p>Optimization is a debatable subject. Some prefer to do it early, in small steps. Some prefer to do it all the way at the end of development. But as you gain experience, your initial code tends to be more optimized in the first place, and may not need many changes later on.</p>
<p>I guess the point is, using an ORM like Doctrine does not magically optimize your database interactions. You still need to put an effort into it.</p>
<h3>Stay Tuned</h3>
<p>Thank you for reading. Learning more about DQL was an important step, as it is an integral part of Doctrine. Also, Hooks and Profiling gave us an opportunity to look at what is going on behind the scenes.</p>
<p>And thank you for all the encouraging comments. It makes writing these articles even more enjoyable.</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/kM1ulA7TBG8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql/feed</wfw:commentRss>
		<slash:comments>26</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql</feedburner:origLink></item>
		<item>
		<title>HTTP Headers for Dummies</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/7Vytb2sRiFc/http-headers-for-dummies</link>
		<comments>http://www.phpandstuff.com/articles/http-headers-for-dummies#comments</comments>
		<pubDate>Wed, 02 Dec 2009 20:16:12 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[headers]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=641</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview_http.jpg" alt="preview_http" title="preview_http" width="200" height="200" class="alignleft size-full wp-image-642" />My second article for Nettuts was just published:

<a href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/" rel="nofollow">http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/</a>

Whether you're a programmer or not, you have seen it everywhere on the web. At this moment your browsers address bar shows something that starts with "http://". Even your first Hello World script sent HTTP headers without you realizing it. In this article we are going to learn about the basics of HTTP headers and how we can use them in our web applications.

<a href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/" rel="nofollow">Read More</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fhttp-headers-for-dummies"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fhttp-headers-for-dummies" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/12/preview_http.jpg" alt="preview_http" title="preview_http" width="200" height="200" class="alignleft size-full wp-image-642" />My second article for Nettuts was just published:</p>
<p><a href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/" rel="nofollow">http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/</a></p>
<p>Whether you&#8217;re a programmer or not, you have seen it everywhere on the web. At this moment your browsers address bar shows something that starts with &#8220;http://&#8221;. Even your first Hello World script sent HTTP headers without you realizing it. In this article we are going to learn about the basics of HTTP headers and how we can use them in our web applications.</p>
<p><a href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/" rel="nofollow">Read More</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/7Vytb2sRiFc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/http-headers-for-dummies/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/http-headers-for-dummies</feedburner:origLink></item>
		<item>
		<title>Top 20+ MySQL Best Practices</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/xEAv8fBRmcQ/top-20-mysql-best-practices</link>
		<comments>http://www.phpandstuff.com/articles/top-20-mysql-best-practices#comments</comments>
		<pubDate>Wed, 25 Nov 2009 18:05:32 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=629</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/preview.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-630" /> Nettuts+ just published my article!  

<a href="http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/" rel="nofollow">http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/</a>

Database operations often tend to be the main bottleneck for most web applications today. It's not only the DBA's (database administrators) that have to worry about these performance issues. We as programmers need to do our part by structuring tables properly, writing optimized queries and better code. Here are some MySQL optimization techniques for programmers.

<a href="http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/">Read more</a>]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Ftop-20-mysql-best-practices"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Ftop-20-mysql-best-practices" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/preview.jpg" alt="preview" title="preview" width="200" height="200" class="alignleft size-full wp-image-630" /> Nettuts+ just published my article!  </p>
<p><a href="http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/" rel="nofollow">http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/</a></p>
<p>Database operations often tend to be the main bottleneck for most web applications today. It&#8217;s not only the DBA&#8217;s (database administrators) that have to worry about these performance issues. We as programmers need to do our part by structuring tables properly, writing optimized queries and better code. Here are some MySQL optimization techniques for programmers.</p>
<p><a href="http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/">Read more</a></p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/xEAv8fBRmcQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/top-20-mysql-best-practices/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/top-20-mysql-best-practices</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch Day 7 – Fixtures &amp; Forum List</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/ftmjK-BotRo/codeigniter-doctrine-scratch-day-7-fixtures-forum-list</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list#comments</comments>
		<pubDate>Fri, 20 Nov 2009 08:33:17 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=536</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> Today we will continue building our <strong>Message Board</strong> project. First we will start building the Home Page, which will be a <strong>Forum List</strong>. Then we will learn about <strong>Doctrine Data Fixtures</strong>. This will help us create some test data to play with.

<div class="clear"></div>

<img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day7_4.png" alt="ci_doctrine_day7_4" title="ci_doctrine_day7_4" width="600" height="422" class="aligncenter size-full wp-image-556" />]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-7-fixtures-forum-list"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-7-fixtures-forum-list" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> Today we will continue building our <strong>Message Board</strong> project. First we will start building the Home Page, which will be a <strong>Forum List</strong>. Then we will learn about <strong>Doctrine Data Fixtures</strong>. This will help us create some test data to play with.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day7.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<h3>First, Some Styling</h3>
<p>Before we get started, let&#8217;s add some style so that pages look somewhat decent. Just copy-paste, and don&#8217;t read it. CSS is not our focus today.</p>
<ul>
<li>Edit: <strong>css/style.css</strong></li>
</ul>
<pre class="brush: css;">
body {
	font-family: &quot;Trebuchet MS&quot;,Arial;
	font-size: 14px;
	background-color: #212426;
	color: #B9AA81;
}

a {
	color: #FFF;
}

a:hover {
	color: #B9AA81;
}

input, textarea, select {
	font-family:inherit;
	font-size:inherit;
	font-weight:inherit;
}

/* FORUMS -----------------------------------------*/

div.forums {
	width: 720px;
	margin: auto;
}

.forums h2 {
	font-size: 16px;
	color: #000;
	padding: 5px 10px 5px 10px;
	margin: 0px;
	background-color: #BBB;
	-moz-border-radius-topleft: 6px;
	-moz-border-radius-topright: 6px;
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
}

.forums h3 {
	font-size: 15px;
	margin: 0px;
}

.category {
	margin-bottom: 40px;
}

.forum {
	border-bottom: 1px solid #666;
	padding: 10px;
}

.forum .description {
	font-size: 14px;
}

/* SIGNUP FORM ------------------------------------*/
#signup_form {
	margin-left: auto;
	margin-right: auto;
	width: 360px;
	font-size: 16px;
}

#signup_form .heading {
	text-align: center;
	font-size: 22px;
	font-weight: bold;
	color: #B9AA81;
}

#signup_form form {
	background-color: #B9AA81;
	padding: 10px;
	border-radius: 8px;
	-moz-border-radius: 8px;
	-webkit-border-radius: 8px;
}

#signup_form form label {
	font-weight: bold;
	color: #11151E;
}

#signup_form form input[type=text],input[type=password] {
	width: 316px;
	font-weight: bold;
	padding: 8px;
	border: 1px solid #FFF;
	border-radius: 4px;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
}

#signup_form form input[type=submit] {
	display: block;
	margin: auto;
	width: 200px;
	font-size: 18px;
	background-color: #FFF;
	border: 1px solid #BBB;

}

#signup_form form input[type=submit]:hover {
	border-color: #000;
}

#signup_form .error {
	font-size: 13px;
	color: #690C07;
	font-style: italic;
}
</pre>
<p>Ok, now we&#8217;re ready to get more coding done!</p>
<h3>The Home Page</h3>
<p>We are about to work on the <strong>Controller</strong> and the <strong>View</strong> for our <strong>Home Page</strong> (i.e. Forum List). We want this page to show all of the <strong>Forums</strong> broken down by <strong>Categories</strong>.</p>
<h4>Home Controller</h4>
<ul>
<li>Edit: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Home extends Controller {

	public function index() {

		$vars['categories'] = Doctrine::getTable('Category')-&gt;findAll();

		$this-&gt;load-&gt;view('home', $vars);
	}	

}
</pre>
<p>As mentioned before, variables are passed to a <strong>View</strong> in an array, and the array indexes become variable names. In other words, $vars['categories'] becomes $categories inside the View.</p>
<p><strong>Doctrine::getTable(&#8217;Category&#8217;)->findAll();</strong> gives us all of the Category records, in the form of a <strong>Doctrine_Collection</strong> object.</p>
<h4>Home View</h4>
<p>(I&#8217;m going build this page in a few steps)</p>
<ul>
<li>Edit: <strong>system/application/views/home.php</strong></li>
</ul>
<p>First we make a blank page, with a container div and a heading:</p>
<pre class="brush: php; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Home&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div class=&quot;forums&quot;&gt;

	&lt;h1&gt;CI+Doctrine Message Board&lt;/h1&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Next, we loop thru the <strong>$categories</strong> object, and display titles for each Category:</p>
<pre class="brush: php; highlight: [15,16,17,18,19,20,21,22,23]; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Home&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div class=&quot;forums&quot;&gt;

	&lt;h1&gt;CI+Doctrine Message Board&lt;/h1&gt;

	&lt;?php foreach($categories as $category): ?&gt;

		&lt;div class=&quot;category&quot;&gt;

			&lt;h2&gt;&lt;?php echo $category-&gt;title; ?&gt;&lt;/h2&gt;

		&lt;/div&gt;

	&lt;?php endforeach; ?&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p><strong>Note:</strong> $categories is a <strong>Doctrine_Collection</strong> object here, but it can be treated like an array. So we can use <strong>foreach</strong> on it.</p>
<p>Now we are going to show each <strong>Forum</strong>, their <strong>descriptions</strong>, and number of <strong>Threads</strong>.</p>
<pre class="brush: php; highlight: [21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36]; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Home&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div class=&quot;forums&quot;&gt;

	&lt;h1&gt;CI+Doctrine Message Board&lt;/h1&gt;

	&lt;?php foreach($categories as $category): ?&gt;

		&lt;div class=&quot;category&quot;&gt;

			&lt;h2&gt;&lt;?php echo $category-&gt;title; ?&gt;&lt;/h2&gt;

			&lt;?php foreach($category-&gt;Forums as $forum): ?&gt;

				&lt;div class=&quot;forum&quot;&gt;

					&lt;h3&gt;
						&lt;?php echo anchor('forums/'.$forum-&gt;id, $forum-&gt;title) ?&gt;
						(&lt;?php echo $forum-&gt;Threads-&gt;count(); ?&gt; threads)
					&lt;/h3&gt;

					&lt;div class=&quot;description&quot;&gt;
						&lt;?php echo $forum-&gt;description; ?&gt;
					&lt;/div&gt;

				&lt;/div&gt;

			&lt;?php endforeach; ?&gt;

		&lt;/div&gt;

	&lt;?php endforeach; ?&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>As you can see, getting all Forums under a Category is as easy as calling <strong>$category->Forums</strong>. And again, we can treat it as an array and loop thru it.</p>
<p><strong>Line 26:</strong> We are creating a <strong>link</strong> to the Forum. It will link to a <strong>Controller</strong> named <strong>Forums</strong> and pass the <strong>id</strong> in the url. And the link text is the Forum title.</p>
<p><strong>Note:</strong> In CodeIgniter, <strong>Controllers</strong> and <strong>Models</strong> cannot have the same name. That&#8217;s why I linked to &#8216;forums&#8217; instead of &#8216;forum&#8217;. Some people might prefer &#8216;view_forum&#8217; or &#8217;show_forum&#8217; etc&#8230;</p>
<p><strong>Line 27:</strong> This is the first time we are using <strong>count()</strong>. That&#8217;s how we get the <strong>number of Threads</strong> that belong to that <strong>Forum</strong> object.</p>
<h4>The Result</h4>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
</ul>
<p>You will see this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day7_1.png" alt="ci_doctrine_day7_1" title="ci_doctrine_day7_1" width="600" height="377" class="aligncenter size-full wp-image-547" /></p>
<p>Looks nice. But the links are broken since we haven&#8217;t created the <strong>Forums Controller</strong> (i.e. Forum Page) yet.</p>
<p>Now, we could go ahead and build the Forum Page, but it&#8217;s just not going to look very good since we have no Threads or Posts whatsoever. This is a great time to start talking about <strong>Data Fixtures</strong>.</p>
<h3>Doctrine Data Fixtures</h3>
<h4>What are Data Fixtures?</h4>
<p>&#8220;<strong>Data fixtures</strong> are meant for loading small sets of test data through your models to populate your database with data to test against.&#8221; (from <a href="http://www.doctrine-project.org/documentation/manual/1_1/en/data-fixtures" rel="nofollow">here</a>).</p>
<p>This will do the job for filling the database with some data, so we can do proper testing as we develop our project.</p>
<p>In the last article, we created a Test Controller for inserting some data. That worked well for this tutorial, and we saw some code examples along the way. But on a real development environment, it&#8217;s better to just use Data Fixtures.</p>
<h4>Creating Fixtures</h4>
<p>First, we need to have a place to put our Fixtures. You can put this folder anywhere, but I would like to create it directly under the applications folder.</p>
<ul>
<li>Create Folder: <strong>system/application/fixtures</strong></li>
<li>Create: <strong>system/application/fixtures/data.yml</strong></li>
</ul>
<p>That&#8217;s right, we are creating a <strong>YAML</strong> file. Don&#8217;t worry if you are not familiar with this file format.</p>
<p>We are going to start small with an example:</p>
<pre class="brush: yaml;">
User:
  Admin:
    username: Administrator
    password: testing
    email: programming@gmail.com
  Test:
    username: TestUser
    password: mypass
    email: test@test.com
</pre>
<p>Even if you are not familiar with YAML, the structure is easy to understand.<br />
This code just creates 2 <strong>User</strong> records.</p>
<p><strong>Note</strong>: I used 2 spaces for <strong>indentation</strong>, but it can be any number of spaces. And Tabs do NOT work.</p>
<ul>
<li>First line is the name of the <strong>Model</strong> we are loading data for.</li>
<li><strong>Line 2 and 6</strong>: These are just names for these records. They can be anything. We can use them later in the fixture to reference these records.</li>
<li>The rest should be obvious. We are assigning data to each field for these records.</li>
</ul>
<p>Now, we need to load this fixture into the database.</p>
<ul>
<li>Edit: <strong>system/application/controllers/doctrine_tools.php</strong></li>
</ul>
<pre class="brush: php; highlight: [16];">
&lt;?php
class Doctrine_Tools extends Controller {

// ....

	function load_fixtures() {
		echo 'This will delete all existing data!&lt;br /&gt;
		&lt;form action=&quot;&quot; method=&quot;POST&quot;&gt;
		&lt;input type=&quot;submit&quot; name=&quot;action&quot; value=&quot;Load Fixtures&quot;&gt;&lt;br /&gt;&lt;br /&gt;';

		if ($this-&gt;input-&gt;post('action')) {

			Doctrine_Manager::connection()-&gt;execute(
				'SET FOREIGN_KEY_CHECKS = 0');

			Doctrine::loadData(APPPATH.'/fixtures');
			echo &quot;Done!&quot;;
		}
	}

}
</pre>
<p>We added a function named <strong>load_fixtures()</strong> to this Controller.</p>
<p><strong>Doctrine:loadData()</strong> does the work. Every time it is called, it will purge existing data from the tables, and load the <strong>Data Fixtures</strong> from the given path. If you don&#8217;t want the table purge to happen, you need to pass a second argument as <strong>true</strong>.</p>
<p>(I also had to disable FOREIGN_KEY_CHECKS to avoid some foreign key related errors during the purge.)</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/doctrine_tools/load_fixtures" rel="nofollow">http://localhost/ci_doctrine/doctrine_tools/load_fixtures</a> and click the button.</li>
<li>Now check the <strong>user table</strong> in phpmyadmin.</li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day7_2.png" alt="ci_doctrine_day7_2" title="ci_doctrine_day7_2" width="600" height="290" class="aligncenter size-full wp-image-552" /></p>
<p>Now that everything seems to be working, let&#8217;s expand our fixture so we have more data to work with.</p>
<ul>
<li>Edit: <strong>system/application/fixtures/data.yml</strong></li>
</ul>
<pre class="brush: yaml; highlight: [18,43,51];">
User:
  Admin:
    username: Administrator
    password: testing
    email: programming@gmail.com
  Test:
    username: TestUser
    password: mypass
    email: test@test.com
  Foo:
    username: Foobar
    password: mypass
    email: test2@test2.com

Forum:
  Forum_1:
    title: Introduce Yourself!
    description: &gt;
      Use this forum to introduce yourself to the CodeIgniter community,
      or to announce your new CI powered site.
  Forum_2:
    title: The Lounge
    description: &gt;
      CodeIgniter's social forum where you can discuss anything not related
      to development. No topics off limits... but be civil.
  Forum_3:
    title: CodeIgniter Discussion
    description: This forum is for general topics related to CodeIgniter.
  Forum_4:
    title: Code and Application Development
    description: &gt;
      Use the forum to discuss anything related to
      programming and code development.
  Forum_5:
    title: Ignited Code
    description: &gt;
      Use this forum to post plugins, libraries, or other code contributions,
      or to ask questions about any of them.

Category:
  Lounge:
    title: The CodeIgniter Lounge
    Forums: [Forum_1, Forum_2]
  Dev:
    title: CodeIgniter Development Forums
    Forums: [Forum_3, Forum_4, Forum_5]

Thread:
  Thread_1:
    title: Hi there!
    Forum: Forum_1
  Thread_2:
    title: Greetings to all
    Forum: Forum_1

Post:
  Post_1:
    Thread: Thread_1
    User: Test
    created_at: 2009-11-20 01:20:30
    content: &gt;
      Hello everyone! My name is Test, and I go to school at
      Test Institute of Technology in the US.
      I just found CodeIgniter some time last week and have been
      reading through the documentation trying to get myself acquainted.

      Hopefully the forums will be a great help! I already have some questions.
      Thanks!
  Post_2:
    Thread: Thread_1
    User: Admin
    created_at: 2009-11-20 02:15:33
    content: Welcome Test! Nice to meet you.
  Post_3:
    Thread: Thread_2
    User: Foo
    created_at: 2009-11-19 12:14:50
    content: I am new here. Just wanted to say hi.
</pre>
<p>This is just a bunch of structured data, nothing complicated. For each Model, we create a few records. And we have a few new things to mention:</p>
<p><strong>Line 18</strong>: Here you can see the syntax for adding a long string value in multiple lines.<br />
<strong>Line 51</strong>: We are setting up the <strong>relationships</strong> between records. This line says Thread_1 belongs to Forum_1.<br />
<strong>Line 43</strong>: Again, we are setting up relationships, but this time we are assigning multiple records, and you see the syntax for that.</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/doctrine_tools/load_fixtures" rel="nofollow">http://localhost/ci_doctrine/doctrine_tools/load_fixtures</a> and click the button.</li>
<li>And, go to <strong>phpmyadmin</strong> and look at all the tables.</li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day7_3.png" alt="ci_doctrine_day7_3" title="ci_doctrine_day7_3" width="524" height="225" class="aligncenter size-full wp-image-555" /></p>
<p>We just created 15 records!</p>
<h4>See the Results</h4>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/" rel="nofollow">http://localhost/ci_doctrine/</a></li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day7_4.png" alt="ci_doctrine_day7_4" title="ci_doctrine_day7_4" width="600" height="422" class="aligncenter size-full wp-image-556" /></p>
<p>We can see all the <strong>Categories</strong> and <strong>Forums</strong> we just created. Also there are 2 <strong>Threads</strong> now, as we can see from the count.</p>
<h3>Stay Tuned</h3>
<p>Our Message Board is starting to take shape. Meanwhile we learned about a new concept called <strong>Data Fixtures</strong>, which is very helpful during the development process.</p>
<p>In the next tutorials we will go deeper into the project and keep building more functional pages.</p>
<p>See you next time!</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/ftmjK-BotRo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list/feed</wfw:commentRss>
		<slash:comments>41</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch Day 6 – Models with Relationships</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/8aEaL1B3SKc/codeigniter-doctrine-day-6-models-relationships</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships#comments</comments>
		<pubDate>Fri, 13 Nov 2009 06:57:27 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=500</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this episode of the series, we will continue building our <strong>Message Board</strong> project. First we will have a quick overview of <strong>Doctrine Model Relationships</strong>. Then we will create <strong>Models</strong> for our Message Board, such as: Forums, Threads, Posts etc... with proper relationships. Finally we will learn how to <strong>add data</strong> into such Models.
]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-day-6-models-relationships"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-day-6-models-relationships" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> In this episode of the series, we will continue building our <strong>Message Board</strong> project. First we will have a quick overview of <strong>Doctrine Model Relationships</strong>. Then we will create <strong>Models</strong> for our Message Board, such as: Forums, Threads, Posts etc&#8230; with proper relationships. Finally we will learn how to <strong>add data</strong> into such Models.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day6.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<h3>Doctrine Model Relationships (a quick overview)</h3>
<p>One of the key features of <strong>Doctrine</strong> is the handling of <strong>Relationships</strong> between <strong>Models</strong>. At this point in our project, we will start utilizing it.</p>
<p>On a typical <strong>Message Board</strong>:</p>
<ul>
<li>There are <strong>Forums</strong></li>
<li><strong>Forums</strong> have <strong>Threads</strong></li>
<li><strong>Threads</strong> have <strong>Posts</strong></li>
<li><strong>Users</strong> have <strong>Posts</strong></li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day6_1.png" alt="ci_doctrine_day6_1" title="ci_doctrine_day6_1" width="450" height="450" class="aligncenter size-full wp-image-501" /></p>
<p>We will learn how to define these relationships in our Models. <strong>Doctrine</strong> supports the following types of relationships:</p>
<ul>
<li><strong>One to Many</strong> (or Many to One)</li>
<li><strong>One to One</strong></li>
<li><strong>Many to Many</strong></li>
<li><strong>Tree</strong> Structure</li>
<li><strong>Nest</strong> Relations</li>
</ul>
<p>Today we will be talking about only the first two.</p>
<h4>Foreign Keys</h4>
<p>To setup relationships between models (and tables in the database), we need to have certain fields in our tables. These are used as <strong>Foreign Keys</strong>.</p>
<p>For example, if each <strong>Post</strong> belongs to a <strong>User</strong>, we need a <strong>user_id</strong> field in the Post table. We can specify this in our model:</p>
<pre class="brush: php;">
class Post extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('content', 'string', 65535);
		$this-&gt;hasColumn('user_id', 'integer');
	}

}
</pre>
<p>But to specify the type of relationship, we are going to have to do more than that.</p>
<h4>One to Many Relationships</h4>
<p>Just like the name suggests, this creates a relationship<strong> between one instance of a Model and multiple instances of another Model</strong>.</p>
<p>For example: <strong>one</strong> User has <strong>many</strong> Posts. </p>
<p>In Doctrine, this kind of relationship is setup using the <strong>hasOne()</strong> and <strong>hasMany()</strong> functions.</p>
<p><strong>Post Example:</strong></p>
<pre class="brush: php; highlight: [5,9,10,11,12];">
class Post extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('content', 'string', 65535);
		$this-&gt;hasColumn('user_id', 'integer');
	}

	public function setUp() {
		$this-&gt;hasOne('User', array(
			'local' =&gt; 'user_id',
			'foreign' =&gt; 'id'
		));
	}

}
</pre>
<p><strong>hasOne()</strong> says that the Post is associated with one User. The first parameter is the <strong>Model name</strong> and the second parameter is an array that sets the <strong>foreign keys</strong>. </p>
<p>It links the two Models by the <strong>user_id</strong> field in the <strong>local</strong> Model (i.e. Post), with the <strong>id</strong> field in the <strong>foreign</strong> Model (i.e. User).</p>
<p>Now we can access the User object for a post like this: <strong>$post->User</strong>. We&#8217;ll see more of that later.</p>
<p><strong>User Example:</strong></p>
<pre class="brush: php; highlight: [9,10,11,12];">
class User extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('username', 'string', 255, array('unique' =&gt; 'true'));
		$this-&gt;hasColumn('password', 'string', 255);
	}

	public function setUp() {
		$this-&gt;hasMany('Post as Posts', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'user_id'
		));
	}
}
</pre>
<p>On this side of the relationship, there are no additional fields for the foreign key. But we still define it by the <strong>hasMany()</strong> call.</p>
<p>The first parameter looks a bit different this time. When we say <strong>Post as Posts</strong>, we link to the <strong>Model</strong> named Post, but we name the <strong>property</strong> Posts.</p>
<p>This way we are going to access it like <strong>$user->Posts</strong>, instead of <strong>$user->Post</strong>. This is just a matter of preference, because it sounds better.</p>
<p><strong>Note:</strong> As a rule of thumb, the Model that has the <strong>hasOne()</strong> call is the one with the foreign key field. (Post.user_id in this case).</p>
<h4>One to One Relationships</h4>
<p>This type of relationship is used when each Model is linked to only one instance of the other Model.</p>
<p>For example, if you have separate Models/Tables for <strong>User</strong> and <strong>Email</strong>, and if you want each User to have <strong>only one</strong> Email, you might use this.</p>
<p>The syntax is exactly the same as the <strong>One to Many</strong> Relationships, but this time <strong>both Models</strong> call the <strong>hasOne()</strong> function, instead of <strong>hasMany()</strong>.</p>
<h4>for more info</h4>
<p>This is all we needed to know to continue our project for now. But if you want to find out about all types of relationships in Doctrine, you can read the whole documentation section on this subject <a href="http://www.doctrine-project.org/documentation/manual/1_1/en/defining-models#relationships" rel="nofollow">here</a>.</p>
<h3>Let&#8217;s Create Some Models</h3>
<p>Let&#8217;s use what we just learned to create our new Models.</p>
<p><strong>Note:</strong> I would like to build this project similar to the <a href="http://codeigniter.com/forums/" rel="nofollow">CodeIgniter Message Board</a>. They also seem to have <strong>Categories</strong>, that contain multiple Forums, so we are going to create a Model for that too.</p>
<h4>Category Model</h4>
<ul>
<li>Create: <strong>system/application/models/category.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Category extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('title', 'string', 255);
	}

	public function setUp() {
		$this-&gt;hasMany('Forum as Forums', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'category_id'
		));
	}
}
</pre>
<p>Looks simple. We have a <strong>Category</strong> Model that has a title, and can have many <strong>Forums</strong>. Also we are expecting that the Forum Model to have a field named <strong>category_id</strong>.</p>
<h4>Forum Model</h4>
<ul>
<li>Create: <strong>system/application/models/forum.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Forum extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('title', 'string', 255);
		$this-&gt;hasColumn('description', 'string', 255);
		$this-&gt;hasColumn('category_id', 'integer', 4);
	}

	public function setUp() {
		$this-&gt;hasOne('Category', array(
			'local' =&gt; 'category_id',
			'foreign' =&gt; 'id'
		));
		$this-&gt;hasMany('Thread as Threads', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'forum_id'
		));
	}

}
</pre>
<p>As expected, we have a <strong>category_id</strong> field for the <strong>foreign key</strong>.</p>
<p>Also we have 2 relationships now. First one is with <strong>Category</strong> Model, as Forums have (or belong to) a single Category. The second one is with <strong>Thread</strong> Model. Each Forum can have many Threads.</p>
<h4>Thread Model</h4>
<ul>
<li>Create: <strong>system/application/models/thread.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Thread extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('title', 'string', 255);
		$this-&gt;hasColumn('forum_id', 'integer', 4);
	}

	public function setUp() {
		$this-&gt;hasOne('Forum', array(
			'local' =&gt; 'forum_id',
			'foreign' =&gt; 'id'
		));
		$this-&gt;hasMany('Post as Posts', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'thread_id'
		));
	}

}
</pre>
<h4>Post Model</h4>
<ul>
<li>Create: <strong>system/application/models/post.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Post extends Doctrine_Record {

	public function setTableDefinition() {
		$this-&gt;hasColumn('content', 'string', 65535);
		$this-&gt;hasColumn('thread_id', 'integer', 4);
		$this-&gt;hasColumn('user_id', 'integer', 4);
	}

	public function setUp() {
		$this-&gt;actAs('Timestampable');
		$this-&gt;hasOne('Thread', array(
			'local' =&gt; 'thread_id',
			'foreign' =&gt; 'id'
		));
		$this-&gt;hasOne('User', array(
			'local' =&gt; 'user_id',
			'foreign' =&gt; 'id'
		));
	}

}
</pre>
<p>Notice this time we have 2 foreign keys. Because a Post belongs to a <strong>Thread</strong>, and also belongs to a <strong>User</strong>.</p>
<h4>User Model</h4>
<p>We already have this Model, we are just making changes.</p>
<ul>
<li>Edit: <strong>system/application/models/user.php</strong></li>
</ul>
<pre class="brush: php; highlight: [11,12,13,14];">
&lt;?php
class User extends Doctrine_Record {

// ...

	public function setUp() {
		$this-&gt;setTableName('user');
		$this-&gt;actAs('Timestampable');
		$this-&gt;hasMutator('password', '_encrypt_password');

		$this-&gt;hasMany('Post as Posts', array(
			'local' =&gt; 'id',
			'foreign' =&gt; 'user_id'
		));
	}
//...
}
</pre>
<h4>Create the Tables</h4>
<p>Remember our Controller that creates Tables from Models? It&#8217;s time to use that again.</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/doctrine_tools/create_tables" rel="nofollow">http://localhost/ci_doctrine/doctrine_tools/create_tables</a></li>
<li>Press the button, and it should create the tables.</li>
<li>Look at phpmyadmin at: <a href="http://localhost/phpmyadmin" rel="nofollow">http://localhost/phpmyadmin</a>.</li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day6_2.png" alt="ci_doctrine_day6_2" title="ci_doctrine_day6_2" width="510" height="340" class="aligncenter size-full wp-image-510" /></p>
<p>Looks great! </p>
<p>Now let&#8217;s see how we can add some data using these Models.</p>
<h3>Creating Records</h3>
<p>We are going to write a quick test controller to demonstrate how we can <strong>add data</strong>.</p>
<ul>
<li>Create: <strong>system/application/controllers/test.php</strong></li>
</ul>
<pre class="brush: php; highlight: [14];">
&lt;?php
class Test extends Controller {

	function index() {

		$category = new Category();
		$category-&gt;title = &quot;The CodeIgniter Lounge&quot;;
		$category-&gt;save();

		$forum = new Forum();
		$forum-&gt;title = &quot;Introduce Yourself!&quot;;
		$forum-&gt;description = &quot;Use this forum to introduce yourself to the CodeIgniter community, or to announce your new CI powered site.&quot;;

		$forum-&gt;Category = $category;

		$forum-&gt;save();
	}

}
</pre>
<p>Do you see how intuitive it is?</p>
<p><strong>$forum->Category</strong> represents the relationship that the Forum object has with the Category Model. We can directly assign a Category object to it to link them.</p>
<p>Let&#8217;s expand this so we have a bit more data.</p>
<ul>
<li>Edit: <strong>system/application/controllers/test.php</strong></li>
</ul>
<pre class="brush: php; highlight: [13,21,36,37];">
&lt;?php
class Test extends Controller {

	function index() {

		$category = new Category();
		$category-&gt;title = &quot;The CodeIgniter Lounge&quot;;

		$forum = new Forum();
		$forum-&gt;title = &quot;Introduce Yourself!&quot;;
		$forum-&gt;description = &quot;Use this forum to introduce yourself to the CodeIgniter community, or to announce your new CI powered site.&quot;;
		// add category to the forum
		$forum-&gt;Category = $category;

		$forum2 = new Forum();
		$forum2-&gt;title = &quot;The Lounge&quot;;
		$forum2-&gt;description = &quot;CodeIgniter's social forum where you can discuss anything not related to development. No topics off limits... but be civil.&quot;;

		// you can also add the other way around
		// add forum to the category
		$category-&gt;Forums []= $forum2;

		// a different syntax (array style)

		$category2 = new Category();
		$category2['title'] = &quot;CodeIgniter Development Forums&quot;;

		$forum3 = new Forum();
		$forum3['title'] = &quot;CodeIgniter Discussion&quot;;
		$forum3['description'] = &quot;This forum is for general topics related to CodeIgniter&quot;;

		$forum4 = new Forum();
		$forum4['title'] = &quot;Code and Application Development&quot;;
		$forum4['description'] = &quot;Use the forum to discuss anything related to programming and code development.&quot;;

		$category2['Forums'] []= $forum3;
		$category2['Forums'] []= $forum4;

		// flush() saves all unsaved objects
		$conn = Doctrine_Manager::connection();
		$conn-&gt;flush();

		echo &quot;Success!&quot;;

	}

}
</pre>
<p>We just created 2 categories, and 2 forums in each of them, in a few different ways.</p>
<ul>
<li><strong>Line 21:</strong> We add a Forum to the Category, instead of the other way around. But this time, since <strong>$category->Forums</strong> contains multiple Forums, we push to it like you would to an array, instead of direct assignment like on line 13.</li>
<li><strong>Lines 25-37:</strong> Here you can see how we can access all elements of the Doctrine Model objects like <strong>array elements</strong>. Some people prefer this syntax.</li>
<li><strong>Lines 40-41:</strong> Instead of calling save() on every single object, we can just use <strong>flush()</strong> to save everything.</li>
</ul>
<p>Let&#8217;s test this.</p>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/test" rel="nofollow">http://localhost/ci_doctrine/test</a></li>
</ul>
<p>You should see the success message:</p>
<pre>
Success!
</pre>
<p>Now let&#8217;s look at the <strong>category table</strong>:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day6_3.png" alt="ci_doctrine_day6_3" title="ci_doctrine_day6_3" width="339" height="76" class="aligncenter size-full wp-image-516" /></p>
<p>You can see our new 2 categories, with id&#8217;s 1 and 2. Let&#8217;s see if the forums got the correct associations.</p>
<p>Look at the <strong>forum table</strong>:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day6_4.png" alt="ci_doctrine_day6_4" title="ci_doctrine_day6_4" width="600" height="96" class="aligncenter size-full wp-image-517" /></p>
<p>Everything looks good! The Forums each have proper category_id&#8217;s assigned.</p>
<h3>Stay Tuned</h3>
<p>Today we learned about one of main features of Doctrine. We were able to create foreign key relationships without using any queries whatsoever! That is one of the nice things about using an ORM like Doctrine. I hope you are able to see how much time you can save by developing like this.</p>
<p>In the next episode we will continue on our project, with a little more CodeIgniter stuff.</p>
<p>See you next time!</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/8aEaL1B3SKc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships/feed</wfw:commentRss>
		<slash:comments>45</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch Day 5 – Database CRUD</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/CKAZMry6OrI/codeigniter-doctrine-day-5-database-crud</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud#comments</comments>
		<pubDate>Mon, 09 Nov 2009 14:00:09 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=481</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> <strong>CRUD</strong> stands for <strong>Create, Read, Update and Delete</strong>, the basic operations performed on the database. With regular <strong>CodeIgniter</strong> setups, most developers would use the <strong>Active Record Class</strong> for performing such operations. But we are not going to be doing that.

In this episode of the series, I will show you how to perform <strong>CRUD with Doctrine</strong>.
]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-day-5-database-crud"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-day-5-database-crud" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" /> <strong>CRUD</strong> stands for <strong>Create, Read, Update and Delete</strong>, the basic operations performed on the database. With regular <strong>CodeIgniter</strong> setups, most developers would use the <strong>Active Record Class</strong> for performing such operations. But we are not going to be doing that.</p>
<p>In this episode of the series, I will show you how to perform <strong>CRUD with Doctrine</strong>.</p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p>In <strong>Doctrine</strong>, there can be multiple ways of accomplishing the same task. This gives you flexibility to pick the best approach suitable for each situation. Therefore we shall explore these different methods for each part of the <strong>CRUD</strong>.</p>
<h3>1. CREATE</h3>
<p>The act of inserting new data/records into the database:</p>
<h4>Record Object</h4>
<p>This is the way we have been creating our user records in the previous tutorials. It&#8217;s pretty simple:</p>
<pre class="brush: php;">
$u = new User();

$u-&gt;username = 'myuser';
$u-&gt;password = 'mypass';

$u-&gt;save();
</pre>
<p>When the <strong>save()</strong> method is called, the new record is created.</p>
<h4>fromArray()</h4>
<p>Sometimes you have all the data already in an array. Instead of assigning every value to the record object separately, you can simply use the <strong>fromArray()</strong> method.</p>
<pre class="brush: php;">
$data = array(
	'username' =&gt; 'myuser',
	'password' =&gt; 'mypass',
	'email' =&gt; 'my@email.com'
);

$u = new User();

$u-&gt;fromArray($data);

$u-&gt;save();
</pre>
<h4>flush()</h4>
<p>When you call the <strong>flush()</strong> method on the <strong>Doctrine_Connection</strong> object, all unsaved record objects automatically get saved. And Doctrine performs this in a single <strong>transaction</strong>.</p>
<pre class="brush: php;">
$u = new User();
$u-&gt;username = 'myuser';
$u-&gt;password = 'mypass';

$u2 = new User();
$u2-&gt;username = 'foouser';
$u2-&gt;password = 'foopass';

$conn = Doctrine_Manager::connection();

$conn-&gt;flush();
</pre>
<p>This way you don&#8217;t need to call the save() method for each object.</p>
<h4>Raw SQL</h4>
<p>We can just give a plain SQL query to the <strong>Doctrine_Connection</strong> object and call the <strong>execute()</strong> method.</p>
<p>This also supports binding of values to the query (with the usage of &#8216;?&#8217;), which automatically filters against SQL injection.</p>
<pre class="brush: php;">
$data = array('myuser','mypass');

$conn = Doctrine_Manager::connection();

$conn-&gt;execute('INSERT INTO user (username, password) VALUES (?,?)',  $data);
</pre>
<h3>2. READ</h3>
<p>The act of fetching records from the database.</p>
<p>Most of these are performed on <strong>Doctrine_Table</strong> objects, which is obtained by calling <strong>Doctrine::getTable()</strong> and passing the model class name to it.</p>
<h4>find()</h4>
<p>The <strong>find()</strong> method fetches a record by the <strong>Primary Key</strong> value.</p>
<pre class="brush: php;">
$user_id = 1;

$u = Doctrine::getTable('User')-&gt;find($user_id);

echo $u-&gt;username;
</pre>
<h4>findOneBy*()</h4>
<p>This is a <strong>magic</strong> method. You can simply append the column name, and it will search the table by that column.</p>
<p>For example, to find a user record by username:</p>
<pre class="brush: php;">
$username = 'myuser';

$u = Doctrine::getTable('User')-&gt;findOneByUsername($username);

echo $u-&gt;username;
</pre>
<p>It fetches only one record.</p>
<h4>findBy*()</h4>
<p>Another <strong>magic</strong> method, which works similarly, but fetches multiple rows. It returns a <strong>Doctrine_Collection</strong> object.</p>
<p>You can treat this returned object just like an <strong>array</strong>, to get to the individual record.</p>
<p>(let&#8217;s assume we have a column named &#8217;status&#8217;):</p>
<pre class="brush: php;">
$users = Doctrine::getTable('User')-&gt;findByStatus('active');

echo $users[0]-&gt;username;
echo $users[1]-&gt;username;
</pre>
<p>Even if the actual column name is all lowercase, it can be used as capitalized in that magic function call (status vs. Status).</p>
<h4>DQL</h4>
<p>This is our first look at <strong>DQL</strong> in these tutorials. It stands for <strong>Doctrine Query Language</strong>. It is actually a major feature. Most advanced queries are performed using DQL.</p>
<p>In this example, we first create the query object, and add the components of the query to it. All the method calls can be <strong>chained</strong> nicely. Finally we execute the query, which returns us a <strong>Doctrine_Collection</strong> object, like that last example.</p>
<pre class="brush: php;">
$status = 'active';

$q = Doctrine_Query::create()
	-&gt;select('username')
	-&gt;from('User')
	-&gt;where('status = ?', $status)
	-&gt;limit(20);

$users = $q-&gt;execute();

echo $users[0]-&gt;username;
echo $users[1]-&gt;username;
</pre>
<p>We will see many more examples of DQL in our project. But if you want more info right now, there is a long documentation chapter <a href="http://www.doctrine-project.org/documentation/manual/1_1/en/dql-doctrine-query-language" rel="nofollow">here</a>.</p>
<h4>toArray()</h4>
<p>A <strong>Doctrine_Record</strong> object contains a lot of stuff behind the scenes. If you ever try to print_r() that object directly, you will see a long list of data.</p>
<p>However, when you simply want the data of the record, you can convert it to an array with the <strong>toArray()</strong> call.</p>
<pre class="brush: php;">
$user_id = 1;

$u = Doctrine::getTable('User')-&gt;find($user_id);

$u_arr = $u-&gt;toArray();

print_r($u_arr);
</pre>
<p>What you get will be similar to what you get from a <strong>mysql_fetch_assoc()</strong> call.</p>
<h3>3. UPDATE</h3>
<p>The act of updating existing records.</p>
<h4>Record Object</h4>
<p>You can make direct changes to any Doctrine_Record object. Once you call save(), it will perform an UPDATE.</p>
<pre class="brush: php;">
$user_id = 1;

$u = Doctrine::getTable('User')-&gt;find($user_id);

$u-&gt;password = 'newpassword';

$u-&gt;save();
</pre>
<h4>DQL</h4>
<p>When you want to update multiple rows at once, the preferred way is to use <strong>DQL</strong>.</p>
<pre class="brush: php;">
$status = 'active';

$q = Doctrine_Query::create()
	-&gt;update('User')
	-&gt;set('status', '?', $status)
	-&gt;where('id &lt; 10');

$numrows = $q-&gt;execute();
echo &quot;$numrows records updated&quot;;
</pre>
<p>The <strong>execute()</strong> call in this case returns the number of updated rows.</p>
<h3>4. DELETE</h3>
<p>The act of deleting records from the database.</p>
<h4>Record Object</h4>
<p>You can simply call the <strong>delete()</strong> method to delete a Doctrine_Record object directly.</p>
<pre class="brush: php;">
$user_id = 1;

$u = Doctrine::getTable('User')-&gt;find($user_id);

$u-&gt;delete();
</pre>
<h4>DQL</h4>
<p>When deleting multiple records, use DQL.</p>
<pre class="brush: php;">
$q = Doctrine_Query::create()
	-&gt;delete('User')
	-&gt;where('id &lt; 10');

$numrows = $q-&gt;execute();
echo &quot;$numrows records deleted&quot;;
</pre>
<p>The <strong>execute()</strong> method call will return the number of deleted records.</p>
<h3>Stay Tuned</h3>
<p>Today, we took a short break from coding our project and explored some important subjects regarding the usage of <strong>CRUD with Doctrine</strong>. What we learned today will be very useful as we continue building our project in the next tutorials. </p>
<p>See you next time!</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/CKAZMry6OrI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud/feed</wfw:commentRss>
		<slash:comments>23</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud</feedburner:origLink></item>
		<item>
		<title>Top 10 Reasons Why You Should Use a PHP Framework</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/M0ue6-P3H5w/top-10-reasons-why-you-should-use-a-php-framework</link>
		<comments>http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework#comments</comments>
		<pubDate>Sat, 07 Nov 2009 01:45:44 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=452</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/frameworks.png" alt="frameworks" title="frameworks" width="128" height="128" class="alignleft size-full wp-image-470" /> 

<strong>PHP Frameworks</strong> have been receiving a lot of attention in the past few years from the web development community. What's this hype all about?

If you look at PHP Job listings, you will often see "MVC Framework Experience" as one of their requirements. It is becoming one of those must-have skill sets for web developers.

There are pretty good reasons behind all of this. In this article we will explore why you, as a PHP programmer, should be using a <strong>PHP Framework</strong>.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Ftop-10-reasons-why-you-should-use-a-php-framework"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Ftop-10-reasons-why-you-should-use-a-php-framework" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/frameworks.png" alt="frameworks" title="frameworks" width="128" height="128" class="alignleft size-full wp-image-470" /> </p>
<p><strong>PHP Frameworks</strong> have been receiving a lot of attention in the past few years from the web development community. What&#8217;s this hype all about?</p>
<p>If you look at PHP Job listings, you will often see &#8220;MVC Framework Experience&#8221; as one of their requirements. It is becoming one of those must-have skill sets for web developers.</p>
<p>There are pretty good reasons behind all of this. In this article we will explore why you, as a PHP programmer, should be using a <strong>PHP Framework</strong>.</p>
<div class="clear"></div>
<h3>1. Code and File Organization</h3>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/php_frameworks_reasons_1.png" alt="php_frameworks_reasons_1" title="php_frameworks_reasons_1" width="282" height="307" class="alignright size-full wp-image-456" /></p>
<p>Just because you created an &#8220;/inc&#8221; folder and made a &#8220;functions.php&#8221; file does not mean your code is organized. </p>
<p>When you setup a <strong>PHP Framework</strong>, it already has a certain folder structure. It is expected from you to follow the same standards and keep everything organized in a certain way.</p>
<p>Once you get used to this model, you will never want to go back. </p>
<p>Unfortunately for some command line champions that still use vi, this can be a challenge. You will need to work with more files, that are smaller in size. But when you use a decent modern <strong>code editor</strong> or an <strong>IDE</strong>, it will be a breeze to browse through your application code and find what you need, quickly.</p>
<div class="clear"></div>
<h3>2. Utilities and Libraries</h3>
<p><strong>PHP</strong> is a great language for web development and provides countless number of tools and libraries.</p>
<p>However, if you ever try to build a whole website with PHP alone, you will find yourself either hunting down a lot of 3rd party code and libraries, or have to write them yourself.</p>
<p>All top PHP frameworks come with certain <strong>Libraries</strong> and <strong>Helpers</strong>, that help you with:</p>
<ul>
<li>Form Validation</li>
<li>Input/Output filtering</li>
<li>Database Abstraction</li>
<li>Session and Cookie Handling</li>
<li>Email, Calendar, Pagination etc&#8230;</li>
</ul>
<p>The list goes on. Not to mention, there is plenty of <strong>plugins</strong> provided by the community that you can add to your framework.</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/appflowchart.gif" alt="appflowchart" title="appflowchart" width="697" height="205" class="aligncenter size-full wp-image-466" /></p>
<h3>3. The MVC Pattern</h3>
<p>The famous <strong>Model View Controller Pattern</strong> dates all the way back to 1979, when a guy named <strong>Trygve Reenskaug</strong> (a Norwegian computer scientist) first described it.</p>
<p>PHP itself works like a template engine. However, when used irresponsibly, it leads to very ugly and unmaintainable code.</p>
<p>The way the <strong>MVC Pattern</strong> applies to PHP applications:</p>
<ul>
<li><strong>Models</strong> represent your data structures, usually by interfacing with the database.</li>
<li><strong>Views</strong> contain page templates and output.</li>
<li><strong>Controllers</strong> handle page requests and bind everything together.</li>
</ul>
<p>This kind of separation leads to cleaner and more maintainable code.</p>
<h3>4. Security</h3>
<p>In PHP you can already find many input and output filtering functions to protect your website against certain attacks.</p>
<p>However, manually using these functions can get tiring and you may forget about them every once in a while.</p>
<p>With a framework, most of the work can be done for you automatically. For example in CodeIgniter:</p>
<ul>
<li>Any value passed to database object gets filtered against SQL injection attacks.</li>
<li>All html generating functions, such as form helpers and url helpers filter the output automatically.</li>
<li>All user input can be filtered against XSS attacks.</li>
<li>Encrypting cookies automatically is only a matter of changing a config option.</li>
</ul>
<h3>5. Less Code &#038; Faster Development</h3>
<p>There is of course a learning curve for all PHP Frameworks. But once you get over this hump, you will enjoy the benefits of <strong>rapid application development</strong>.</p>
<p>You will write less code, which means less time spent typing. You will not have to chase down 3rd party libraries all the time for every new project because most of them will come with the default framework install.</p>
<p>Also, since you are being more organized, it will be much faster to chase down bugs, maintain code, and make changes to existing code.</p>
<h3>6. Community Support</h3>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/php_frameworks_reasons_2.png" alt="php_frameworks_reasons_2" title="php_frameworks_reasons_2" width="600" height="154" class="aligncenter size-full wp-image-463" /></p>
<p>All popular PHP Frameworks have great active <strong>communities</strong> behind them. You can talk to other developers, get help, feedback and also give back to the community yourself.</p>
<p>There are message boards and mailing lists&#8230; You can also learn a lot by just browsing the forums and look at what other people are talking about.</p>
<h3>7. Job Opportunities</h3>
<p>Have you looked at any PHP Job postings lately? Most of them require experience with either Frameworks or a CMS. Follow the demand!</p>
<p>Example from Careerbuilder.com:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/php_frameworks_reasons_3.png" alt="php_frameworks_reasons_3" title="php_frameworks_reasons_3" width="508" height="106" class="aligncenter size-full wp-image-465" /></p>
<p>Experience with PHP Frameworks greatly increases your job qualifications as a web developer.</p>
<h3>8. Performance Tools</h3>
<p>One of the main arguments from the naysayers comes in this subject. There is obviously a performance hit when you build a &#8220;Hello World&#8221; application with a framework vs. plain PHP code.</p>
<p>But those benchmarks are just bad examples. First of all, you should understand that <strong>developers are more expensive than servers</strong>. Saving time from development and maintenance is likely to outweigh any extra money you need to spend on servers.</p>
<p>Putting all of that aside, you can actually gain performance <strong>benefits</strong> by using a PHP framework. They come with tools that help you do <strong>caching</strong>, <strong>benchmarks</strong>, <strong>profiling</strong> etc&#8230;</p>
<p>Modern frameworks are also great with <strong>dynamic loading</strong>, as they load code only as needed. Different page requests can load different amount of library code based on what needs to be used.</p>
<h3>9. Suitable for Teamwork</h3>
<p>The way your project is organized in a PHP Framework also helps you create a suitable environment for teamwork.</p>
<p>You can let your designers work on the <strong>Views</strong>, database guru work on the <strong>Models</strong>, let the smart programmer (yourself <img src='http://www.phpandstuff.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) build reusable Libraries and Plugins etc&#8230; </p>
<p>Also you can let someone build <strong>unit tests</strong>, because they come with tools for that too.</p>
<h3>10. And It&#8217;s Fun!</h3>
<p>This might actually be most important point of all. When you have fun doing your work, you will be more productive and happier in general.</p>
<p>If you have been coding plain old PHP for years, and getting really bored with it, getting started with a Framework can give you that crucial morale boost you have been lacking.</p>
<p>It&#8217;s like getting a new toy, and being able to build cool things with it. At least that&#8217;s how I felt when I first got started with Frameworks. I&#8217;m sure many of the web developers have gone through similar experiences.</p>
<h3>Conclusion</h3>
<p>Using a <strong>PHP Framework</strong> may or may not be the best choice for you. However, you should always keep an open mind and keep up to date with all the new developments in the web development world.</p>
<p>Frameworks are cool and hot today, and we can&#8217;t tell what tomorrow is going to bring. I guess all I&#8217;m saying is that they are definitely worth looking into.</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/M0ue6-P3H5w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework</feedburner:origLink></item>
		<item>
		<title>CodeIgniter and Doctrine from scratch Day 4 – User Login</title>
		<link>http://feedproxy.google.com/~r/PhpAndStuff/~3/85tshf1Ug60/codeigniter-doctrine-scratch-day-4-user-login</link>
		<comments>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login#comments</comments>
		<pubDate>Fri, 06 Nov 2009 07:16:30 +0000</pubDate>
		<dc:creator>Burak</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpandstuff.com/?p=418</guid>
		<description><![CDATA[<img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" />In this episode we are going to build a <strong>User Signup Form</strong> following these steps:

- We build a <strong>Login Form View</strong> and a <strong>Login Controller</strong>.
- Learn about some <strong>URL Helpers</strong>.
- Change the <strong>Default Controller</strong>.
- Implement <strong>User Authentication</strong>.
- Learn about <strong>Singleton Pattern</strong> and use it to improve our code design.
- Learn about the <strong>Sessions Library</strong>. 
- Implement <strong>User Logout</strong>.

<img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_1.png" alt="ci_doctrine_day4_1" title="ci_doctrine_day4_1" width="434" height="421" class="aligncenter size-full wp-image-423" />]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-4-user-login"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.phpandstuff.com%2Farticles%2Fcodeigniter-doctrine-scratch-day-4-user-login" height="61" width="51" /></a></div><p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/codeigniter_doctrine.png" alt="Codeigniter Doctrine" title="Codeigniter Doctrine" width="128" height="128" class="alignleft size-full wp-image-140" />In this episode we are going to build a <strong>User Login</strong> system following these steps:</p>
<p>- We will build a <strong>Login Form View</strong> and a <strong>Login Controller</strong>.<br />
- Learn about some <strong>URL Helpers</strong>.<br />
- Change the <strong>Default Controller</strong>.<br />
- Implement <strong>User Authentication</strong>.<br />
- Learn about <strong>Singleton Pattern</strong> and use it to improve our code design.<br />
- Learn about the <strong>Sessions Library</strong>.<br />
- Implement <strong>User Logout</strong>.</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_1.png" alt="ci_doctrine_day4_1" title="ci_doctrine_day4_1" width="434" height="421" class="aligncenter size-full wp-image-423" /></p>
<div class="clear"></div>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<p><a href="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4.zip"><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/download_code.png" alt="download_code" title="download_code" width="240" height="80" class="aligncenter size-full wp-image-249" /></a></p>
<h3>Login Form View</h3>
<p>First thing we are going to do is to create the <strong>View</strong> for the <strong>Login Form</strong>.</p>
<p>We are going to make this one very similar to the <strong>Signup Form</strong> we created in the <a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">last article</a>.</p>
<ul>
<li>Create: <strong>system/application/views/login_form.php</strong></li>
</ul>
<pre class="brush: php; highlight: [33]; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Login Form&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div id=&quot;signup_form&quot;&gt;

	&lt;p class=&quot;heading&quot;&gt;User Login&lt;/p&gt;

	&lt;?php echo form_open('login/submit'); ?&gt;

	&lt;?php echo validation_errors('&lt;p class=&quot;error&quot;&gt;','&lt;/p&gt;'); ?&gt;

	&lt;p&gt;
		&lt;label for=&quot;username&quot;&gt;Username: &lt;/label&gt;
		&lt;?php echo form_input('username',set_value('username')); ?&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for=&quot;password&quot;&gt;Password: &lt;/label&gt;
		&lt;?php echo form_password('password'); ?&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;?php echo form_submit('submit','Login'); ?&gt;
	&lt;/p&gt;

	&lt;?php echo form_close(); ?&gt;
	&lt;p&gt;
		&lt;?php echo anchor('signup','Create an Account'); ?&gt;
	&lt;/p&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>All I did was copy the contents of the signup form, change the page title, remove some form fields and added a link at the bottom to the signup form.</p>
<h4>anchor()</h4>
<p>On <strong>Line 33</strong> in the file above, I used a function named <strong>anchor()</strong>. This is part of the <strong>URL Helper</strong> in CodeIgniter. It helps us create links with ease. The first argument is the <strong>Controller Name</strong>, and the second argument is the <strong>Link Text</strong>. You can also pass an optional third argument for extra html attributes. The result is:</p>
<pre class="brush: xml;">
&lt;a href=&quot;http://localhost/ci_doctrine/signup&quot;&gt;Create an Account&lt;/a&gt;
</pre>
<h4>Style the links</h4>
<p>I am just going to make a small addition to the <strong>stylesheet</strong> so our links look better.</p>
<ul>
<li>Edit: css/style.css</li>
</ul>
<pre class="brush: css; highlight: [8,9,10,11,12,13,14];">
body {
	font-family: &quot;Trebuchet MS&quot;,Arial;
	font-size: 14px;
	background-color: #212426;
	color: #11151E;
}

a {
	color: #FFF;
}

a:hover {
	color: #B9AA81;
}

/* ... */
</pre>
<p>I only added the highlighted lines.</p>
<h4>Link from the Signup Form</h4>
<p>Likewise, we will add a link from the <strong>Signup Form</strong> to the new <strong>Login Form</strong>.</p>
<ul>
<li>Edit: <strong>system/application/views/signup_form.php</strong></li>
</ul>
<pre class="brush: php; highlight: [39,40,41]; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Signup Form&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div id=&quot;signup_form&quot;&gt;

	&lt;p class=&quot;heading&quot;&gt;New User Signup&lt;/p&gt;

	&lt;?php echo form_open('signup/submit'); ?&gt;

	&lt;?php echo validation_errors('&lt;p class=&quot;error&quot;&gt;','&lt;/p&gt;'); ?&gt;

	&lt;p&gt;
		&lt;label for=&quot;username&quot;&gt;Username: &lt;/label&gt;
		&lt;?php echo form_input('username',set_value('username')); ?&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for=&quot;password&quot;&gt;Password: &lt;/label&gt;
		&lt;?php echo form_password('password'); ?&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for=&quot;passconf&quot;&gt;Confirm Password: &lt;/label&gt;
		&lt;?php echo form_password('passconf'); ?&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for=&quot;email&quot;&gt;E-mail: &lt;/label&gt;
		&lt;?php echo form_input('email',set_value('email')); ?&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;?php echo form_submit('submit','Create my account'); ?&gt;
	&lt;/p&gt;
	&lt;?php echo form_close(); ?&gt;
	&lt;p&gt;
		&lt;?php echo anchor('login','Login Form'); ?&gt;
	&lt;/p&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>I only added the highlighted lines.</p>
<p><strong>Note:</strong> We just linked to a <strong>Controller</strong> named <strong>login</strong>. This Controller does not exist yet. So let&#8217;s create it.</p>
<h3>Login Controller</h3>
<p>First we are going create a sort of skeleton structure for our new Controller.</p>
<ul>
<li>Create: <strong>system/application/controllers/login.php</strong></li>
</ul>
<pre class="brush: php; highlight: [22];">
&lt;?php
class Login extends Controller {

	public function __construct() {
		parent::Controller();

		$this-&gt;load-&gt;helper(array('form','url'));
		$this-&gt;load-&gt;library('form_validation');
	}

	public function index() {
		$this-&gt;load-&gt;view('login_form');
	}

	public function submit() {

		if ($this-&gt;_submit_validate() === FALSE) {
			$this-&gt;index();
			return;
		}

		redirect('/');

	}

	private function _submit_validate() {

	}

}
</pre>
<p>This looks very similar to the <strong>submit Controller</strong> we created in the last article. The only new thing is the highlighted line.</p>
<h4>redirect()</h4>
<p>This function is part of the <strong>URL Helper</strong>. It forwards the surfer to a specified Controller. In this case we only passed <strong>&#8216;/&#8217;</strong>, which will basically send the surfer to the <strong>Home Page</strong> or in other words the <strong>Default Controller</strong>.</p>
<p>So the user will end up at <strong>http://localhost/ci_doctrine/</strong>.</p>
<h4>Test The Login Controller+View</h4>
<ul>
<li>Go here: <a href="http://localhost/ci_doctrine/login" rel="nofollow">http://localhost/ci_doctrine/login</a></li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_41.png" alt="ci_doctrine_day4_4" title="ci_doctrine_day4_4" width="423" height="378" class="aligncenter size-full wp-image-437" /></p>
<ul>
<li>Now click the link that says <strong>Create an Account</strong>.</li>
</ul>
<p>You should see our old <strong>Signup Form</strong> page.</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_3.png" alt="ci_doctrine_day3_3" title="ci_doctrine_day3_3" width="484" height="501" class="aligncenter size-full wp-image-390" /></p>
<p>Works great!</p>
<h3>Default Controller</h3>
<p>When someone visits the main page of our website (i.e. there is no controller name in the url), it calls the <strong>Default Controller</strong>. Right now if you go to <strong>http://localhost/ci_doctrine/</strong>, you will see this:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/10/ci_doctrine_day1_3.png" alt="ci_doctrine_day1_3" title="ci_doctrine_day1_3" width="500" height="276" class="aligncenter size-full wp-image-184" /></p>
<p>Because CodeIgniter is loading a Controller named <strong>welcome</strong> by default.</p>
<p>Let&#8217;s say we would like to have a Default Controller named <strong>home</strong> instead.</p>
<ul>
<li>Create: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Home extends Controller {

	public function index() {
		echo &quot;Home Sweet Home!&quot;;
	}	

}
</pre>
<h4>Routes File</h4>
<ul>
<li>Edit: <strong>system/application/config/routes.php</strong></li>
</ul>
<p>Changing just one line:</p>
<pre class="brush: php; highlight: [2];">
// ...
$route['default_controller'] = &quot;home&quot;;
$route['scaffolding_trigger'] = &quot;&quot;;
// ...
</pre>
<p>That&#8217;s it. Now when you go to <a href="http://localhost/ci_doctrine/" ref="nofollow">http://localhost/ci_doctrine/</a>, you will see our controller:</p>
<pre>
Home Sweet Home!
</pre>
<p>The Routes File has some other purposes, which we will not get into right now. But you can read more about it <a rel="nofollow" href="http://codeigniter.com/user_guide/general/routing.html">here</a>.</p>
<h3>User Login (Authentication)</h3>
<p>Now that our forms are in place, we need to add authentication functionality to our application.</p>
<p>First I want to show you how to accomplish it in a simple and most common way. Once we cover that, I will show you a better way of handling this.</p>
<h4>Authentication with Form Validation</h4>
<ul>
<li>Edit: <strong>system/application/controllers/login.php</strong></li>
</ul>
<pre class="brush: php; highlight: [26,40];">
&lt;?php
class Login extends Controller {

	public function __construct() {
		parent::Controller();

		$this-&gt;load-&gt;helper(array('form','url'));
		$this-&gt;load-&gt;library('form_validation');
	}

	public function index() {
		$this-&gt;load-&gt;view('login_form');
	}

	public function submit() {

		if ($this-&gt;_submit_validate() === FALSE) {
			$this-&gt;index();
			return;
		}

		redirect('/');

	}

	private function _submit_validate() {

		$this-&gt;form_validation-&gt;set_rules('username', 'Username',
			'trim|required|callback_authenticate');

		$this-&gt;form_validation-&gt;set_rules('password', 'Password',
			'trim|required');

		$this-&gt;form_validation-&gt;set_message('authenticate','Invalid login. Please try again.');

		return $this-&gt;form_validation-&gt;run();

	}

	public function authenticate() {

		// get User object by username
		if ($u = Doctrine::getTable('User')-&gt;findOneByUsername($this-&gt;input-&gt;post('username'))) {

			// this mutates (encrypts) the input password
			$u_input = new User();
			$u_input-&gt;password = $this-&gt;input-&gt;post('password');

			// password match (comparing encrypted passwords)
			if ($u-&gt;password == $u_input-&gt;password) {
				unset($u_input);
				return TRUE;
			}
			unset($u_input);
		}

		return FALSE;
	}
}
</pre>
<p>Highlighted functions have been updated.</p>
<p>First I added some form validation rules inside the <strong>_submit_validate()</strong> function, like in the last article. But this time I added a <strong>Callback</strong> rule. Notice on Line 29: <strong>callback_authenticate</strong>. The format is <strong>callback_[function_name]</strong>.</p>
<p>On <strong>Line 34</strong> I set a custom message for this validation rule, in case it fails.</p>
<p>Then I added the function named <strong>authenticate</strong>. This callback function needs to return TRUE when everything is good, and FALSE when the validation fails.</p>
<p><strong>Lines 43-53:</strong> This is where I perform the username and password check for the login. First I attempt to get the <strong>User Record</strong> searching by the input <strong>username</strong>. (We learned about the getTable and findOneBy* functions in the last article).</p>
<h4>Applying the Mutator to an external value</h4>
<p>Remember we added a <strong>Mutator</strong> to the password field in the last article?</p>
<p>Since the stored passwords are encrypted, I need to apply the same encryption to the user input, before I can compare the two.</p>
<p>That&#8217;s why I create a new User object named <strong>$u_input</strong>. on <strong>Line 46</strong> and assigned the input password to it. This is how I trigger the <strong>Mutator</strong> function on the password that was entered in the form. (If anyone knows a better of doing this, let me know!)</p>
<p>Now the encrypted version of the input password resides in <strong>$u_input->password</strong>. So I was able to compare it to <strong>$u->password</strong>.</p>
<p>I also <strong>unset</strong> the $u_input object, just to make sure it doesn&#8217;t get saved as a new record by accident.</p>
<h4>Testing the Form</h4>
<p>First create a new user by going to the <strong>Signup Form</strong> at <a href="http://localhost/ci_doctrine/signup" rel="nofollow">http://localhost/ci_doctrine/signup</a>.</p>
<p>Now go to: <a href="http://localhost/ci_doctrine/login" rel="nofollow">http://localhost/ci_doctrine/login</a> and use a <strong>wrong</strong> login. You should see:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_1.png" alt="ci_doctrine_day4_1" title="ci_doctrine_day4_1" width="434" height="421" class="aligncenter size-full wp-image-423" /></p>
<p>When you use a <strong>correct</strong> login, you should get forwarded back to the <strong>home</strong> page.</p>
<pre>
Home Sweet Home!
</pre>
<p>Our Login Form works!</p>
<h3>Now the Better Way!</h3>
<p>I mentioned I was going to change things a bit and show you how to do this in a better way.</p>
<h4>What&#8217;s wrong with the current method?</h4>
<ol>
<li>I don&#8217;t like how the authentication code is all inside the <strong>Controller</strong>. This is not good for code reusability.</li>
<li>It should be part of the <strong>User Model</strong>, since it&#8217;s directly related to it.</li>
<li>We stored the <strong>User Record</strong> in a variable named <strong>$u</strong>. But it&#8217;s inside a function and not <strong>global</strong>. So, if other Controllers need to use it, they can&#8217;t.</li>
<li>Turning the object <strong>$u</strong> directly into a <strong>Global Variable</strong> would be a bad design decision.</li>
<li>We do not want to store the whole user object inside the <strong>session</strong>. Doctrine Models have a lot of internal data, which could quickly inflate the size of our session storage. Only thing we are going store in the session is the <strong>user_id</strong>.</li>
</ol>
<h4>Singleton Pattern to the rescue!</h4>
<p>Some of you may not know what <strong>Singleton Pattern</strong> means. It&#8217;s one of the most popular <strong>design patterns</strong>, and I will show you how we are going to use it.</p>
<p>With this new class I am going to create, we will have a better design for our authentication functionality, and we will also make the User Model instance for the logged in user globally available in our application.</p>
<h3>Singleton Pattern for Current User</h3>
<p>First let&#8217;s build the skeleton:</p>
<ul>
<li>Create: <strong>system/application/models/current_user.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Current_User {

	private static $user;

	private function __construct() {}

	public static function user() {

		if(!isset(self::$user)) {

			// put the User record into $this-&gt;user
			// ...

		}

		return self::$user;
	}

	public function __clone() {
		trigger_error('Clone is not allowed.', E_USER_ERROR);
	}

}
</pre>
<p>Now let&#8217;s go over the code:</p>
<ul>
<li>There is a reason I called the class <strong>Current_User</strong>. Because this <strong>static</strong> class will always return an instance of the <strong>User</strong> class, for the <strong>current logged in user</strong>.</li>
<li>This class does NOT extend <strong>Doctrine_Record</strong>, because we are not really creating a Doctrine Model.</li>
<li>The <strong>$user</strong> variable will contain the User object for the logged in user. And we will access it by <strong>Current_User::user()</strong>. That is the syntax for calling a <strong>static</strong> class function.</li>
<li>We will never create an instance of this Current_User class, so the <strong>constructor</strong> is set to <strong>private</strong>.</li>
<li>We also disallow <strong>cloning</strong> of this class so the <strong>__clone()</strong> function triggers an error.</li>
</ul>
<p>Now I&#8217;m going to add a bit more code to make this functional.</p>
<ul>
<li>Edit: <strong>system/application/models/current_user.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Current_User {

	private static $user;

	private function __construct() {}

	public static function user() {

		if(!isset(self::$user)) {

			$CI =&amp; get_instance();
			$CI-&gt;load-&gt;library('session');

			if (!$user_id = $CI-&gt;session-&gt;userdata('user_id')) {
				return FALSE;
			}

			if (!$u = Doctrine::getTable('User')-&gt;find($user_id)) {
				return FALSE;
			}

			self::$user = $u;
		}

		return self::$user;
	}

	public static function login($username, $password) {

		// get User object by username
		if ($u = Doctrine::getTable('User')-&gt;findOneByUsername($username)) {

			// this mutates (encrypts) the input password
			$u_input = new User();
			$u_input-&gt;password = $password;

			// password match (comparing encrypted passwords)
			if ($u-&gt;password == $u_input-&gt;password) {
				unset($u_input);

				$CI =&amp; get_instance();
				$CI-&gt;load-&gt;library('session');
				$CI-&gt;session-&gt;set_userdata('user_id',$u-&gt;id);
				self::$user = $u;

				return TRUE;
			}

			unset($u_input);
		}

		// login failed
		return FALSE;

	}

	public function __clone() {
		trigger_error('Clone is not allowed.', E_USER_ERROR);
	}

}
</pre>
<p>Let&#8217;s go over the code in <strong>user()</strong> method first:</p>
<ul>
<li>The usage for this function is: Current_User::user() and it returns the User object for the logged in user.</li>
<li><strong>Line 10</strong>: We check to see if the user object is already there. If it is, we return it at line 26 . </li>
<li><strong>Lines 12-17</strong>: We load the session library, so we can read/write in the session. If the user is logged in, his id should be stored there. If we don&#8217;t see the <strong>user_id</strong>, it returns FALSE.</li>
<li>We had to use the <strong>$CI</strong> object to load the session library because this is a static class.</li>
<li><strong>Lines 19-21</strong>: Fetch the User object by id. If we can&#8217;t, return FALSE. Note that we used a function named <strong>find()</strong> to look up by id.</li>
<li><strong>Lines 23 and 26</strong>: Everything went well, so we store the user object in the static variable <strong>$user</strong> and return it.</li>
</ul>
<p>Now, when we call <strong>Current_User::user()</strong> , we can get the User object as if it&#8217;s a <strong>global variable</strong>. And if it returns false, it means the user is NOT logged in.</p>
<p>Let&#8217;s go over the <strong>login()</strong> method:</p>
<ul>
<li>I copied most of the code from the <strong>login</strong> Controller we created earlier. The code is from the <strong>authenticate()</strong> method.</li>
<li>I added loading of the <strong>session library</strong> at <strong>line 42-43</strong>, so I could store the user_id in the session at <strong>line 44</strong></li>
<li>I also added <strong>line 45</strong>. Once the user gets logged in, the <strong>$user</strong> static variable is set, so it can be returned by the <strong>user()</strong> function later.</li>
</ul>
<p>By the way, we just learned how to use <strong>Sessions</strong> in CodeIgniter. It&#8217;s not very complicated. All you need to do is to load the <strong>library</strong> and you can use the <strong>userdata()</strong> and <strong>set_userdata()</strong> function to read and write the variables. You can read more about it <a href="http://codeigniter.com/user_guide/libraries/sessions.html" rel="nofollow">here</a>.</p>
<p>Now we can call the static function like this: <strong>Current_User::login($username,$password)</strong> , and it will take care of the rest.</p>
<p>Phew! I hope that was not very complicated. But I&#8217;m sure you will soon  understand why we went through all of that.</p>
<h4>Simplified Login Controller</h4>
<p>We are about the see the first benefit of creating all that code above.</p>
<ul>
<li>Edit: <strong>system/application/controllers/login.php</strong></li>
</ul>
<p>Only editing the authenticate() function:</p>
<pre class="brush: php;">
&lt;?php
class Login extends Controller {

	// ...

	public function authenticate() {

		return Current_User::login($this-&gt;input-&gt;post('username'),
									$this-&gt;input-&gt;post('password'));

	}
}
</pre>
<p>See how easy that is now?</p>
<p>When we call <strong>Current_User::login()</strong> it attempts to login the user, and returns <strong>TRUE</strong> on success. If the login information is <strong>incorrect</strong>, it returns <strong>FALSE</strong>. </p>
<p>Once the user is logged in this way, we can retrieve the <strong>User</strong> object for the logged in user, anywhere in our application by simply calling <strong>Current_User::user()</strong>.</p>
<p>Also note that we didn&#8217;t need to put &#8220;$this->load->model(&#8217;Current_User&#8217;)&#8221; in the code, and we will never have to. The Current_User class will always be globally available in the application, because of the Doctrine autoloader that was registered in the &#8220;system/application/plugins/doctrine_pi.php&#8221; file.</p>
<h3>Logout</h3>
<p>Now we are going to let users <strong>logout</strong> by clicking a link. But first:</p>
<h4>Autoloading Libraries</h4>
<p>It seems like we are going to be using the Session Library almost everywhere in our application. Let&#8217;s have it autoloaded by CodeIgniter so we don&#8217;t have to keep calling <strong>$this->library->load(&#8217;session&#8217;)</strong> all the time.</p>
<ul>
<li>Edit: <strong>system/application/config/autoload.php</strong></li>
</ul>
<p>Find this line:</p>
<pre class="brush: php;">
// ...
$autoload['libraries'] = array('session');
// ...
</pre>
<p>Let&#8217;s also autoload the <strong>URL Helper</strong>.</p>
<ul>
<li>Edit: <strong>system/application/config/autoload.php</strong></li>
</ul>
<p>Find this line:</p>
<pre class="brush: php;">
// ...
$autoload['helper'] = array('url');
// ...
</pre>
<p>Now that&#8217;s out of the way.</p>
<h4>Logout Controller</h4>
<ul>
<li>Create: <strong>system/application/controllers/logout.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Logout extends Controller {

	public function index() {

		$this-&gt;session-&gt;sess_destroy();
		$this-&gt;load-&gt;view('logout');
	}

}
</pre>
<p>We remove all of the <strong>session data</strong> by calling <strong>$this->session->sess_destroy()</strong>. Now the user will no longer be logged in.</p>
<h4>Logout View</h4>
<ul>
<li>Create: <strong>system/application/views/logout.php</strong></li>
</ul>
<pre class="brush: php; highlight: [8];">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Logout&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
	&lt;meta http-equiv=&quot;refresh&quot; content=&quot;3;url=&lt;?php echo base_url(); ?&gt;&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div&gt;

	&lt;p&gt;
		You are now logged out.
	&lt;/p&gt;
	&lt;p&gt;
		Redirecting you &lt;?php echo anchor('/','home'); ?&gt;.
	&lt;/p&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>This logout page will display a short message and redirect the surfer using a <strong>meta refresh</strong>.</p>
<h4>Style Changes</h4>
<p>I have made some css changes, so just copy paste the following:</p>
<ul>
<li>Edit: <strong>css/style.css</strong></li>
</ul>
<pre class="brush: css;">
body {
	font-family: &quot;Trebuchet MS&quot;,Arial;
	font-size: 14px;
	background-color: #212426;
	color: #B9AA81;
}

a {
	color: #FFF;
}

a:hover {
	color: #B9AA81;
}

input, textarea, select {
	font-family:inherit;
	font-size:inherit;
	font-weight:inherit;
}

#signup_form {
	margin-left: auto;
	margin-right: auto;
	width: 360px;

	font-size: 16px;

}

#signup_form .heading {
	text-align: center;
	font-size: 22px;
	font-weight: bold;
	color: #B9AA81;
}

#signup_form form {

	background-color: #B9AA81;
	padding: 10px;

	border-radius: 8px;
	-moz-border-radius: 8px;
	-webkit-border-radius: 8px;

}

#signup_form form label {
	font-weight: bold;
	color: #11151E;
}

#signup_form form input[type=text],input[type=password] {
	width: 316px;
	font-weight: bold;
	padding: 8px;

	border: 1px solid #FFF;
	border-radius: 4px;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
}

#signup_form form input[type=submit] {
	display: block;
	margin: auto;
	width: 200px;
	font-size: 18px;
	background-color: #FFF;
	border: 1px solid #BBB;

}

#signup_form form input[type=submit]:hover {
	border-color: #000;
}

#signup_form .error {
	font-size: 13px;
	color: #690C07;
	font-style: italic;
}
</pre>
<h4>Home View</h4>
<p>Now we are going to see how easy it is to fetch user information for the logged in user.</p>
<ul>
<li>Create: <strong>system/application/views/home.php</strong></li>
</ul>
<pre class="brush: php; highlight: [13,14]; html-script: true;">
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
	&lt;title&gt;Home&lt;/title&gt;
	&lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;?php echo base_url(); ?&gt;css/style.css&quot;
		type=&quot;text/css&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div&gt;

	&lt;?php if(Current_User::user()): ?&gt;
		&lt;h2&gt;Hello &lt;em&gt;&lt;?php echo Current_User::user()-&gt;username; ?&gt;&lt;/em&gt;.&lt;/h2&gt;
		&lt;h2&gt;&lt;?php echo anchor('logout','Logout'); ?&gt;&lt;/h2&gt;
	&lt;?php else: ?&gt;
		&lt;h2&gt;New Users: &lt;?php echo anchor('signup','Create an Account'); ?&gt;.&lt;/h2&gt;
		&lt;h2&gt;Members: &lt;?php echo anchor('login','Login'); ?&gt;.&lt;/h2&gt;
	&lt;?php endif; ?&gt;

&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<h4>Home Controller</h4>
<ul>
<li>Edit: <strong>system/application/controllers/home.php</strong></li>
</ul>
<pre class="brush: php;">
&lt;?php
class Home extends Controller {

	public function index() {
		$this-&gt;load-&gt;view('home');
	}	

}
</pre>
<p>That&#8217;s it!</p>
<h3>Let&#8217;s Test It</h3>
<ul>
<li>Go to: <a href="http://localhost/ci_doctrine/logout" rel="nofollow">http://localhost/ci_doctrine/logout</a> to make sure you are logged out.</li>
</ul>
<p>First you will see:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_2.png" alt="ci_doctrine_day4_2" title="ci_doctrine_day4_2" width="372" height="175" class="aligncenter size-full wp-image-431" /></p>
<p>And it will forward you home:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_3.png" alt="ci_doctrine_day4_3" title="ci_doctrine_day4_3" width="424" height="271" class="aligncenter size-full wp-image-432" /></p>
<ul>
<li>Click the <strong>Login link</strong> to be forwarded to our <strong>Login Form</strong>.</li>
</ul>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_4.png" alt="ci_doctrine_day4_4" title="ci_doctrine_day4_4" width="423" height="378" class="aligncenter size-full wp-image-433" /></p>
<ul>
<li>Enter a <strong>correct</strong> login info and you will be redirected <strong>home</strong> again.</li>
</ul>
<p>Now you should see:</p>
<p><img src="http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day4_5.png" alt="ci_doctrine_day4_5" title="ci_doctrine_day4_5" width="348" height="255" class="aligncenter size-full wp-image-434" /></p>
<p>In this case my username is <strong>burak</strong>, and it was displayed back to me.</p>
<p>Voila!</p>
<h3>Stay Tuned</h3>
<p>We covered quite a few new concepts in today&#8217;s tutorial. I hope you enjoyed it and learned from it.</p>
<p>In the next tutorial we will explore the <strong>CRUD</strong> (<strong>Create</strong>, <strong>Read</strong>, <strong>Update</strong> and <strong>Delete</strong>) functionality with <strong>Doctrine</strong> in more detail.</p>
<p>See you next time!</p>
<p>
		<div class="article-series" style="background-color: #FFFFFF; padding: 10px; -moz-border-radius: 4px; border:1px solid #B7A99A; margin-bottom: 20px;">
			<h4 style="margin-top: 0px">"CodeIgniter and Doctrine from Scratch" Series:</h4>
			<ul>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">Day 1: Install and Setup</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-and-doctrine-from-scratch-day-2-the-basics">Day 2: The Basics</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form">Day 3: User Signup Form</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login">Day 4: User Login</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-5-database-crud">Day 5: Database CRUD</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-day-6-models-relationships">Day 6: Models with Relationships</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-7-fixtures-forum-list">Day 7: Fixtures & Forum List</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-8-hooks-profiling-dql">Day 8: Hooks, Profiling & DQL</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-9-templates-data-hydrators">Day 9: Templates & Data Hydrators</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-10-pagination">Day 10: Pagination</a></li>
				<li><a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-11-record-hooks">Day 11: Record Hooks</a></li>
				<li>Day 12: ...coming soon</li>
			</ul>
		</div>
	</p>
<img src="http://feeds.feedburner.com/~r/PhpAndStuff/~4/85tshf1Ug60" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login/feed</wfw:commentRss>
		<slash:comments>73</slash:comments>
		<feedburner:origLink>http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 1.209 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-03-09 17:56:50 -->
