<?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>cakebaker &#187; sql</title>
	<atom:link href="http://cakebaker.42dh.com/tags/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://cakebaker.42dh.com</link>
	<description>baking cakes with CakePHP</description>
	<lastBuildDate>Mon, 19 Jul 2010 14:23:38 +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>Selecting related tags with SQL</title>
		<link>http://cakebaker.42dh.com/2009/02/03/selecting-related-tags-with-sql/</link>
		<comments>http://cakebaker.42dh.com/2009/02/03/selecting-related-tags-with-sql/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 16:40:24 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/?p=1095</guid>
		<description><![CDATA[Recently I had to implement a &#8220;related tags&#8221; feature, i.e. you want to get all tags of items tagged with a specific tag. For example, if you have posts tagged with &#8220;sql&#8221; then you want to get all other tags of those &#8220;sql&#8221; posts, like &#8220;mysql&#8221;, &#8220;performance&#8221;, whatever. Here the SQL I came up with [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I had to implement a &#8220;related tags&#8221; feature, i.e. you want to get all tags of items tagged with a specific tag. For example, if you have posts tagged with &#8220;sql&#8221; then you want to get all other tags of those &#8220;sql&#8221; posts, like &#8220;mysql&#8221;, &#8220;performance&#8221;, whatever.</p>
<p>Here the SQL I came up with for the aforementioned example:</p>
<pre>
<code>SELECT 
    Tag.name, 
    COUNT(*) as postcount
FROM 
    tags AS t 
    INNER JOIN posts_tags AS pt ON (t.id = pt.tag_id) 
    INNER JOIN posts AS p ON (pt.post_id = p.id) 
    INNER JOIN posts_tags AS pota ON (p.id = pota.post_id) 
    INNER JOIN tags AS Tag ON (pota.tag_id = Tag.id) 
WHERE 
    t.name = 'sql'  
    AND t.id &lt;&gt; Tag.id
GROUP BY 
    Tag.name';</code>
</pre>
<p>I hope this SQL snippet is useful for some of you!</p>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2009/02/03/selecting-related-tags-with-sql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Deleting records with a limited life time</title>
		<link>http://cakebaker.42dh.com/2008/09/15/deleting-records-with-a-limited-life-time/</link>
		<comments>http://cakebaker.42dh.com/2008/09/15/deleting-records-with-a-limited-life-time/#comments</comments>
		<pubDate>Mon, 15 Sep 2008 15:31:56 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/?p=814</guid>
		<description><![CDATA[Just a short tip today. During the NoseRub DevCamp last weekend (here a short summary) I had to implement request tokens with a limited life time. In our case this life time is 24 hours, i.e. the user has to use the request token within 24 hours, or else it expires. To remove the expired [...]]]></description>
			<content:encoded><![CDATA[<p>Just a short tip today. </p>
<p>During the NoseRub DevCamp last weekend (here a <a href="http://blog.noserub.com/blog/archives/59-NoseRub-DevCamp-08-What-was-it-like.html">short summary</a>) I had to implement request tokens with a limited life time. In our case this life time is 24 hours, i.e. the user has to use the request token within 24 hours, or else it expires. To remove the expired request tokens I wrote the following method:</p>
<pre>
<code>// in the RequestToken model
public function deleteExpired() {
    $this-&gt;deleteAll(array('RequestToken.modified &lt;= DATE_SUB(NOW(), INTERVAL 24 HOUR)'));
}</code>
</pre>
<p>This snippet performs the following steps: it gets the current date and time, subtracts 24 hours, and then deletes all request tokens whose &#8220;modified&#8221; value is smaller (i.e. older) or equal to the result of the subtraction.</p>
<p>MySQL&#8217;s date and time functions are much more powerful than shown in this example, so I recommended to check out the <a href="http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html">documentation</a>, too.</p>
<p>I hope this is helpful for some of you :)</p>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2008/09/15/deleting-records-with-a-limited-life-time/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Order by field</title>
		<link>http://cakebaker.42dh.com/2008/06/10/order-by-field/</link>
		<comments>http://cakebaker.42dh.com/2008/06/10/order-by-field/#comments</comments>
		<pubDate>Tue, 10 Jun 2008 17:09:33 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/?p=613</guid>
		<description><![CDATA[Yesterday, Tarique Sani mentioned in a thread in the CakePHP Group &#8220;order by field&#8221;. I know &#8220;order by&#8221;, but I never heard about &#8220;order by field&#8221; (which seems to be MySQL-specific). Ok, let&#8217;s do some examples to learn more about it. We will use the following countries table: [1] =&#62; USA [2] =&#62; Germany [3] [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday, <a href="http://www.sanisoft.com/blog/author/tariquesani/">Tarique Sani</a> mentioned in a <a href="http://groups.google.com/group/cake-php/browse_thread/thread/dfdebc408aac8bc0/e99c0260204a8ec8">thread</a> in the CakePHP Group &#8220;order by field&#8221;. I know &#8220;order by&#8221;, but I never heard about &#8220;order by field&#8221; (which seems to be MySQL-specific). </p>
<p>Ok, let&#8217;s do some examples to learn more about it. We will use the following countries table:</p>
<pre>
[1] =&gt; USA
[2] =&gt; Germany
[3] =&gt; Russia
[4] =&gt; Austria
[5] =&gt; China
[6] =&gt; Switzerland
</pre>
<p>Now, we don&#8217;t want to sort them by the id, but by some &#8220;strange&#8221; order: Austria, USA, China, Russia, Switzerland, Germany. For this purpose we can use &#8220;order by field&#8221;: the first parameter is the column name and all following parameters are values of the respective column. In CakePHP it is done in the following way:</p>
<pre>
$this-&gt;Country-&gt;find('list', array('order' =&gt; array('FIELD(Country.id, 4, 1, 5, 3, 6, 2)')));
</pre>
<p>And we get the expected result:</p>
<pre>
[4] =&gt; Austria
[1] =&gt; USA
[5] =&gt; China
[3] =&gt; Russia
[6] =&gt; Switzerland
[2] =&gt; Germany
</pre>
<p>Probably more common is the scenario that you want to have certain values at the top of a list, and the other values of the list should be ordered alphabetically. If we want the German-speaking countries at the top of the list we would do:</p>
<pre>
$this-&gt;Country-&gt;find('list', array('order' =&gt; array('FIELD(Country.id, 2, 4, 6)', 'Country.name')));

or 

$this-&gt;Country-&gt;find('list', array('order' =&gt; array('FIELD(Country.name, "Germany", "Austria", "Switzerland")', 'Country.name')));
</pre>
<p>Unfortunately, this doesn&#8217;t return the expected result, the records which should be at the top are at the bottom:</p>
<pre>
[5] =&gt; China
[3] =&gt; Russia
[1] =&gt; USA
[2] =&gt; Germany
[4] =&gt; Austria
[6] =&gt; Switzerland
</pre>
<p>We can solve this &#8220;problem&#8221; by using the &#8220;DESC&#8221; keyword and changing the order of the provided values:</p>
<pre>
$this-&gt;Country-&gt;find('list', array('order' =&gt; array('FIELD(Country.id, 6, 4, 2) DESC', 'Country.name')));

or

$this-&gt;Country-&gt;find('list', array('order' =&gt; array('FIELD(Country.name, "Switzerland", "Austria", "Germany") DESC', 'Country.name')))
</pre>
<p>With those changes we get the expected result:</p>
<pre>
[2] =&gt; Germany
[4] =&gt; Austria
[6] =&gt; Switzerland
[5] =&gt; China
[3] =&gt; Russia
[1] =&gt; USA
</pre>
<p>Thanks to Tarique for mentioning &#8220;order by field&#8221; and to <a href="http://www.gigapromoters.com/blog/">Abhimanyu Grover</a> for asking the original question.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2008/06/10/order-by-field/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Using distinct and count with CakePHP</title>
		<link>http://cakebaker.42dh.com/2007/08/06/using-distinct-and-count-with-cakephp/</link>
		<comments>http://cakebaker.42dh.com/2007/08/06/using-distinct-and-count-with-cakephp/#comments</comments>
		<pubDate>Mon, 06 Aug 2007 16:42:52 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2007/08/06/using-distinct-and-count-with-cakephp/</guid>
		<description><![CDATA[This post is the answer to Mandy Singh&#8216;s comment to the article Select distinct with CakePHP in which he asked how to use &#8220;count&#8221; with &#8220;distinct&#8221;. The answer I gave then &#8212; to use a custom query &#8212; works, but there exists a more Cake-like solution. The obvious solution &#8212; using findCount() &#8212; doesn&#8217;t work, [...]]]></description>
			<content:encoded><![CDATA[<p>This post is the answer to <a href="http://mandysingh.blogspot.com/">Mandy Singh</a>&#8216;s comment to the article <a href="http://cakebaker.42dh.com/2007/07/25/select-distinct-with-cakephp/">Select distinct with CakePHP</a> in which he asked how to use &#8220;count&#8221; with &#8220;distinct&#8221;. The answer I gave then &#8212; to use a custom query &#8212; works, but there exists a more Cake-like solution. </p>
<p>The obvious solution &#8212; using findCount() &#8212; doesn&#8217;t work, as there is no way to specify that you want to use &#8220;distinct&#8221;. </p>
<p>So to get the desired result we have to use a find() or findAll() statement as shown in the following example:</p>
<pre>
$this-&gt;User-&gt;find(null, "COUNT(DISTINCT User.city) AS 'count'");
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2007/08/06/using-distinct-and-count-with-cakephp/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Select distinct with CakePHP</title>
		<link>http://cakebaker.42dh.com/2007/07/25/select-distinct-with-cakephp/</link>
		<comments>http://cakebaker.42dh.com/2007/07/25/select-distinct-with-cakephp/#comments</comments>
		<pubDate>Wed, 25 Jul 2007 08:53:27 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2007/07/25/select-distinct-with-cakephp/</guid>
		<description><![CDATA[Sometimes you have to use SELECT DISTINCT to get the desired records from the database. How can you use SELECT DISTINCT with CakePHP? The solution is rather simple: $this-&#62;User-&#62;findAll(null, 'DISTINCT User.city'); Or with the array syntax: $this-&#62;User-&#62;findAll(null, array('DISTINCT User.city')); Please notice that the keyword &#8220;DISTINCT&#8221; has to be uppercase, else you will get the following [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes you have to use <a href="http://www.w3schools.com/sql/sql_select.asp">SELECT DISTINCT</a> to get the desired records from the database. How can you use SELECT DISTINCT with CakePHP? </p>
<p>The solution is rather simple:</p>
<pre>
$this-&gt;User-&gt;findAll(null, 'DISTINCT User.city');
</pre>
<p>Or with the array syntax:</p>
<pre>
$this-&gt;User-&gt;findAll(null, array('DISTINCT User.city'));
</pre>
<p>Please notice that the keyword &#8220;DISTINCT&#8221; has to be uppercase, else you will get the following error:</p>
<pre>
Unknown column 'distinct User.city'
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2007/07/25/select-distinct-with-cakephp/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How to use SQL functions in conditions, part II</title>
		<link>http://cakebaker.42dh.com/2007/05/22/how-to-use-sql-functions-in-conditions-part-ii/</link>
		<comments>http://cakebaker.42dh.com/2007/05/22/how-to-use-sql-functions-in-conditions-part-ii/#comments</comments>
		<pubDate>Tue, 22 May 2007 08:06:41 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2007/05/22/how-to-use-sql-functions-in-conditions-part-ii/</guid>
		<description><![CDATA[In the original post &#8220;How to use SQL functions in conditions&#8221; I showed you how to use SQL functions in conditions by means of the magic &#8220;-!&#8221; marker with the following example: $this-&#62;User-&#62;findAll(array('DATE(User.modified)' =&#62; '-!CURDATE()')); This snippet returns all user records modified at the current day. Now John-Henrique asked in a comment how to do [...]]]></description>
			<content:encoded><![CDATA[<p>In the original post <a href="http://cakebaker.42dh.com/2007/05/04/how-to-use-sql-functions-in-conditions/">&#8220;How to use SQL functions in conditions&#8221;</a> I showed you how to use SQL functions in conditions by means of the magic &#8220;-!&#8221; marker with the following example:</p>
<pre>
$this-&gt;User-&gt;findAll(array('DATE(User.modified)' =&gt; '-!CURDATE()'));
</pre>
<p>This snippet returns all user records modified at the current day. Now <a href="http://vibemidia.com/blog/">John-Henrique</a> asked in a comment how to do the contrary, i.e. select those records not modified at the current day. </p>
<p>There exist at least two possible ways to accomplish this, the simplest one is to use &#8220;&lt;&gt;&#8221;:</p>
<pre>
$this-&gt;User-&gt;findAll(array('DATE(User.modified)' =&gt; '&lt;&gt; -!CURDATE()'));
</pre>
<p>It creates the following SQL code:</p>
<pre>
... WHERE DATE(`User`.`modified`) &lt;&gt; CURDATE()
</pre>
<p>Another approach is to use the &#8220;NOT&#8221; keyword of SQL:</p>
<pre>
$this-&gt;User-&gt;findAll(array('NOT' =&gt; array('DATE(User.modified)' =&gt; '-!CURDATE()')));
</pre>
<p>With this snippet we get the following SQL statement:</p>
<pre>
... WHERE NOT (DATE(`User`.`modified`) = CURDATE())
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2007/05/22/how-to-use-sql-functions-in-conditions-part-ii/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How to use SQL functions in conditions</title>
		<link>http://cakebaker.42dh.com/2007/05/04/how-to-use-sql-functions-in-conditions/</link>
		<comments>http://cakebaker.42dh.com/2007/05/04/how-to-use-sql-functions-in-conditions/#comments</comments>
		<pubDate>Fri, 04 May 2007 15:24:14 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2007/05/04/how-to-use-sql-functions-in-conditions/</guid>
		<description><![CDATA[Sometimes it is handy to use a (database-specific) SQL function in your find/findAll statements, e.g. a function which returns the current date. But how can this be done? The obvious approach doesn&#8217;t work: $this-&#62;User-&#62;findAll(array('DATE(User.modified)' =&#62; 'CURDATE()')); The function &#8220;CURDATE()&#8221; is escaped and treated as a string as you can see in the generated SQL statement: [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes it is handy to use a (database-specific) SQL function in your find/findAll statements, e.g. a function which returns the current date. But how can this be done? </p>
<p>The obvious approach doesn&#8217;t work:</p>
<pre>
$this-&gt;User-&gt;findAll(array('DATE(User.modified)' =&gt; 'CURDATE()'));
</pre>
<p>The function &#8220;CURDATE()&#8221; is escaped and treated as a string as you can see in the generated SQL statement:</p>
<pre>
... WHERE DATE(`User`.`modified`) = 'CURDATE()'
</pre>
<p>To avoid the escaping we have to add the magical &#8220;-!&#8221; marker in front of the function name:</p>
<pre>
$this-&gt;User-&gt;findAll(array('DATE(User.modified)' =&gt; '-!CURDATE()'));
</pre>
<p>This will generate the expected SQL:</p>
<pre>
... WHERE DATE(`User`.`modified`) = CURDATE()
</pre>
<p>Hooray!</p>
<p>Thanks to Kabturek who mentioned this little trick some time ago in his <a href="http://kabturek.info/archive/2007/02/09">blog</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2007/05/04/how-to-use-sql-functions-in-conditions/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>How to use NOT IN in a condition</title>
		<link>http://cakebaker.42dh.com/2007/04/26/how-to-use-not-in-in-a-condition/</link>
		<comments>http://cakebaker.42dh.com/2007/04/26/how-to-use-not-in-in-a-condition/#comments</comments>
		<pubDate>Thu, 26 Apr 2007 08:28:17 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[cakephp]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2007/04/26/how-to-use-not-in-in-a-condition/</guid>
		<description><![CDATA[Yesterday, moeffju asked in a comment to the post &#8220;Using an IN list in a condition&#8221; how to use NOT IN in SQL queries generated by CakePHP. A good question as the solution is not that obvious (at least if you use the array syntax for conditions). First the obvious solution: $this-&#62;User-&#62;findAll('User.id NOT IN (1, [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday, <a href="http://moeffju.net/blog/">moeffju</a> asked in a comment to the post <a href="http://cakebaker.42dh.com/2006/09/28/using-an-in-list-in-a-condition/">&#8220;Using an IN list in a condition&#8221;</a> how to use NOT IN in SQL queries generated by CakePHP. A good question as the solution is not that obvious (at least if you use the array syntax for conditions).</p>
<p>First the obvious solution:</p>
<pre>
$this-&gt;User-&gt;findAll('User.id NOT IN (1, 2, 3)');
</pre>
<p>And here the solution using the array syntax:</p>
<pre>
$this-&gt;User-&gt;findAll(array('NOT' =&gt; array('User.id' =&gt; array(1, 2, 3))));
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2007/04/26/how-to-use-not-in-in-a-condition/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Baking a Cake &#8211; From the domain model to Cake models</title>
		<link>http://cakebaker.42dh.com/2007/03/04/baking-a-cake-from-the-domain-model-to-cake-models/</link>
		<comments>http://cakebaker.42dh.com/2007/03/04/baking-a-cake-from-the-domain-model-to-cake-models/#comments</comments>
		<pubDate>Sun, 04 Mar 2007 16:53:24 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[baking a cake]]></category>
		<category><![CDATA[cakephp]]></category>
		<category><![CDATA[domain model]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2007/03/04/baking-a-cake-from-the-domain-model-to-cake-models/</guid>
		<description><![CDATA[Do you remember the domain model from a previous post? No? No problem, here it is again: The next logical step on the way from the domain model to the Cake models would be to refine the domain model to a database diagram. I say &#8220;would be&#8221; as it is something I almost never do, [...]]]></description>
			<content:encoded><![CDATA[<p>Do you remember the domain model from a previous post? No? No problem, here it is again:</p>
<p><img src='http://cakebaker.42dh.com/wp-content/uploads/2007/02/domain_model.png' alt='Domain model' /></p>
<p>The next logical step on the way from the domain model to the Cake models would be to refine the domain model to a database diagram. I say &#8220;would be&#8221; as it is something I almost never do, especially not for small projects. For me it isn&#8217;t worth the additional effort as a database diagram doesn&#8217;t add much value if you know some basic rules (Cake conventions). And well, I don&#8217;t have found a free tool for this task which convinced me ;-)</p>
<p>So I will go on and create the tables manually. For this purpose I will create a create.sql file in app/config/sql.</p>
<p>The first rule is that table names are plural. So we can write the SQL statement for the table for the &#8220;User&#8221; class (I omit the other classes as it is the same for them):</p>
<pre>
CREATE TABLE users (
);
</pre>
<p>The second rule is that each table has a primary key field with the name &#8220;id&#8221;. So we can modify the script from above to:</p>
<pre>
CREATE TABLE users (
    id INT(11) NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
);
</pre>
<p>The third rule is optional, but you can add the fields &#8220;created&#8221; and &#8220;modified&#8221; to the table, which are later automatically populated by CakePHP:</p>
<pre>
CREATE TABLE users (
    id INT(11) NOT NULL AUTO_INCREMENT,
    created DATETIME,
    modified DATETIME,
    PRIMARY KEY (id)
);
</pre>
<p>The fourth rule affects 1:n relations: The &#8220;n&#8221; table must contain a field named &#8220;singular name of &#8217;1&#8242; table&#8221; + &#8220;_id&#8221;. In our domain model the relation between User and Project is such a 1:n relation: one User can have many Projects. So we have to add the field &#8220;user_id&#8221; to the &#8220;projects&#8221; table:</p>
<pre>
CREATE TABLE projects (
    id INT(11) NOT NULL AUTO_INCREMENT,
    user_id INT(11) NOT NULL,
    created DATETIME,
    modified DATETIME,
    PRIMARY KEY (id)
);
</pre>
<p>The fifth rule affects n:n relations. Such relations cannot be mapped directly to the database, we have to introduce a join table. The name of this join table is &#8220;plural name of first &#8216;n&#8217; table&#8221; + &#8220;_&#8221; + &#8220;plural name of second &#8216;n&#8217; table&#8221; whereby the names are sorted alphabetically. In our domain model we have only one n:n relation, between User and Project. So the table name is &#8220;projects_users&#8221;. We also have to apply the fourth rule, as the relations between &#8220;projects&#8221; and &#8220;projects_users&#8221; resp. between &#8220;users&#8221; and &#8220;projects_users&#8221; are 1:n relations. And so we get:</p>
<pre>
CREATE TABLE projects_users (
    project_id INT(11) NOT NULL,
    user_id INT(11) NOT NULL
);
</pre>
<p>Now we can add the attributes from the conceptual classes as fields to the respective tables and write the drop statements. And we get:</p>
<pre>
CREATE TABLE users (
    id INT(11) NOT NULL AUTO_INCREMENT,
    created DATETIME,
	modified DATETIME,
    PRIMARY KEY (id)
);

CREATE TABLE projects (
    id INT(11) NOT NULL AUTO_INCREMENT,
    user_id INT(11) NOT NULL,
    created DATETIME,
    modified DATETIME,
    PRIMARY KEY (id)
);

CREATE TABLE messages (
    id INT(11) NOT NULL AUTO_INCREMENT,
    project_id INT(11) NOT NULL,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    created DATETIME,
    modified DATETIME,
    PRIMARY KEY (id)
);

CREATE TABLE feeds (
    id INT(11) NOT NULL AUTO_INCREMENT,
    user_id INT(11) NOT NULL,
    url VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME,
    PRIMARY KEY (id)
);

CREATE TABLE projects_users (
    project_id INT(11) NOT NULL,
    user_id INT(11) NOT NULL
);
</pre>
<p>And in app/config/sql/drop.sql:</p>
<pre>
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS projects;
DROP TABLE IF EXISTS messages;
DROP TABLE IF EXISTS feeds;
DROP TABLE IF EXISTS projects_users;
</pre>
<p>To execute these SQL scripts I use a simple Ant script (app/config/sql/build.xml):</p>
<pre>
&lt;?xml version="1.0"?&gt;
&lt;project name="n" default="default"&gt;
    &lt;property name="driver" value="com.mysql.jdbc.Driver"&gt;&lt;/property&gt;
    &lt;property name="url" value="jdbc:mysql://localhost/n?characterEncoding=UTF-8"&gt;&lt;/property&gt;
    &lt;property name="user" value="root"&gt;&lt;/property&gt;
    &lt;property name="password" value=""&gt;&lt;/property&gt;

    &lt;target name="default"&gt;
        &lt;sql driver="${driver}" password="${password}" url="${url}" userid="${user}" src="drop.sql" encoding="UTF-8"&gt;&lt;/sql&gt;
        &lt;sql driver="${driver}" password="${password}" url="${url}" userid="${user}" src="create.sql" encoding="UTF-8"&gt;&lt;/sql&gt;
    &lt;/target&gt;
&lt;/project&gt;
</pre>
<p>After executing the Ant script, we are ready to bake the models. I will use the bake script (available in cake/scripts) to generate the User model, as I was asked to show how bake.php is used. I think it should be self-explanatory:</p>
<p><img src='http://cakebaker.42dh.com/wp-content/uploads/2007/03/baking_model_1.png' alt='Baking model, part 1' /></p>
<p><img src='http://cakebaker.42dh.com/wp-content/uploads/2007/03/baking_model_2.png' alt='Baking model, part 2' /></p>
<p>This will create the following model in app/models/user.php:</p>
<pre>
&lt;?php
class User extends AppModel {
    var $name = 'User';

    //The Associations below have been created with all possible keys, those that are not needed can be removed
    var $hasMany = array(
        'Feed' =&gt; array('className' =&gt; 'Feed',
            'foreignKey' =&gt; 'user_id',
            'conditions' =&gt; '',
            'fields' =&gt; '',
            'order' =&gt; '',
            'limit' =&gt; '',
            'offset' =&gt; '',
            'dependent' =&gt; '',
            'exclusive' =&gt; '',
            'finderQuery' =&gt; '',
            'counterQuery' =&gt; ''),
        'Project' =&gt; array('className' =&gt; 'Project',
            'foreignKey' =&gt; 'user_id',
            'conditions' =&gt; '',
            'fields' =&gt; '',
            'order' =&gt; '',
            'limit' =&gt; '',
            'offset' =&gt; '',
            'dependent' =&gt; '',
            'exclusive' =&gt; '',
            'finderQuery' =&gt; '',
            'counterQuery' =&gt; ''),
    );

    var $hasAndBelongsToMany = array(
        'Project' =&gt; array('className' =&gt; 'Project',
            'joinTable' =&gt; 'projects_users',
            'foreignKey' =&gt; 'user_id',
            'associationForeignKey' =&gt; 'project_id',
            'conditions' =&gt; '',
            'fields' =&gt; '',
            'order' =&gt; '',
            'limit' =&gt; '',
            'offset' =&gt; '',
            'unique' =&gt; '',
            'finderQuery' =&gt; '',
            'deleteQuery' =&gt; '',
            'insertQuery' =&gt; ''),
    );
}
?&gt;
</pre>
<p>It generates also a test case for the model in app/tests/cases/models/user.test.php:</p>
<pre>
&lt;?php 

loadModel('User');

class UserTestCase extends UnitTestCase {
    var $object = null;

    function setUp() {
        $this-&gt;object = new User();
    }

    function tearDown() {
        unset($this-&gt;object);
    }

    /*
    function testMe() {
        $result = $this-&gt;object-&gt;doSomething();
        $expected = 1;
        $this-&gt;assertEqual($result, $expected);
    }
    */
}
?&gt;
</pre>
<p>As you see, when using the bake script you have to answer many questions. That&#8217;s a bit of a pain when you want to bake multiple models. And if you don&#8217;t want to write tests you have to remove them (that&#8217;s at least what I do with files which are not used). These are the reasons I prefer to write the models manually. </p>
<p>Here are the other models (please notice that I omit the $name variable as I am a) using PHP5 and b) lazy):</p>
<pre>
// app/models/feed.php
&lt;?php

class Feed extends AppModel {
    var $belongsTo = array('User');
}
?&gt;
</pre>
<pre>
// app/models/project.php
&lt;?php

class Project extends AppModel {
    var $hasMany = array('Message');
    var $hasAndBelongsToMany = array('User');
}
?&gt;
</pre>
<pre>
// app/models/message.php
&lt;?php

class Message extends AppModel {
    var $belongsTo = array('Project');
}
?&gt;
</pre>
<p>To test whether we defined the associations correctly, we can create for all models the corresponding controllers. Here the UsersController (the other controllers are similar):</p>
<pre>
// app/controllers/users_controller.php
&lt;?php

class UsersController extends AppController {
    var $scaffold;
}
?&gt;
</pre>
<p>With that, we have something to play, we can add, edit, and remove records. But it isn&#8217;t very useful yet ;-)</p>
<p>That&#8217;s it for today.</p>
<p>(<a href="http://cakebaker.42dh.com/tags/baking-a-cake/">other articles</a> from this series)</p>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2007/03/04/baking-a-cake-from-the-domain-model-to-cake-models/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>A simple task to generate sql scripts</title>
		<link>http://cakebaker.42dh.com/2006/10/25/a-simple-task-to-generate-sql-scripts/</link>
		<comments>http://cakebaker.42dh.com/2006/10/25/a-simple-task-to-generate-sql-scripts/#comments</comments>
		<pubDate>Wed, 25 Oct 2006 16:55:07 +0000</pubDate>
		<dc:creator>cakebaker</dc:creator>
				<category><![CDATA[bake]]></category>
		<category><![CDATA[cakephp]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[task]]></category>

		<guid isPermaLink="false">http://cakebaker.42dh.com/2006/10/25/a-simple-task-to-generate-sql-scripts/</guid>
		<description><![CDATA[To make it a bit easier to write the sql scripts for creating and dropping tables, I wrote a simple bake task. There isn&#8217;t much to say about it, so I show you just an example. The following call: php bake2.php sqlscripts users profiles profiles_users creates app/config/sql/create.sql: CREATE TABLE users ( id INT(11) NOT NULL [...]]]></description>
			<content:encoded><![CDATA[<p>To make it a bit easier to write the sql scripts for creating and dropping tables, I wrote a simple bake task. There isn&#8217;t much to say about it, so I show you just an example. </p>
<p>The following call:</p>
<pre>
php bake2.php sqlscripts users profiles profiles_users
</pre>
<p>creates app/config/sql/create.sql:</p>
<pre>
CREATE TABLE users (
  id INT(11) NOT NULL AUTO_INCREMENT,
  created DATETIME,
  modified DATETIME,
  PRIMARY KEY (id)
); 

CREATE TABLE profiles (
  id INT(11) NOT NULL AUTO_INCREMENT,
  created DATETIME,
  modified DATETIME,
  PRIMARY KEY (id)
); 

CREATE TABLE profiles_users (
  profile_id INT(11) NOT NULL,
  user_id INT(11) NOT NULL,
  PRIMARY KEY (profile_id, user_id)
);
</pre>
<p>and app/config/sql/drop.sql:</p>
<pre>
DROP TABLE IF EXISTS users;

DROP TABLE IF EXISTS profiles;

DROP TABLE IF EXISTS profiles_users;
</pre>
<p>That&#8217;s it. You can find the code in the <a href="http://cakebaker.42dh.com/downloads">download section</a>. Happy baking :)</p>
]]></content:encoded>
			<wfw:commentRss>http://cakebaker.42dh.com/2006/10/25/a-simple-task-to-generate-sql-scripts/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
