<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Tutorials</title>
		<link>http://www.i-lateral.com/tutorials/rss</link>
		<atom:link href="http://www.i-lateral.com/tutorials/rss" rel="self" type="application/rss+xml" />
		<description></description>

		
		<item>
			<title>Extending FullTextSearch for DataObjects</title>
			<link>http://www.i-lateral.com/tutorials/extending-fulltextsearch-for-dataobjects/</link>
			<description>&amp;lt;p&amp;gt;I have been wrestling over the problem of extending the default search functionality in Silverstripe to not only search Page objects, but other DataObjects as well.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;In the end I came up with a workable solution thanks to the help of &amp;lt;a href=&amp;quot;http://www.kdurrani.co.uk/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;Katja Durrani&amp;lt;/a&amp;gt; over at the &amp;lt;a href=&amp;quot;http://silverstripe.org/form-questions/show/14961&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;Silverstripe forum&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;It seems that you can&#39;t currently get add searchable objects to FullTextSearchable by any means. Instead, you have to perform a bit of a hack (in my opinion) to the results method on your Page_Controller.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Before getting that far though, you first need to allow any DataObjects you want searched to be indexed. Do the following to your DataObject&#39;s model:&amp;lt;/p&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;pre&amp;gt;public static $indexes = array(<br />    &amp;quot;fulltext (Title, Content)&amp;quot;<br />);&amp;lt;/pre&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;p&amp;gt;Then rebuild your database (/dev/build/?flush=all).&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Now you can go about adding your search form, as described in the &amp;lt;a href=&amp;quot;http://doc.silverstripe.org/sapphire/en/tutorials/4-site-search&amp;quot;&amp;gt;Silverstripe docs&amp;lt;/a&amp;gt;. Once this is done, you need to change your results() method in Page_Controller to look more like this:&amp;lt;/p&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;pre&amp;gt;class Page_Controller extends ContentController {<br />...<br />    public function results($data, $form){<br />        $data = $_REQUEST; <br />        <br />        $query = htmlspecialchars($data[&#39;Search&#39;], ENT_QUOTES,&#39;UTF-8&#39;); <br />        <br />        $pages = DataObject::get(&amp;quot;SiteTree&amp;quot;,&amp;quot;MATCH (Title,Content) AGAINST (&#39;$query&#39; IN BOOLEAN MODE)&amp;quot;);<br />        $studies = DataObject::get(&amp;quot;CaseStudy&amp;quot;,&amp;quot;MATCH (Title,Content) AGAINST (&#39;$query&#39; IN BOOLEAN MODE)&amp;quot;);<br />        <br />        $searchresults = new DataObjectSet();<br />        $searchresults-&amp;amp;gt;merge($pages);<br />        $searchresults-&amp;amp;gt;merge($studies);<br />        <br />        if($searchresults){ <br />            $data[&#39;Results&#39;] = $searchresults;           <br />        } else { <br />            $data[&#39;Results&#39;] = &#39;&#39;; <br />        } <br />        <br />        $data[&#39;Title&#39;] = &#39;Search Results&#39;; <br /><br />        return $this-&amp;amp;gt;customise($data)-&amp;amp;gt;renderWith(array(&#39;Search_results&#39;,&#39;Page&#39;)); <br />    }<br />...<br />}<br />&amp;lt;/pre&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;p&amp;gt;What this new method does, is use the submitted search to perform 2 queries:&amp;lt;/p&amp;gt;<br />&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;line-height: 20px;&amp;quot;&amp;gt;Query SiteTree and return any Objects that have match the search term&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;<br />&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;line-height: 20px;&amp;quot;&amp;gt;Query the DataObject (in this case &amp;quot;CaseStudy&amp;quot;) in the same way.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;<br />&amp;lt;/ol&amp;gt;&amp;lt;p&amp;gt;If you have more than one DataObject you want to query, you would need to add additional queries for each one.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Finally, you need to merge your two returned DataObjectSet&#39;s and then check if they contain any data.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Now you can return this to a custom template (for this example, I have used &amp;quot;Search_results&#39;) and there you go!&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;You can also find this code on &amp;lt;a href=&amp;quot;http://pastie.org/2082787&amp;quot;&amp;gt;Pastie&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;</description>
			<pubDate>Fri, 17 Jun 2011 17:20:49 +0100</pubDate>
			
			
			<guid>http://www.i-lateral.com/tutorials/extending-fulltextsearch-for-dataobjects/</guid>
		</item>
		
		<item>
			<title>Disabling the &quot;Icons&quot; folder on an Ubuntu web server</title>
			<link>http://www.i-lateral.com/tutorials/disabling-the-icons-folder-on-an-ubuntu-web-server/</link>
			<description>&amp;lt;p&amp;gt;Recently one of the websites I built had to go through a fairly thorough sercurity audit. Thankfully it was generally good results all round with no &amp;quot;THIS IS A SERIOUS ERROR&amp;quot; reports (which is always good).&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;One thing that popped up did supprise me though. Apparently there was a full directory listing appearing at: http://www.siteurl.com/icons/&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;I found this odd because I thought I had explicity disabled all directory listings. What was even more annoying was that there doesn&#39;t seem to be a massive amount of conclusive answers as to why this was happening.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Apparently, this is caused by the &amp;quot;mod_alias&amp;quot; extension for Apache, which is enabled by default on Ubuntu (more info at http://httpd.apache.org/docs/2.2/mod/mod_alias.html). Once I knew that, it is quite easy to turn this &amp;quot;feature&amp;quot; off:&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;First, log into your web server and run:&amp;lt;/p&amp;gt;<br />&amp;lt;pre&amp;gt;sudo nano /etc/apache2/mods-available/alias.conf&amp;lt;/pre&amp;gt;<br />&amp;lt;p&amp;gt;This will give you a file that looks like:&amp;lt;/p&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;&amp;amp;lt;IfModule alias_module&amp;amp;gt;&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;#&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# Aliases: Add here as many aliases as you need (with no limit). The format is&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# Alias fakename realname&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;#&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# Note that if you include a trailing / on fakename then the server will&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# require it to be present in the URL.  So &amp;quot;/icons&amp;quot; isn&#39;t aliased in this&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# example, only &amp;quot;/icons/&amp;quot;.  If the fakename is slash-terminated, then the&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# realname must also be slash terminated, and if the fakename omits the&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# trailing slash, the realname must also omit it.&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;#&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# We include the /icons/ alias for FancyIndexed directory listings.  If&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;# you do not use FancyIndexing, you may comment this out.&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;#&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;#Alias /icons/ &amp;quot;/usr/share/apache2/icons/&amp;quot;&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;&amp;amp;lt;Directory &amp;quot;/usr/share/apache2/icons&amp;quot;&amp;amp;gt;&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;    Options -Indexes MultiViews&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;    AllowOverride None&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;    Order allow,deny&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;    Allow from all&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;&amp;amp;lt;/Directory&amp;amp;gt;&amp;lt;/div&amp;gt;<br />&amp;lt;div id=&amp;quot;_mcePaste&amp;quot; style=&amp;quot;position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;&amp;quot;&amp;gt;&amp;amp;lt;/IfModule&amp;amp;gt;&amp;lt;/div&amp;gt;<br />&amp;lt;pre&amp;gt;&amp;amp;lt;IfModule alias_module&amp;amp;gt;<br />#<br /># Aliases: Add here as many aliases as you need (with no limit). The format is<br /># Alias fakename realname<br />#<br /># Note that if you include a trailing / on fakename then the server will<br /># require it to be present in the URL.  So &amp;quot;/icons&amp;quot; isn&#39;t aliased in this<br /># example, only &amp;quot;/icons/&amp;quot;.  If the fakename is slash-terminated, then the<br /># realname must also be slash terminated, and if the fakename omits the<br /># trailing slash, the realname must also omit it.<br />#<br /># We include the /icons/ alias for FancyIndexed directory listings.  If<br /># you do not use FancyIndexing, you may comment this out.<br />#<br />#Alias /icons/ &amp;quot;/usr/share/apache2/icons/&amp;quot;<br /><br />&amp;amp;lt;Directory &amp;quot;/usr/share/apache2/icons&amp;quot;&amp;amp;gt;<br />    Options Indexes MultiViews<br />    AllowOverride None<br />    Order allow,deny<br />    Allow from all<br />&amp;amp;lt;/Directory&amp;amp;gt;<br /><br />&amp;amp;lt;/IfModule&amp;amp;gt;&amp;lt;/pre&amp;gt;<br />&amp;lt;p&amp;gt;All you need to do is change the line:&amp;lt;/p&amp;gt;<br />&amp;lt;pre style=&amp;quot;color: #000000; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; margin: 8px;&amp;quot;&amp;gt;Options Indexes MultiViews&amp;lt;/pre&amp;gt;<br />&amp;lt;p&amp;gt;To:&amp;lt;/p&amp;gt;<br />&amp;lt;pre style=&amp;quot;color: #000000; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; margin: 8px;&amp;quot;&amp;gt;Options -Indexes MultiViews&amp;lt;/pre&amp;gt;<br />&amp;lt;p&amp;gt;Now that annoying directory listing will no longer appear.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Note: &amp;lt;/strong&amp;gt;You could also comment out (or delete) these lines, it should all have the same effect except that all links to the icons directory would become invalid and may break some of the default Apache error pages.&amp;lt;/p&amp;gt;</description>
			<pubDate>Wed, 13 Oct 2010 12:07:00 +0100</pubDate>
			
			
			<guid>http://www.i-lateral.com/tutorials/disabling-the-icons-folder-on-an-ubuntu-web-server/</guid>
		</item>
		
		<item>
			<title>Integrating a Windows VM on VirtualBox with the host system</title>
			<link>http://www.i-lateral.com/tutorials/integrating-a-windows-vm-on-virtualbox-with-the-host-system/</link>
			<description>&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;http://www.virtualbox.org/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;VirtualBox&amp;lt;/a&amp;gt; is brilliant (and Open Source) Virtualization software, produced by Sun. I use VirtualBox regularly to test out systems, different operating systems or web sites and applications in different browsers and environments. Whenever I use it however I always seem to forget this one step, so it is worth noting it down.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;By default, when you create a Windows VM in VirtualBox, it is independent of the host system. It is impossible to share files, and when you full screen the VM, the resolution doesn&#39;t change, you just get black borders around it.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Its actually quite easy to get this working. Once your VM is running, just  click Devices -&amp;amp;gt; Install Guest Additions. This will mount a CD and autorun an installer. Just step through the installer, then re-boot the system. When it comes back online, you will now be able to map network drives to your shared folders and the VM&#39;s resolution will change when you run it full screen.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Like I said, nice and simple! :)&amp;lt;/p&amp;gt;</description>
			<pubDate>Wed, 28 Apr 2010 23:20:00 +0100</pubDate>
			
			
			<guid>http://www.i-lateral.com/tutorials/integrating-a-windows-vm-on-virtualbox-with-the-host-system/</guid>
		</item>
		
		<item>
			<title>Getting an image from a sub level pages top level parent.</title>
			<link>http://www.i-lateral.com/tutorials/getting-an-image-from-a-sub-level-pages-top-level-parent/</link>
			<description>&amp;lt;p&amp;gt;Quite a simple one this time, but something I feel is worth posting up. On a recent project, I needed to add the ability for the site editors to be able attach an image to any page on the site that sits at the root level of the Site Tree. Any children (grandchildren, etc) of these pages however had to also inherit this image.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;After a bit of searching, I found you could easily do this using the Level() method. Here is how I went about this: &amp;lt;/p&amp;gt;<br />&amp;lt;h2&amp;gt;Page class&amp;lt;/h2&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;pre&amp;gt;class Page extends SiteTree {<br />    public static $has_one = array(<br />        &#39;HeaderImage&#39; =&amp;amp;gt; &#39;Image&#39;<br />    );<br /><br />    public function getCMSFields() {<br />        $fields = parent::getCMSFields();<br /><br />        $fields-&amp;amp;gt;addFieldToTab(&#39;Root.Content.Misc&#39;, new ImageField(&#39;HeaderImage&#39;,&#39;Image to appear in header&#39;));<br /><br />        return $fields;<br />    }<br />}&amp;lt;/pre&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Now this relationship has been added, and the new field added to the CMS, run a /dev/build/ and rebuild the database.&amp;lt;/p&amp;gt;<br />&amp;lt;h2&amp;gt;Your Template&amp;lt;/h2&amp;gt;<br />&amp;lt;p&amp;gt;Now you can go about attaching images to your top level pages. Once you have done this, you can then get all children of that page to inherit the image by adding the following to your template:&amp;lt;/p&amp;gt;<br />&amp;lt;h3&amp;gt;To render a complete image tag:&amp;lt;/h3&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;pre&amp;gt;$Level(1).HeaderImage&amp;lt;/pre&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;<br />&amp;lt;h3&amp;gt;To just get the URL:&amp;lt;/h3&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;pre&amp;gt;$Level(1).HeaderImage.URL&amp;lt;/pre&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;<br />&amp;lt;h3/&amp;gt;<br />&amp;lt;h3&amp;gt;To render as a background image:&amp;lt;/h3&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;pre&amp;gt;&amp;amp;lt;div style=&amp;quot;background-image: url(http://www.i-lateral.com/&#39;(1).HeaderImage.URL&#39;)&amp;quot;&amp;amp;gt;<br />    ...<br />&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/pre&amp;gt;<br />&amp;lt;hr/&amp;gt;&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;That is pretty much it. Using the Level() method retrieves a full page object for that level, so it is also possible to use methods and variables such as:&amp;lt;/p&amp;gt;<br />&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;line-height: 13px;&amp;quot;&amp;gt;Title&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;<br />&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;line-height: 13px;&amp;quot;&amp;gt;Link&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;<br />&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;line-height: 13px;&amp;quot;&amp;gt;URL&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;<br />&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;line-height: 13px;&amp;quot;&amp;gt;etc...&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;<br />&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;</description>
			<pubDate>Thu, 04 Mar 2010 23:25:00 +0000</pubDate>
			
			
			<guid>http://www.i-lateral.com/tutorials/getting-an-image-from-a-sub-level-pages-top-level-parent/</guid>
		</item>
		
		<item>
			<title>Silverstripe DataObjectSet and Templates</title>
			<link>http://www.i-lateral.com/tutorials/silverstripe-dataobjectset-and-templates/</link>
			<description>&amp;lt;p&amp;gt;For some reason, I always forget how to generate a custom DataObjectSet in a Silverstripe method, that I can then return to my template to correctly render in a control loop. Because of this, I am going to write an example tutorial, using my Twitter RSS feed and SimpleXML (which should be part of the PHP5 core for most installs) as an example.&amp;lt;/p&amp;gt;<br />&amp;lt;h2&amp;gt;Step 1: Setting up your model and controller.&amp;lt;/h2&amp;gt;<br />&amp;lt;p&amp;gt;In this tutorial, I am going to add my Twitter feed to my Page class. That way it can appear on all pages, and be available to child classes as well.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;To do this I will first add a TwitterURL field to my model, as well as the relevant fields to the CMS:&amp;lt;/p&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;pre&amp;gt;class Page extends SiteTree {&amp;lt;br /&amp;gt; &amp;amp;nbsp;static $db = array(&amp;lt;br /&amp;gt;  &amp;amp;nbsp; &#39;TwitterURL&#39;&amp;lt;span style=&amp;quot;white-space: pre;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;=&amp;amp;gt; &#39;Text&#39;&amp;lt;br /&amp;gt;  );&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;  public function getCMSFields() {&amp;lt;br /&amp;gt;    $fields = parent::getCMSFields();&amp;lt;br /&amp;gt;    $fields-&amp;amp;gt;addFieldToTab(&#39;Root.Content.Misc&#39;,new TextField(&#39;TwitterURL&#39;, &#39;Twitter URL&#39;));&amp;lt;br /&amp;gt;    return $fields;&amp;lt;br /&amp;gt;  }&amp;lt;br /&amp;gt;}&amp;lt;/pre&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;p&amp;gt;Next, I will add the method I will call in my template to my controller:&amp;lt;/p&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;pre&amp;gt;class Page_Controller extends ContentController {&amp;lt;br /&amp;gt;  public function init() {&amp;lt;br /&amp;gt;    parent::init();&amp;lt;br /&amp;gt;  }&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;  public function getTwitterFeed($limit = 5) {&amp;lt;br /&amp;gt;    // More to go here&amp;lt;br /&amp;gt;  }&amp;lt;br /&amp;gt;}&amp;lt;/pre&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;h2&amp;gt;Step 2: Getting our RSS feed.&amp;amp;nbsp;&amp;lt;/h2&amp;gt;<br />&amp;lt;p&amp;gt;Now the basic setup is complete, now we need to write some code to extract our Twitter feed and then loop through each posted item in the feed channel. Here is how we would do this using SimpleXML (there are other methods of doing something similar, including PHP Dom and SimplePie):&amp;lt;/p&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;pre&amp;gt;class Page_Controller extends ContentController {&amp;lt;br /&amp;gt;  ...&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;  public function getTwitterFeed($limit = 5) {&amp;lt;br /&amp;gt;    $Twitter = simplexml_load_file($this-&amp;amp;gt;TwitterURL);&amp;lt;br /&amp;gt;    $i = 0;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;    foreach($Twitter-&amp;amp;gt;channel-&amp;amp;gt;item as $item) {&amp;lt;br /&amp;gt;      if($i &amp;amp;lt; $limit) {&amp;lt;br /&amp;gt;        // Some data object stuff will go here shortly&amp;lt;br /&amp;gt;      }&amp;lt;br /&amp;gt;    }&amp;lt;br /&amp;gt;  }&amp;lt;br /&amp;gt;}&amp;lt;/pre&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;p&amp;gt;Admitidly this wont do much at the moment, just loop through the items in your RSS feed until you the end, or the loop reaches the limit set by $limit.&amp;lt;/p&amp;gt;<br />&amp;lt;h2&amp;gt;Step 3: Setting up our DataObjectSet&amp;lt;/h2&amp;gt;<br />&amp;lt;p&amp;gt;Now we have our loop, the interesting bit can begin. Now we need to create a new DataObjectSet and for each item, push an array of data to it. This will be the data that is then sent to the template for rendering.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Now you need to alter your getTwitterFeed() method as below:&amp;lt;/p&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;pre&amp;gt;class Page_Controller extends ContentController {&amp;lt;br /&amp;gt;  ...&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;  public function getTwitterFeed($limit = 5) {&amp;lt;br /&amp;gt;    $Twitter = simplexml_load_file($this-&amp;amp;gt;TwitterURL);&amp;lt;br /&amp;gt;    $result = new DataObjectSet();&amp;lt;br /&amp;gt;    $i = 0;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;    foreach($Twitter-&amp;amp;gt;channel-&amp;amp;gt;item as $item) {&amp;lt;br /&amp;gt;      if($i &amp;amp;lt; $limit) {&amp;lt;br /&amp;gt;        // To retrieve the publish date in a format that Silverstripe&amp;lt;br /&amp;gt;        // will be able to play with, we need to convert it to a date object.&amp;lt;br /&amp;gt;        $Date = new Date(&#39;Date&#39;);&amp;lt;br /&amp;gt;        $Date-&amp;amp;gt;setValue((string)$item-&amp;amp;gt;pubDate);&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;        // Put info from RSS into an Array, then push into $result&amp;lt;br /&amp;gt;        $result-&amp;amp;gt;push(new ArrayData(array(&amp;lt;br /&amp;gt;          &#39;Title&#39; =&amp;amp;gt; (string)$item-&amp;amp;gt;title,&amp;lt;br /&amp;gt;          &#39;Date&#39; =&amp;amp;gt; $Date&amp;lt;br /&amp;gt;        )));&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;        $i++;&amp;lt;br /&amp;gt;      }&amp;lt;br /&amp;gt;    }&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;    return $result;&amp;lt;br /&amp;gt;  }&amp;lt;br /&amp;gt;}&amp;lt;/pre&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;p&amp;gt;Now what is happening is that we create a new DataObjectSet called $result. For each iteration of the RSS feed, we take the title and date from the feed, convert and cast then as necessary then put that into an array. Silverstripe requires that this data be formatted using an ArrayData object, so we use that first, before dding the data to our DataObjectSet.&amp;lt;/p&amp;gt;<br />&amp;lt;p&amp;gt;Finally we return the completed DataObjectSet, from this example, the variables $Title and $Date will be available in your control loop.&amp;lt;/p&amp;gt;<br />&amp;lt;h2&amp;gt;Step 4: Setting up your template.&amp;lt;/h2&amp;gt;<br />&amp;lt;p&amp;gt;Now we have all the data in in right format, the final step is to render it in your template. In order to render each tweet as a paragraph, you would do:&amp;lt;/p&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;pre&amp;gt;&amp;amp;lt;% control getTwitterFeed %&amp;amp;gt;<br />  &amp;amp;lt;p&amp;amp;gt;<br />    $Title&amp;amp;lt;br/&amp;amp;gt;<br />    Posted: $Date.Ago<br />  &amp;amp;lt;/p&amp;amp;gt;<br />&amp;amp;lt;% end_control %&amp;amp;gt;&amp;lt;/pre&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;p&amp;gt;By default, this method will display the 5 most recent tweets. If you wanted to show a different number, for example 10, you could use:&amp;lt;/p&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;pre&amp;gt;&amp;amp;lt;% control getTwitterFeed(10) %&amp;amp;gt;&amp;lt;br /&amp;gt;  &amp;amp;lt;p&amp;amp;gt;&amp;lt;br /&amp;gt;    $Title&amp;amp;lt;br/&amp;amp;gt;&amp;lt;br /&amp;gt;    Posted: $Date.Ago&amp;lt;br /&amp;gt;  &amp;amp;lt;/p&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;lt;% end_control %&amp;amp;gt;&amp;lt;/pre&amp;gt;<br />&amp;lt;hr /&amp;gt;<br />&amp;lt;p&amp;gt;Thats it, if you want to include additional info, like Link and Description, you simply have to add those items to your array in your method. These will then be available to you in your template.&amp;lt;/p&amp;gt;</description>
			<pubDate>Wed, 03 Feb 2010 12:29:00 +0000</pubDate>
			
			
			<guid>http://www.i-lateral.com/tutorials/silverstripe-dataobjectset-and-templates/</guid>
		</item>
		

	</channel>
</rss>
