<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kevin Bradwick &#187; Doctrine</title>
	<atom:link href="http://www.kevinbradwick.co.uk/tag/doctrine/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kevinbradwick.co.uk</link>
	<description>Web development and design blog</description>
	<lastBuildDate>Fri, 09 Jul 2010 08:11:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Introduction to Doctrine&#8217;s Nested Set</title>
		<link>http://www.kevinbradwick.co.uk/2009/12/introduction-to-doctrines-nested-set/</link>
		<comments>http://www.kevinbradwick.co.uk/2009/12/introduction-to-doctrines-nested-set/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 02:31:30 +0000</pubDate>
		<dc:creator>kevin</dc:creator>
				<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[nested set]]></category>

		<guid isPermaLink="false">http://www.kevinbradwick.co.uk/?p=24</guid>
		<description><![CDATA[A common problem requirement among developers is to store hierarchial data to a flat file database. You have probably come across the parent/child methodology whereby a table has a typical &#8216;parent&#8217; column that references, you guessed it, its parent &#8211; this method is also known as adjacency list model. Querying in this way can often [...]]]></description>
			<content:encoded><![CDATA[<p>A common <del datetime="2010-01-07T21:13:33+00:00">problem</del> requirement among developers is to store hierarchial data to a flat file database. You have probably come across the parent/child methodology whereby a table has a typical &#8216;parent&#8217; column that references, you guessed it, its parent &#8211; this method is also known as adjacency list model. Querying in this way can often lead to a lot of transactions per single request (one transaction per row) and an application with many rows of hierarchial data will dent your transaction efficiency. There are benefits to this system (simpler SQL management for CRUD operation) but there is another way that is more efficient &#8211; the Nested Set model (also known as modified pre-order tree traversal algorithm &#8211; MPTT).</p>
<p>Doctrine has by far the best known method of Nested Set operation I have come across. My main reason for this is the ability for it to store multiple roots in a single table. For example, this could come in handy for an application that implements multiple blogs.</p>
<p>So, let&#8217;s dive in and take a look at how we use this system.</p>
<p>For this example, I am going to show how this would come in use for a web application that hosts multiple blogs. Our database schema looks like this.</p>
<pre name="code" class="php">
CREATE TABLE `Blogs` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `blog_admin` int(11) unsigned NOT NULL,
  `blog_title` text,
  `blog_description` text,
  `status` enum('live','private','offline') NOT NULL DEFAULT 'live',
  PRIMARY KEY (`id`),
  KEY `FK_Blogs_users` (`blog_admin`),
  CONSTRAINT `FK_Blogs_users` FOREIGN KEY (`blog_admin`) REFERENCES `Users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;

CREATE TABLE `BlogCategories` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `blog_id` int(11) unsigned NOT NULL,
  `name` varchar(140) DEFAULT NULL,
  `description` text,
  `lft` int(11) unsigned NOT NULL,
  `rgt` int(11) unsigned NOT NULL,
  `level` int(10) unsigned NOT NULL DEFAULT '0',
  `root_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_BlogCategories_blogs` (`blog_id`),
  CONSTRAINT `FK_BlogCategories_blogs` FOREIGN KEY (`blog_id`) REFERENCES `Blogs` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
</pre>
<p>Simply, we have a blogs table that has a foreign key back to a user table and the BlogCategories table will hold our categories relating to all the blogs. Next we will create our models&#8230;</p>
<p>I&#8217;m not going to cover model creation but for reference, I prefer to design my database through MySQL Query Browser first, then let Doctrine to generate the models for me using the generateModelsFromDb method like this;</p>
<pre name="code" class="php">
//...
Doctrine_Core::generateModelsFromDb('/path/to/where/i/want/to/output/my/models/', array('doctrine'), array('generateTableClasses' => true));
</pre>
<p>In my BlogsCategories model, I tell it to act as a nested set, tell it there are many roots and declare the root column name (by default it is root_id, so I don&#8217;t need to declare it here but this is to show you how you would declare it to be a name other than root_id)</p>
<pre name="code" class="php">
//...
$this->actAs('NestedSet', array(
	'hasManyRoots' => TRUE,
	'rootColumnName' => 'root_id'
	));
</pre>
<p>Now we&#8217;re good to go. The first thing we want to do is create a new root category. This category will be the parent category for all other categories.</p>
<pre name="code" class="php">
$root = new BlogCategories();
$root->blog_id = 1; // relates back to the Blogs table
$root->name = 'ROOT';
$root->description = 'DO NOT DELETE';
$root->save(); // saves the new root category

$treeObject = Doctrine_Core::getTable('BlogCategories')->getTree();
$treeObject->createRoot($root);
</pre>
<p>If you look in your database now, you notice this has inserted the row and set the left/right/level/root columns appropriately. You can do this a few times to create a few roots. Now let&#8217;s look at inserting nodes for a particular blog. We&#8217;ll work with blog_id 1.</p>
<pre name="code" class="php">
$blogOneRoot = Doctrine_Core::getTable('BlogCategories')->find(1); // the primary key of the root node for blog_id 1

$child = new BlogCategories();
$child->blog_id = 1;
$child->name = 'Doctrine';
$child->description = 'Good Doctrine tutorials';
$child->getNode()->insertAsLastChildOf($blogOneRoot);
</pre>
<p>This has now inserteda new child category for blog_id 1.</p>
<p>The last step we&#8217;ll take now is rendering a category tree of a particular blog. For this example again, I&#8217;ll assume blog_id 1.</p>
<pre name="code" class="php">
$categoryTree = Doctrine_Core::getTable('BlogCategories')->getTree();
foreach($categoryTree ->fetchTree(array('root_id' => 1)) as $cat)
{
     echo str_repeat(' ', $cat['level']) . $cat['name'] . "\n";

}
</pre>
<p>And that pretty much covers the basics. It&#8217;s really easy &#8211; once you know how. There are many more cool things that can be done with Doctrine&#8217;s nested set method that I may cover on another day. Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kevinbradwick.co.uk/2009/12/introduction-to-doctrines-nested-set/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integrating CodeIgniter and Doctrine</title>
		<link>http://www.kevinbradwick.co.uk/2009/12/integrating-codeigniter-and-doctrine/</link>
		<comments>http://www.kevinbradwick.co.uk/2009/12/integrating-codeigniter-and-doctrine/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 23:05:06 +0000</pubDate>
		<dc:creator>kevin</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[ORM]]></category>

		<guid isPermaLink="false">http://www.kevinbradwick.co.uk/?p=5</guid>
		<description><![CDATA[Having used CodeIgniter over the past year or so, I came to realise some limitations with the Database library. CodeIgniter does not have a proper ORM library like a lot of other frameworks provide. With an ORM library, you have a lot more tools at your disposal to not only increase productivity but also improve [...]]]></description>
			<content:encoded><![CDATA[<p>Having used <a href="http://www.codeigniter.com">CodeIgniter</a> over the past year or so, I came to realise some limitations with the Database library. CodeIgniter does not have a proper ORM library like a lot of other frameworks provide. With an ORM library, you have a lot more tools at your disposal to not only increase productivity but also improve database transaction efficiency.</p>
<p><a href="http://www.doctrine-project.org">Doctrine</a> is a full blown PHP ORM framework that can be integrated into other frameworks or old school PHP applications. Here is how to integrate the framework to CodeIgniter.</p>
<p><a href="http://www.doctrine-project.org/download">Download</a> a copy of the Doctrine framework and place it somewhere in your web directory (for this tutorial I am placing it at the web root directory /). My directory structure looks like;</p>
<pre name="code" class="php">
.
..
.htaccess
index.php
licence.txt
user_guide
system
doctrine
application
</pre>
<h3>Set database credentials</h3>
<p>As you would with any other CI app that utilises a database, enter the connection details in the database.php file inside of the config folder.</p>
<pre name="code" class="php">
//.. application/config/database.php
$db['default']['hostname'] = "[hostname]";
$db['default']['username'] = "[username]";
$db['default']['password'] = "[password]";
$db['default']['database'] = "[databasename]";
$db['default']['dbdriver'] = "[driver e.g. mysql]";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";
</pre>
<h3>Enable hooks</h3>
<p>In the config file [application/config/config.php] enable hooks by setting hooks to TRUE.</p>
<pre class="php" name="code">
//.. application/config/config.php
$config['enable_hooks'] = TRUE;
</pre>
<h3>Insert the hook</h3>
<p>Create a new file in the hooks directory [application/hooks] called doctrine.php</p>
<pre name="code" class="php">
//.. application/hooks/doctrine.php
if(!defined('BASEPATH')) exit('file locked');

require_once( FCPATH . 'doctrine/lib/Doctrine.php' );

class DoctrineHook
{

	function bootstrap_doctrine()
	{
		require_once( APPPATH . '/config/database.php' );

		spl_autoload_register(array('Doctrine', 'autoload'));
		Doctrine_Manager::getInstance()->setAttribute('model_loading', 'aggressive');

		if (!isset($db[$active_group]['dsn'])) {
			$db[$active_group]['dsn'] = $db[$active_group]['dbdriver'] .
							'://' . $db[$active_group]['username'] .
							':' . $db[$active_group]['password'].
							'@' . $db[$active_group]['hostname'] .
							'/' . $db[$active_group]['database'];
		}

		Doctrine_Manager::connection($db[$active_group]['dsn']);
		Doctrine_Manager::setAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
		Doctrine_Manager::setAttribute(Doctrine_Core::ATTR_USE_NATIVE_ENUM, true);
		Doctrine::loadModels(APPPATH . DIRECTORY_SEPARATOR . 'models/doctrine/');
	}

}
</pre>
<h3>Register the hook</h3>
<p>So, now we have the hook in place we need to tell CI to execute the hook on system start up. Over to application/config/hooks.php&#8230;</p>
<pre name="code" class="php">
//.. application/config/hooks.php
 if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| Hooks
| -------------------------------------------------------------------------
| This file lets you define "hooks" to extend CI without hacking the core
| files.  Please see the user guide for info:
|
|	http://codeigniter.com/user_guide/general/hooks.html
|
*/
$hook['pre_controller'][] = array(
	'class' => 'DoctrineHook',
	'function' => 'bootstrap_doctrine',
	'filename' => 'doctrine.php',
	'filepath' => 'hooks'
	);

/* End of file hooks.php */
/* Location: ./system/application/config/hooks.php */
</pre>
<p>With this now in place, CI will load doctrine upon each load. There is one thing left to do. Some of you may have noticed in the doctrine.php hook we created, we told Doctrine to load our models from application/models/doctrine. I created the <em>doctrine</em> folder inside the models folder to purposely seperate doctrine classes from my CI models.</p>
<p>Everything should now work and you can call a model using native PHP class loading methods&#8230;</p>
<pre name="code" class="php">
//.. inside a controller we may call a user class like this;
$user = new User();
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.kevinbradwick.co.uk/2009/12/integrating-codeigniter-and-doctrine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
