<?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>Mark O&#039;Sullivan &#187; Lussumo</title>
	<atom:link href="http://markosullivan.ca/category/lussumo/feed/" rel="self" type="application/rss+xml" />
	<link>http://markosullivan.ca</link>
	<description>Currently Programming Jerry-Lee-Lewis-Style</description>
	<lastBuildDate>Thu, 28 Jul 2011 13:13:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>The Road</title>
		<link>http://markosullivan.ca/the-road/</link>
		<comments>http://markosullivan.ca/the-road/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 16:01:43 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Garden]]></category>
		<category><![CDATA[Lussumo]]></category>
		<category><![CDATA[Vanilla 2]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/?p=604</guid>
		<description><![CDATA[It is long overdue that I post an update to the Garden &#038; Vanilla 2 development. First: if you find that I&#8217;ve not been posting on my blog, you can take it as a good sign meaning that I&#8217;m busy doing other things. Myself and a great friend of mine (Todd Burry) have been working [...]]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://markosullivan.ca/wp-content/uploads/2009/06/vanilla-2.gif" alt="Vanilla 2" title="Vanilla 2" width="500" height="234" class="alignnone size-full wp-image-605" /></center></p>
<p>It is long overdue that I post an update to the Garden &#038; Vanilla 2 development. First: if you find that I&#8217;ve not been posting on my blog, you can take it as a good sign meaning that I&#8217;m busy doing other things. </p>
<p>Myself and a great friend of mine (Todd Burry) have been working full-time on the project for the last four weeks.</p>
<p>Next week we will be moving our <a href="http://issues.gardenframework.com">current issue tracker</a> over to GitHub and simultaneously releasing the Garden and Vanilla 2 code there. The code is still under heavy development and is absolutely not ready for production use. However, it <em>does</em> work and we need your help getting it finished. </p>
<p>Although Vanilla 1 is an open source project, I have always been the bottleneck that keeps it from really taking off. I refuse to let this happen with Garden and Vanilla 2. So, we will be doing our best to allow everyone in the 10,000-strong Lussumo community to help us out this time around, and the release of the code on GitHub is just the first of many steps in this direction.</p>
<p>Following the GitHub move, I will be contacting the authors of the most popular plugins for Vanilla 1 and helping them to get their plugins ported to Vanilla 2 so they can be fully functional and compatible for the Vanilla 2 release. If, for some reason, the authors are uninterested in porting their plugins to Vanilla 2, I will be making announcements here to find anyone out there who is interested in picking up where the previous authors left off, so keep your eyes peeled. If you have a new plugin idea that you want implemented for Vanilla 2 and you want a hand with getting Garden, Vanilla 2, and understanding how things are done: feel free to contact me here on this blog, via twitter @navvywavvy, or directly via email at mark [at] lussumodotcom.</p>
<p>The future starts here!</p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/the-road/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Survey Says?</title>
		<link>http://markosullivan.ca/survey-says/</link>
		<comments>http://markosullivan.ca/survey-says/#comments</comments>
		<pubDate>Mon, 25 May 2009 21:07:06 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Lussumo]]></category>
		<category><![CDATA[Vanilla]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/?p=598</guid>
		<description><![CDATA[In an effort to better understand the every day Vanilla user &#038; administrator, I&#8217;ve put a short survey together and linked it from the Vanilla download and the Addon download pages. If you are a Vanilla user, were a Vanilla user, or will be a Vanilla user, please take a few minutes to help us [...]]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://markosullivan.ca/wp-content/uploads/2009/05/pat-sajak.jpg" alt="Pat Sajak" title="Pat Sajak" width="241" height="331" class="alignnone size-full wp-image-599" /></center></p>
<p>In an effort to better understand the every day Vanilla user &#038; administrator, I&#8217;ve put a short survey together and linked it from the Vanilla download and the Addon download pages. If you are a Vanilla user, were a Vanilla user, or will be a Vanilla user, please take a few minutes to help us out with this survey so we can make Vanilla better for everyone: <a href="http://lussumo.com/survey.php">Survey!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/survey-says/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>And Or Alternatives</title>
		<link>http://markosullivan.ca/and-or-alternatives/</link>
		<comments>http://markosullivan.ca/and-or-alternatives/#comments</comments>
		<pubDate>Sun, 17 May 2009 02:50:32 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Garden]]></category>
		<category><![CDATA[Lussumo]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/?p=589</guid>
		<description><![CDATA[I&#8217;m in the process of adding some methods to the database object to help in writing chained queries for Garden. One of the annoying problems I&#8217;ve run into is that the words &#8220;or&#8221; and &#8220;and&#8221; are reserved and won&#8217;t work as method names. So, for example, imagine I wanted to write the following chained query: [...]]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://markosullivan.ca/wp-content/uploads/2009/05/applestooranges.gif" alt="Apples and Oranges" title="Apples and Oranges" width="400" height="295" class="alignnone size-full wp-image-593" /></center></p>
<p>I&#8217;m in the process of adding some methods to the database object to help in writing chained queries for Garden. One of the annoying problems I&#8217;ve run into is that the words &#8220;or&#8221; and &#8220;and&#8221; are reserved and won&#8217;t work as method names. So, for example, imagine I wanted to write the following chained query:</p>
<pre>$Database
     ->Select('FieldName')
     ->From('TableName')
     ->Where('FieldName', 'value')
     -><strong>Or</strong>()
     ->Where('FieldName', 'othervalue')
     -><strong>And</strong>()
     ->Where('FieldName', 'Yet Another Value')
     ->Get();</pre>
<p>I realize that this query really doesn&#8217;t make much sense, but that&#8217;s beside the point. The &#8220;or&#8221; and the &#8220;and&#8221; methods can&#8217;t exist in PHP, so what should I use instead?</p>
<p>I&#8217;ve played with things like <strong>AndOp</strong> and <strong>OrOp</strong>, implying that they are operators. I&#8217;ve tried going for shorter versions like <strong>Nd</strong> and <strong>R</strong>, but those are just stupid and don&#8217;t make much sense. I&#8217;ve also considered having <strong>OrWhere</strong> and <strong>AndWhere</strong> methods, but that would mean adding a whole bunch of methods like that (think: OrWhere, AndWhere, OrLike, AndLike, OrWhereIn, AndWhereIn, etc).</p>
<p>I&#8217;m looking for community input here. What would you prefer to type?</p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/and-or-alternatives/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Rebranding</title>
		<link>http://markosullivan.ca/rebranding/</link>
		<comments>http://markosullivan.ca/rebranding/#comments</comments>
		<pubDate>Tue, 05 May 2009 23:17:35 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Garden]]></category>
		<category><![CDATA[Lussumo]]></category>
		<category><![CDATA[Vanilla 2]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/?p=576</guid>
		<description><![CDATA[In recent weeks I&#8217;ve been working closely with Jon Contino of Onetwentysix to overhaul the branding of Lussumo products. Recently we settled on the new logos for Vanilla, Conversations, and Garden. Thanks Jon! Update Jon posted a walk-through of how all of these logos came to life. Check it out!]]></description>
			<content:encoded><![CDATA[<p>In recent weeks I&#8217;ve been working closely with Jon Contino of <a href="http://www.onetwentysix.com/">Onetwentysix</a> to overhaul the branding of Lussumo products. Recently we settled on the new logos for Vanilla, Conversations, and Garden. Thanks Jon!</p>
<p><center><img src="http://markosullivan.ca/wp-content/uploads/2009/05/rebranding1.png" alt="Vanilla, Conversations, Garden" title="Vanilla, Conversations, Garden" width="480" height="77" class="alignnone size-full wp-image-581" /></center></p>
<p><strong>Update</strong><br />
Jon posted a walk-through of how all of these logos came to life. <a href="http://joncontino.com/fresh/branding-lussumo/">Check it out!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/rebranding/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Vanilla 1.1.6 Released</title>
		<link>http://markosullivan.ca/vanilla-116-released/</link>
		<comments>http://markosullivan.ca/vanilla-116-released/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 14:23:28 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Lussumo]]></category>
		<category><![CDATA[Vanilla 1]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/blog/?p=548</guid>
		<description><![CDATA[Vanilla 1.1.6 has been released and is now available at getvanilla.com. If you are upgrading from a previous installation of Vanilla, you&#8217;ll want to read the upgrade instructions. If you&#8217;re curious like me, you&#8217;ll want to read the release notes. A big thank you to all of the contributors! dinoboff edavis hst izaak Reed Loden [...]]]></description>
			<content:encoded><![CDATA[<p>Vanilla 1.1.6 has been released and is now available at <a href="http://getvanilla.com">getvanilla.com</a>.</p>
<p>If you are upgrading from a previous installation of Vanilla, you&#8217;ll want to read the <a href="http://lussumo.com/docs/doku.php?id=vanilla:upgrading">upgrade instructions</a>.</p>
<p>If you&#8217;re curious like me, you&#8217;ll want to read the <a href="http://lussumo.com/docs/doku.php?id=vanilla:releasenotes">release notes</a>.</p>
<p>A big thank you to all of the contributors!</p>
<blockquote><p>dinoboff<br />
edavis<br />
hst<br />
izaak<br />
Reed Loden<br />
[-Stash-]<br />
sirlancelot<br />
SubJunk<br />
Wallphone</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/vanilla-116-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Community Help: Lussumo.com Connectivity Issues [RESOLVED]</title>
		<link>http://markosullivan.ca/community-help-lussumocom-connectivity-issues/</link>
		<comments>http://markosullivan.ca/community-help-lussumocom-connectivity-issues/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 22:36:25 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[help]]></category>
		<category><![CDATA[Lussumo]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/blog/?p=491</guid>
		<description><![CDATA[Today you may have begun to notice database errors when attempting to load any of my websites. Particularly lussumo.com/community and markosullivan.ca/blog have been showing intermittent errors. These errors have come at a particularly inopportune time (is there ever a good time?) because I am extremely busy with a new contract, development of the Garden framework, [...]]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://files.lussumo.com/first_four.jpg" border="0" width="400" height="317" /></center></p>
<p>Today you may have begun to notice database errors when attempting to load any of my websites. Particularly lussumo.com/community and markosullivan.ca/blog have been showing intermittent errors.</p>
<p>These errors have come at a particularly inopportune time (is there ever a good time?) because I am extremely busy with a new contract, development of the Garden framework, Vanilla 2, and I also manage to have a life in there somewhere (sometimes <img src='http://markosullivan.ca/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>When I began to notice the slow page-loading times on my server and then the errors that followed, I contacted my hosting company to find out what was going wrong. I am hosted at rackspace.com, and they are well known for their fanatical support. True to form, they got back to me quickly with a diagnosis of the problem:</p>
<pre>Good Afternoon,

I have made some adjustments to the my.cnf configuration file in /etc

skip-bdb

query_cache_size=64M
query_cache_limit=12M

interactive_timeout=300
wait_timeout=300

tmp_table_size=128M
max_heap_table_size=128M

in order to decrease the high amount of disk I/O occuring on this server.  This should help with the query building by allocating more memory to this resource.  I have also disabled persistent MySQL connections from PHP:

mysql.allow_persistent = Off

It appears you are reaching your maximum connections limit for MySQL.  The above adjustments are conservative due to the low amount of physical memory you have on this server.

When your server runs out of physical memory, it resorts to using disk space (SWAP memory).  This swapping can and will cause your server to become unresponsive.

You may also consider increasing the amount of physical memory on this server with a RAM upgrade.  If you are interested in proceeding, I can send this ticket to a BDC who can assist you with this upgrade and update you on pricing for this component.

Besides processes in "sleep" status, indicating the use of persistent MySQL connections, it appears most of the connections are due to table locking occuring:

+-----+---------+-----------+-----------+---------+------+-------------------------------+------------------------------------------------------------------------------------------------------+
| Id  | User    | Host      | db        | Command | Time | State                         | Info                                                                                                 |
+-----+---------+-----------+-----------+---------+------+-------------------------------+------------------------------------------------------------------------------------------------------+
| 573 | xxxx | localhost | community | Query   |    9 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 574 | xxxx | localhost | community | Query   |   10 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 583 | xxxx | localhost | community | Query   |   10 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 584 | xxxx | localhost | community | Query   |    9 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 591 | xxxx | localhost | community | Query   |   10 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 593 | xxxx | localhost | community | Query   |   10 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 728 | xxxx | localhost | community | Query   |    5 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 729 | xxxx | localhost | community | Query   |    4 | Locked                        | select a.AddOnID  as AddOnID, a.AddOnTypeID  as AddOnTypeID, a.ApplicationID  as ApplicationID, a.Au |
| 733 | xxxx | localhost | community | Query   |    3 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 734 | xxxx | localhost | community | Query   |    3 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 730 | xxxx | localhost | community | Query   |    3 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 735 | xxxx | localhost | community | Query   |    2 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 736 | xxxx | localhost | community | Query   |    2 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 737 | xxxx | localhost | community | Query   |    2 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 738 | xxxx | localhost | community | Query   |    0 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 739 | xxxx | localhost | community | Query   |    0 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
| 740 | xxxx | localhost | community | Query   |    0 | Locked                        | SELECT t.DiscussionID  AS DiscussionID, t.FirstCommentID  AS FirstCommentID, t.AuthUserID  AS AuthUs |
+-----+---------+-----------+-----------+---------+------+-------------------------------+------------------------------------------------------------------------------------------------------+
as these queries are locking the table, subsequent queries are having to wait and thus stacking up taking available connections.  You may find that changing this table type to Innodb may help with this table locking issue.  You may need to discuss with your developers if this change would have an inverse affect to your applications.

As well, I have enabled slow query logging in:

/var/lib/mysqllogs/slow-log

which will log queries taking over 5 seconds to complete.  This information will help your developers to optimize any SQL queries and/or apply indexing where appropriate.

I have also put in the option in Apache:

MaxRequestsPerChild  1000

which will help to reduce the memory footprint of this service.

While it appears that the above changes helped with the non availabilty of MySQL, the server is still highly loaded.</pre>
<p>Now, I always knew that the Vanilla 1 queries were hairy and could cause problems. I didn&#8217;t think it was going to happen any time soon, and I was hoping to get Vanilla 2 in place before this became an issue (Vanilla 2&#8242;s queries are much simpler and faster) &#8211; but it looks like that is not going to happen. Regardless, it would seem that my traffic has slowly and steadily been increasing at lussumo.com over the years. In December we peaked at 2.5 million page views for that month at lussumo.com alone, and we&#8217;ve maintained that amount of traffic almost every day since. </p>
<p>Obviously I could throw more RAM at the server as the Rackspace support person suggested &#8211; this seems to be a common answer to problems of this sort (we currently only have 1G of ram on the server), but I don&#8217;t know if that is the answer I should be looking for &#8211; especially considering that I&#8217;m already paying a lot of money for the server. </p>
<p>So, I am hoping that all of those who use Vanilla can step up to the plate and offer your expertise on how to resolve this issue. I am opening the doors and accepting any and all advice, questions, ideas on how to fix the problem.</p>
<p>Here is what I have tried so far:</p>
<p>* I reviewed the slow queries that mysql logged and found that 99% of them were Vanilla&#8217;s &#8220;comments page&#8221; and &#8220;discussions page&#8221; queries. I&#8217;ve <a href="http://markosullivan.ca/ups/slow-log-sample.zip">uploaded a sample of the slow query log</a> so you can see what queries are causing problems.</p>
<p>* I downloaded a copy of the Lussumo Community database to my local dev machine so I could get a good look at the tables, indexes, etc.</p>
<p>* I found that none of the indexes that are included with the current release of Vanilla 1 were applied on the tables (other than primary keys). This is probably due to the fact that I&#8217;ve just added columns as development has continued and never had a problem before now. </p>
<p>* I added the indexes that are shipped with the current release of Vanilla 1 to the community database. I found that this had little-to-no effect on the speed of the page-load (it might have even made the queries slower).</p>
<p>* I&#8217;ve created a script that converts all of the tables in the community db to innodb tables (as suggested by the rackspace tech). I&#8217;ve done some googling that has detailed both good and bad results of this type of change. It could start to throw fatal errors when data is being inserted (rather than while it&#8217;s being selected, as it is now). I have not yet run this script as I want to hear back from the community first.</p>
<p>* I&#8217;ve taken the community forums offline and enabled wp-cache on this blog so that everyone can have access to this blog post and be fully aware of the issue.</p>
<h2>Help!</h2>
<p>So, I am reaching out to you for help. No question is a dumb one. Any idea is welcome. Please share your expertise and help us to get this convoy back on the road&#8230;</p>
<h2>Update</h2>
<p>It turns out that I had forgotten to apply all of the indexes &#038; optimizations to this database through the years that we&#8217;ve been online. The growth of our community, combined with poor indexing caused a couple of the tables to begin to lock. The LUM_User and LUM_UserDiscussionWatch tables in particular were locking. These tables are updated frequently with login information and discussion tracking information respectively. Because the tables were MyISAM type, all records would be locked when an update was applied to just a single row &#8211; this meant that all 9000+ user records would get locked whenever anyone&#8217;s &#8220;DateLastActive&#8221; field was updated, and all 90,000+ records in the LUM_UserDiscussionWatch table would get locked whenever anyone even looked at a single discussion (and the record of their view of that discussion was recorded).</p>
<p>To fix both of these issues, I changed their table types to InnoDB so that only the affected row should become locked when updates are applied. </p>
<p>I also analyzed the Discussions &#038; Comments queries, which are (obviously) the most actively run queries in the application. The comments query was extremely slow. After running EXPLAIN on the query, I found that it was indexed incorrectly. For some reason the LUM_Comment table was using both the CommentID and the DiscussionID columns as it&#8217;s primary key. I removed the DiscussionID as a primary key and added it as a simple index. This allows the query to not scan the entire LUM_Comment table when performing the join to LUM_Discussion. I also found that the LUM_UserBlock table had no indexes at all, so I added those and was able to further reduce the query time. Here is a list of the changes that I made to the database for anyone who might be interested:</p>
<pre>ALTER TABLE `community`.`LUM_Comment` DROP PRIMARY KEY,
 ADD PRIMARY KEY  USING BTREE(`CommentID`),
 ADD INDEX `comment_discussion`(`DiscussionID`);

ALTER TABLE LUM_UserBlock ADD INDEX (BlockingUserID);
ALTER TABLE LUM_UserBlock ADD INDEX (BlockedUserID);

ALTER TABLE LUM_User ENGINE=InnoDB;
ALTER TABLE LUM_UserDiscussionWatch ENGINE=InnoDB;</pre>
<p>Thanks to Damien (Dinoboff) and Dave (Wallphone) for jumping in and offering some assistance.</p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/community-help-lussumocom-connectivity-issues/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>Garden Preview Part IV: Views</title>
		<link>http://markosullivan.ca/garden-preview-part-iv-views/</link>
		<comments>http://markosullivan.ca/garden-preview-part-iv-views/#comments</comments>
		<pubDate>Tue, 02 Dec 2008 16:32:23 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Garden]]></category>
		<category><![CDATA[Lussumo]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/blog/?p=291</guid>
		<description><![CDATA[Garden Preview Part I: Overview Garden Preview Part II: Filesystem Garden Preview Part III: Anatomy of a Request Garden Preview Part IV: Views Garden Preview Part V: Data Garden Preview Part VI: Models &#038; Forms Garden Preview Part VII: Ajax Garden Preview Part VIII: Plugins Garden Preview Part IX: Roles &#038; Permissions Garden Preview Part [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://markosullivan.ca/blog/?p=231">Garden Preview Part I: Overview</a><br />
<a href="http://markosullivan.ca/blog/?p=251">Garden Preview Part II: Filesystem</a><br />
<a href="http://markosullivan.ca/blog/?p=275">Garden Preview Part III: Anatomy of a Request</a><br />
<a href="http://markosullivan.ca/blog/?p=291">Garden Preview Part IV: Views</a><br />
<a href="http://markosullivan.ca/blog/?p=310">Garden Preview Part V: Data</a><br />
<a href="http://markosullivan.ca/blog/?p=326">Garden Preview Part VI: Models &#038; Forms</a><br />
<a href="http://markosullivan.ca/blog/?p=347">Garden Preview Part VII: Ajax</a><br />
<a href="http://markosullivan.ca/blog/?p=360">Garden Preview Part VIII: Plugins</a><br />
<a href="http://markosullivan.ca/blog/?p=373">Garden Preview Part IX: Roles &#038; Permissions</a><br />
<a href="http://markosullivan.ca/blog/?p=397">Garden Preview Part X: User Registration</a><br />
<a href="http://markosullivan.ca/blog/?p=419">Garden Preview Part XI: Structure</a></p>
<p>Last week I described how requests to Garden are handled by the dispatcher. This week I&#8217;m going to explain how those requests are rendered by the requested controller. </p>
<p>Once a controller method is called to handle the request, how is the xhtml of the page put together? <strong>Views</strong>.</p>
<p>There are two types of views in Garden: &#8220;Views&#8221; and &#8220;Master Views&#8221;. A view relates directly to the controller method that called it and handles rendering content related to that request. You can typically think of a view as the content for that page. For example, if a Vanilla->Discussion->All() method is called, the view for that method would handle rendering all of the discussions. Everything that is rendered around the discussions is handled by the Master View.</p>
<p>The Master View allows you to create a consistent layout for the pages in the application. A single master view defines the look and feel and standard behavior for all of the pages (or a group of pages) in the application. </p>
<p>Let&#8217;s go back to the filesystem so you can get a better picture. In the following example, the request in the url would have been the following:</p>
<p><code>http://myserver.com/garden/profile/index/mark</code></p>
<p>So, this means that Garden&#8217;s &#8220;Profile&#8221; controller was requested, the &#8220;index&#8221; method was requested from the profile controller, and the first argument into the index method is &#8220;mark&#8221;. In other words, the request was: <code>$ProfileController->Index('mark');</code></p>
<p><center><img src="http://markosullivan.ca/blog/wp-content/uploads/2008/12/fs-views.gif" alt="" title="Views" width="417" height="687" /></center></p>
<p>Let&#8217;s take a look at the profile controller&#8217;s index method:</p>
<pre>public function Index($UserReference = '') {
   $UserModel = new UserModel();
   $this->User = $UserModel->GetByReference($UserReference);
   $this->Render();
}</pre>
<p>Simply put, the index method grabs some data that can be later used in the profile controller&#8217;s &#8220;index&#8221; view, and then calls the Render() method. The Render method is defined on the base Controller class; the class from which all controllers are extended. The Render method performs the following tasks:</p>
<p>1. Finds and fetches the view.<br />
2. Finds and fetches the css for the view.<br />
3. Finds and renders the master view.</p>
<p>In the most simple example, the view will be as it appears in the image above: in a &#8220;profile&#8221; folder within the &#8220;views&#8221; folder, and named after the method that was called: <em>/views/profile/index.php</em>.</p>
<p>By default, the controller will fetch that view from the context of the FetchView method of the base controller class. In plain-English: the view file is included within a method on the Controller class called &#8220;FetchView&#8221;. That is why I placed the user data within a $this->User property in my $ProfileController->Index() method, above; so it could be accessible from within my view file. The view file likely will contain something as simple as this:</p>
<pre>&lt;h3>Basic Information&lt;/h3>
&lt;dl class="Info">
   &lt;dt>Joined&lt;/dt>
   &lt;dd>&lt;?php echo $this->User->DateFirstVisit; ?>&lt;/dd>
   &lt;dt>Visits&lt;/dt>
   &lt;dd>&lt;?php echo $this->User->CountVisits; ?>&lt;/dd>
   &lt;dt>Last Active&lt;/dt>
   &lt;dd>&lt;?php echo $this->User->DateLastActive; ?>&lt;/dd>
&lt;/dl></pre>
<p><em>It is important to note that I have not used a custom templating engine like smarty. This is because PHP already <strong>is</strong> a templating engine. Further to that point, I am only resorting to switching to PHP when echoing data to the screen, and I am not building large concatenated echo statements. All of these efforts are taken in order to make the theme author&#8217;s job easier.</em></p>
<p>Once the view is fetched, it is added to an asset collection. By default it is added to the &#8220;Content&#8221; asset collection. The rest of the page (the &#8220;Frame&#8221; of the page) is handled by the master view. By default, the &#8220;default.master&#8221; master view is used unless another master view is specified. In the image above you can see that there are a few different master views available in the Garden application: default, email, error, and setup. The css files for each of those master views are named accordingly, as well. So, the default.master view has a default.screen.css file, the error.master view has an error.screen.css file, etc. Again, in the most simple of examples, the master view is located in the &#8220;view&#8221; folder of the application, and the related css files are located in the &#8220;design&#8221; folder of that application. </p>
<p>Here is what the default.master view looks like:</p>
<pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-ca">
&lt;head>
	&lt;?php $this->RenderAsset('Head'); ?>
&lt;/head>
&lt;body&lt;?php echo Attribute(array('id' => $BodyIdentifier, 'class' => $this->CssClass)); ?>>
   &lt;div id="Frame">
      &lt;div id="Title">&lt;a href="&lt;?php Link('garden/user/browse'); ?>">&lt;span>&lt;?php echo $this->Head->TitlePrefix; ?>&lt;/span>&lt;/a>&lt;/div>
      &lt;?php $this->RenderAsset('Menu'); ?>
      &lt;div id="Content">&lt;?php $this->RenderAsset('Content'); ?>&lt;/div>
      &lt;div id="Foot">&lt;?php $this->RenderAsset('Foot'); ?>&lt;/div>
   &lt;/div>
&lt;/body>
&lt;/html></pre>
<p>As you can see, the master view handles the basic structure of a page. As I mentioned above, by default the view that is fetched by the controller is added to an asset collection called &#8220;Content&#8221;, and that asset collection is rendered in this master view when the <code>$this->RenderAsset('Content')</code> method is called &#8211; right there in the middle of the master view.</p>
<p>As you can see in the master view above, there are a number of different asset collections available for application and plugin authors (Head, Menu, Content, and Foot). An application author has the ability to add as many of these as he/she desires and add to them as necessary. The idea behind these asset collections is that while the basic request can be handled and placed into the &#8220;Content&#8221; asset (ie. the profile information being displayed from the example above), there are still a lot of other elements a person may want on a page. Plugin authors may want to add assets to the head, menu, or foot. They may even want to add assets to the content collection. Garden itself has other UI components that get rendered in the head and menu asset collections (which will be discussed in a later preview). </p>
<p>So, in the most basic example, the &#8220;index&#8221; view is requested from it&#8217;s controller&#8217;s view folder, the default.screen.css file is requested from the application&#8217;s design folder, and the master view is requested from the root of the application&#8217;s &#8220;view&#8221; folder. What other ways could the views and css have been retrieved?</p>
<p>The controller uses Garden&#8217;s FileSystem object to search the application for the appropriate file to handle the request. Whatever the filesystem object finds first, it will use. </p>
<h3>Views are retrieved with the following precedence:</h3>
<p><strong>1. An explicitly defined path to a view.</strong><br />
ie. a plugin&#8217;s custom view location<br />
<strong>2. Application-specific theme view.</strong><br />
ie. /path/to/garden/themes/theme_name/app_name/views/controller_name/view.php<br />
<strong>3. Garden-wide theme view.</strong><br />
ie. /path/to/garden/themes/theme_name/views/controller_name/view.php<br />
<strong>4. Application default.</strong><br />
ie. /path/to/garden/applications/app_name/views/controller_name/view.php</p>
<h3>Master views are retrieved with the following precedence:</h3>
<p><strong>1. Application-specific theme view.</strong><br />
ie. /path/to/garden/themes/theme_name/app_name/views/default.master<br />
<strong>2. Garden-wide theme view.</strong><br />
ie. /path/to/garden/themes/theme_name/views/default.master<br />
<strong>3. Application default.</strong><br />
ie. /path/to/garden/applications/app_name/views/default.master<br />
<strong>4. Garden default.</strong><br />
ie. /path/to/garden/applications/garden/views/default.master</p>
<h3>CSS files are retrieved with the following precedence:</h3>
<p><strong>1. Application-specific css.</strong><br />
ie. /path/to/garden/themes/theme_name/app_name/design/default.screen.css<br />
<strong>2. Garden-wide theme view.</strong><br />
ie. /path/to/garden/themes/theme_name/design/default.screen.css<br />
<strong>3. Application default.</strong><br />
ie. /path/to/garden/applications/app_name/design/default.screen.css<br />
<strong>4. Garden default.</strong><br />
ie. /path/to/garden/applications/garden/design/default.screen.css</p>
<p>You might be wondering things like: can I change the view or master view that handles my request on the fly? Of course you can! Everything in Garden was written so that you have total control over what comes out on the other end. In my example above, I could change my views on the fly with something like this:</p>
<pre>public function Index($UserReference = '') {
   $UserModel = new UserModel();
   $this->User = $UserModel->GetByReference($UserReference);
   $this->View = "somethingelse"; <strong>// Use /views/profile/somethingelse.php to handle the content
   // ... or ...</strong>
   $this->View = "/some/other/view.php"; <strong>// Use some custom view to handle the content</strong>
   $this->MasterView = "setup"; <strong>// Use the setup master view to render my contents</strong>
   $this->Render();
}</pre>
<p>Views are a lot to take in, and they certainly might be daunting upon first read. But I can guarantee that I have found them to be utterly simple and flexible to use. Think of the possibilities you can accomplish with views! You could create a master view that handles rendering of RSS feeds. You could port your request method to use your RSS master and render all of your contents with a custom RSS view. You could grab the email master view and send out your content to some email address(es) before rendering. You could bypass the rendering altogether and deliver json data. The possibilities are endless, and that is the real power of views.</p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/garden-preview-part-iv-views/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>jQuery Expression Reference</title>
		<link>http://markosullivan.ca/jquery-expression-reference/</link>
		<comments>http://markosullivan.ca/jquery-expression-reference/#comments</comments>
		<pubDate>Thu, 27 Nov 2008 18:18:38 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Geekery]]></category>
		<category><![CDATA[Lussumo]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/blog/?p=288</guid>
		<description><![CDATA[Does anyone know if there is a way to get the expression that returned an object in jQuery from within it&#8217;s handler? Example: $('body > a').click(function() { // Is there any way I can alert 'body > a' in here? // Perhaps something like: alert($(this).expression); ? });]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://markosullivan.ca/blog/wp-content/uploads/2008/11/handey.jpg" alt="Plans" title="Plans" width="233" height="310" /></center></p>
<p>Does anyone know if there is a way to get the expression that returned an object in jQuery from within it&#8217;s handler?</p>
<p>Example:</p>
<pre>$('body > a').click(function() {
   // Is there any way I can alert 'body > a' in here?
   // Perhaps something like: alert($(this).expression); ?
});</pre>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/jquery-expression-reference/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Garden Preview Part III: Anatomy of a Request</title>
		<link>http://markosullivan.ca/garden-preview-part-iii-anatomy-of-a-request/</link>
		<comments>http://markosullivan.ca/garden-preview-part-iii-anatomy-of-a-request/#comments</comments>
		<pubDate>Mon, 24 Nov 2008 16:51:53 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Garden]]></category>
		<category><![CDATA[Lussumo]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/blog/?p=275</guid>
		<description><![CDATA[Garden Preview Part I: Overview Garden Preview Part II: Filesystem Garden Preview Part III: Anatomy of a Request Garden Preview Part IV: Views Garden Preview Part V: Data Garden Preview Part VI: Models &#038; Forms Garden Preview Part VII: Ajax Garden Preview Part VIII: Plugins Garden Preview Part IX: Roles &#038; Permissions Garden Preview Part [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://markosullivan.ca/blog/?p=231">Garden Preview Part I: Overview</a><br />
<a href="http://markosullivan.ca/blog/?p=251">Garden Preview Part II: Filesystem</a><br />
<a href="http://markosullivan.ca/blog/?p=275">Garden Preview Part III: Anatomy of a Request</a><br />
<a href="http://markosullivan.ca/blog/?p=291">Garden Preview Part IV: Views</a><br />
<a href="http://markosullivan.ca/blog/?p=310">Garden Preview Part V: Data</a><br />
<a href="http://markosullivan.ca/blog/?p=326">Garden Preview Part VI: Models &#038; Forms</a><br />
<a href="http://markosullivan.ca/blog/?p=347">Garden Preview Part VII: Ajax</a><br />
<a href="http://markosullivan.ca/blog/?p=360">Garden Preview Part VIII: Plugins</a><br />
<a href="http://markosullivan.ca/blog/?p=373">Garden Preview Part IX: Roles &#038; Permissions</a><br />
<a href="http://markosullivan.ca/blog/?p=397">Garden Preview Part X: User Registration</a><br />
<a href="http://markosullivan.ca/blog/?p=419">Garden Preview Part XI: Structure</a></p>
<p>mod_rewrite was an afterthought in Vanilla 1. As a result, I&#8217;ve always felt that the mod_rewrite mappings were sloppy and really just didn&#8217;t make much sense. In Garden, the way pages are accessed is completely different, and definitely deserves explaining. Let&#8217;s start by looking at a typical url request in Garden <em>without</em> mod_rewrite enabled:</p>
<pre>http://localhost/garden/default.php/garden/settings/configure</pre>
<p>Let&#8217;s look closer at each part of the request:</p>
<p><strong>http://localhost/garden/default.php</strong>: On my development server, I&#8217;ve created a folder called garden, and placed all of the garden files I discussed in last week&#8217;s preview in it. As you can see, the default.php file that handles all requests is sitting within that folder&#8217;s root. </p>
<p><strong>/garden</strong>: The next part of the url is the application that is being requested. In this case, we are requesting the &#8220;garden&#8221; application within the garden framework&#8217;s application folder.</p>
<p><strong>/settings</strong>: The next part of the url is the controller that is being requested within the garden application. In this example, we are requesting a controller called &#8220;Settings&#8221;.</p>
<p><strong>/configure</strong>: the final part of the url in this example is the method within the &#8220;Settings&#8221; controller that we are calling. In this example, we are calling <code>$SettingsController->Configure();</code>.</p>
<p>If you were to map this request to the filesystem, it would be like this:<br />
<center><img src="http://markosullivan.ca/blog/wp-content/uploads/2008/11/fs-request.gif" alt="Request" title="Request" width="441" height="642" /></center></p>
<p>I could take the same request and add information to the end, like this:</p>
<pre>http://localhost/garden/default.php/garden/settings/configure<strong>/arg1/arg2/argn</strong></pre>
<p>And it would take any other parameters after the controller&#8217;s configure method as if they are arguments being passed into that method. In other words, the above request would be essentially the same as calling that method like so:</p>
<pre>$SettingsController->Configure('arg1', 'arg2', 'argn');</pre>
<p>This can get pretty handy when doing things like paging through records, or specifying which user to load in a page. For example, to edit a user, the url would be:</p>
<pre>http://localhost/garden/default.php/garden/user/edit/mark</pre>
<p>Which would map to:</p>
<pre>$UserController->Edit('mark');</pre>
<p><strong>Analyzing the Request</strong><br />
All requests are handled through the Dispatcher class. The dispatcher class looks at the request (everything after default.php) and tries to figure out the best way to handle it. As far as the dispatcher is concerned, in a perfect world the request would always include the application name, the controller name, and the method name. But in reality you might not always want all three items in your url. For example, you might want your application invisible to the user &#8211; so that, for example, a request to vanilla&#8217;s discussion list goes to </p>
<pre>http://yourwebsite.com/default.php/discussions/all</pre>
<p>&#8230; instead of &#8230;</p>
<pre>http://yourwebsite.com/default.php/vanilla/discussions/all</pre>
<p>Furthermore, you might want your controller&#8217;s method hidden as well. So you could end up with something like:</p>
<pre>http://yourwebsite.com/default.php/discussions</pre>
<p>The dispatcher can handle all of these and a lot more. First of all, when no method is defined in the request, the dispatcher assumes that you are calling the &#8220;index&#8221; method of the controller. So, a request to:</p>
<pre>http://yourwebsite.com/default.php/vanilla/discussions</pre>
<p>&#8230; is the same as calling &#8230;</p>
<pre>$DiscussionsController->Index();</pre>
<p>Furthermore, when the dispatcher gets a request that doesn&#8217;t include the application name, it starts to look through all of the enabled applications for the requested controller name. As soon as it finds one, it records it&#8217;s mapping in the cache folder and calls it appropriately. There is the possibility that two different applications could have the same controller name, and in that case, it would return the first application&#8217;s controller that it found. </p>
<p>Probably the nicest thing about this method of handling requests is that a 6-line .htaccess file:</p>
<pre>&lt;IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.*)$ default.php/$1 [QSA,L]
&lt;/IfModule></pre>
<p>&#8230; allows you to remove the default.php from the url and makes all requests look like this:</p>
<pre>http://yourdomain.com/application/controller/method</pre>
<p>Or, in it&#8217;s simplest form:</p>
<pre>http://yourdomain.com/controller</pre>
<p><strong>Next</strong><br />
In the next garden preview, I&#8217;ll be getting into how controllers work, how views are found and rendered, and how master views can let you customize layouts between applications and themes.</p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/garden-preview-part-iii-anatomy-of-a-request/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Garden Preview Part I</title>
		<link>http://markosullivan.ca/garden-preview-part-i/</link>
		<comments>http://markosullivan.ca/garden-preview-part-i/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 20:15:19 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Garden]]></category>
		<category><![CDATA[Lussumo]]></category>

		<guid isPermaLink="false">http://markosullivan.ca/blog/?p=231</guid>
		<description><![CDATA[Garden Preview Part I: Overview Garden Preview Part II: Filesystem Garden Preview Part III: Anatomy of a Request Garden Preview Part IV: Views Garden Preview Part V: Data Garden Preview Part VI: Models &#038; Forms Garden Preview Part VII: Ajax Garden Preview Part VIII: Plugins Garden Preview Part IX: Roles &#038; Permissions Garden Preview Part [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://markosullivan.ca/blog/?p=231">Garden Preview Part I: Overview</a><br />
<a href="http://markosullivan.ca/blog/?p=251">Garden Preview Part II: Filesystem</a><br />
<a href="http://markosullivan.ca/blog/?p=275">Garden Preview Part III: Anatomy of a Request</a><br />
<a href="http://markosullivan.ca/blog/?p=291">Garden Preview Part IV: Views</a><br />
<a href="http://markosullivan.ca/blog/?p=310">Garden Preview Part V: Data</a><br />
<a href="http://markosullivan.ca/blog/?p=326">Garden Preview Part VI: Models &#038; Forms</a><br />
<a href="http://markosullivan.ca/blog/?p=347">Garden Preview Part VII: Ajax</a><br />
<a href="http://markosullivan.ca/blog/?p=360">Garden Preview Part VIII: Plugins</a><br />
<a href="http://markosullivan.ca/blog/?p=373">Garden Preview Part IX: Roles &#038; Permissions</a><br />
<a href="http://markosullivan.ca/blog/?p=397">Garden Preview Part X: User Registration</a><br />
<a href="http://markosullivan.ca/blog/?p=419">Garden Preview Part XI: Structure</a></p>
<p><center><img src="http://markosullivan.ca/blog/wp-content/uploads/2008/11/garden.gif" alt="What's growing in your Garden?" title="What's growing in your Garden?" width="377" height="182" /></center></p>
<p>Almost two years ago I started thinking about rewriting the Lussumo Framework, the framework upon which Vanilla is built. After a year of heavy contemplation, I finally started development on the new version, which I have come to call &#8220;Garden&#8221;. </p>
<p>My concept for the Garden framework is not to be competition for the likes of The Zend Framework, CakePHP, or even CodeIgniter (to name a few of the other great PHP frameworks), but something both a little less and a little more. My idea was to create a framework that didn&#8217;t solve <em>every</em> problem, but just most of the <em>common</em> problems we face when developing simple web applications. I wanted to build a framework that had user and permission management built right in. I wanted to build a framework with which you could easily create new applications and throw them alongside any others &#8211; and all users, roles, permissions, preferences, plugins, and themes could play nice together. </p>
<p>I can safely say that I have accomplished that task. </p>
<p>Recently I had an active member of the Lussumo Community contact me and ask if his plugins for Vanilla 1 would work with Vanilla 2. It was hard to give him the answer that, no, <strong>none</strong> of the (over 400) plugins for Vanilla 1 would work with Vanilla 2. I had to explain to him that developing in Garden will be easier, faster, and take far less code than it used to. His questions made me realize that I need to step up and explain Garden to all of the great Lussumo Developers out there. </p>
<p>In this part of the Garden preview, I am going to give a brief overview of some of the main goals of Garden. In the parts to follow, I will go into great detail of each part of the framework, explaining the theories behind them and how they can be used by developers to build new applications, plugins and themes.</p>
<p><strong>Extending Garden</strong><br />
In Vanilla 1 there were a number of ways that developers could add to the application. I called these <a href="http://lussumo.com/addons/">Add-ons</a> and they fell into the categories of: extensions, themes, styles, and languages. </p>
<p>When I started thinking about how to add to Garden, I realized that I was missing a key ingredient: applications. Vanilla is just one application, and I wanted to be able to use Garden to do more than just Vanilla. I also realized that almost no-one ever worked with themes <em>(Hell, I started to do one and found it too difficult)</em>, so I&#8217;ve taken the concept of themes, simplified it and munged it together with styles. Finally, I realized that the lay-person doesn&#8217;t really know what an extension is, but everyone knows what a plugin is.</p>
<p>So, in Garden, add-ons will fall into the following categories: applications, plugins, and themes. If you&#8217;re wondering what happened to languages, you&#8217;ll read about that in a little bit.</p>
<p><strong>Speed</strong><br />
Probably the biggest criticism of Vanilla 1 was that it slows down under heavy load. I absolutely refuse to give up on object-oriented programming in PHP, so I&#8217;ve been <em>exclusively</em> working with the latest releases of PHP; taking advantage of it&#8217;s speed with OO programming. I&#8217;ve also done a ton of research on code optimization for PHP. Rest assured, Garden is <strong>very</strong> fast. But application speed isn&#8217;t where the conversation should end. </p>
<p>I&#8217;ve also worked very hard to produce libraries that are fast and easy to work with. I wanted it to take fewer lines of code to accomplish both difficult <em>and</em> common tasks. For example, I&#8217;ve completely rewritten the database libraries so that building queries is easier, and it integrates with the MVC code so that models are instantly created simply by referring to the tables they represent. This means that data validation can be automated based on the properties of columns in database tables &#8211; just one of the many places that Garden will speed up your development time.</p>
<p><strong>Models, Views, and Controllers</strong><br />
When I was writing Vanilla 1, I didn&#8217;t know what an MVC pattern was. Little did I know that I was re-inventing the wheel at the time. Vanilla 1 used a bloated, red-headed step-child of the MVC design pattern. Garden is still based on the MVC design pattern, but it is done with far less code and in a much more elegant way. When I began re-thinking the page delivery model for Garden, I decided to go out there and research what the competition was doing. I read books on design patterns, read blog entries about everything under the sun by developers from all around the world. I looked into every framework I could get my hands on. </p>
<p>I ended up being a little wowed by the simplicity of CakePHP and CodeIgniter&#8217;s approaches to MVC. In the end I&#8217;ve borrowed ideas from both and added a few of my own. The result is views that can be delivered in-page or via ajax popups. Dynamic content delivered in a myriad of ways. Fully integrated protection from exploits and CSRF attacks. Master/container views that allow theme authors to quickly and easily put Garden applications right into their own applications. Simple models that can be generated on the fly. And custom routing so that pointing users to different parts of your applications is dead simple.</p>
<p><strong>Membership, Roles &#038; Permissions</strong><br />
While I had done some very different things with roles &#038; permissions in Vanilla 1, I had also painted myself into a corner that made expansion difficult. In Garden, adding new permissions is dead easy, and users can be assigned to more than just one role. There are many different ways to set up registration and add new users. Four out-of-the box options are: simple (apply and you&#8217;re in), captcha, administrative approval, and by invitation.</p>
<p><strong>Localization</strong><br />
While I believe that localization was one of the things I got right in Vanilla 1, it didn&#8217;t have any follow through. The result of this lack of follow-through is that Vanilla 1 is still released with just one language available. Another problem is that whenever the application changed, or new extensions were added, there would be the need for new translations to be in place &#8211; but no way of notifying the translation authors that these translations were needed. </p>
<p>In Garden, the localization files are roughly the same. One difference is that the folder name for a set of localization files is based on the already known and followed internationalization codes used everywhere on the internet. So, for example, the locale folder I&#8217;ve been working with is labeled &#8220;en-CA&#8221; for &#8220;Canadian English&#8221;. The major difference is that localization will no longer be represented on the add-ons site. Instead, the Lussumo community will be in charge of localization. </p>
<p>One of the many applications I am building with Garden (alongside Vanilla, of course) is a localization application that monitors any translation that is made by Garden and records it in a database. Any member of the community can then work on any set of locale definitions they want to. It will be a wiki-like handling of localization. Whenever a full set of translations is finished and approved by a group of members, it will be added to the appropriate application or plugin and be included in the downloadable application package.</p>
<p><strong>So Much More</strong><br />
With literally years of deep pontification transformed into code, there is so much to tell you. I still haven&#8217;t even touched upon Garden&#8217;s error-handling, out-of-the-box friendly urls, new licensing model (still open source and free), database engine integrations, cache management, jQuery! I haven&#8217;t even mentioned menu organization, plugin management, enforced plugin and application requirements, automated setup and installation. And I have only hinted at the other applications that are coming along with garden besides Vanilla. I never even told you about the hosted solution I&#8217;ll be offering when Garden and Vanilla are released!</p>
<p>The long and short of it is that the hard work is done. Aside from cleanup and debugging, the Garden framework is up and running and I am now into application, plugin, and theme development. My hope is to have an entirely new lussumo.com launched within the first quarter of the new year. In the meantime, keep checking back here for more in-depth previews of Garden.</p>
]]></content:encoded>
			<wfw:commentRss>http://markosullivan.ca/garden-preview-part-i/feed/</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
	</channel>
</rss>

