<?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> blog</title>
		<link>http://www.mikenovember.com/blog/</link>
		<atom:link href="http://www.mikenovember.com/blog/" rel="self" type="application/rss+xml" />
		<description></description>

		
		<item>
			<title>Updates for Advanced Reports and Simple Wiki modules</title>
			<link>http://www.mikenovember.com/blog/updates-for-advanced-reports-and-simple-wiki-modules/</link>
			<description>&amp;lt;p&amp;gt;Have added some new functionality for the advanced reports module that allows for late binding data into the conditions used in the report. This is through the use of either strtotime: last sunday|Y-m-d H:i:s for doing time calcs, or using param: ParamName for using parameters specified in either the _GET array, or via the default parameter listing for the report (to provide a fallback). &amp;lt;a href=&amp;quot;https://github.com/nyeholt/silverstripe-advancereports&amp;quot;&amp;gt;https://github.com/nyeholt/silverstripe-advancereports&amp;lt;/a&amp;gt; Also, our new guy Shea has been doing some cool stuff on the simplewiki module to add in some much much nicer file upload/linking and page linking that uses autocomplete for selecting items instead of the nasty nasty hacky stuff that was there previously. VERY much nicer to use now &amp;lt;a href=&amp;quot;https://github.com/nyeholt/silverstripe-simplewiki&amp;quot;&amp;gt;https://github.com/nyeholt/silverstripe-simplewiki&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;</description>
			<pubDate>Fri, 18 Nov 2011 16:38:53 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/updates-for-advanced-reports-and-simple-wiki-modules/</guid>
		</item>
		
		<item>
			<title>Clean content</title>
			<link>http://www.mikenovember.com/blog/clean-content/</link>
			<description>&amp;lt;p&amp;gt;I recently slapped together a &amp;#39;Clean Content&amp;#39; module for SS pages that allows you to have HTML Tidy and/or Purify run on content. This can be done optionally on save, or from a template call to $Clean(ContentFieldName) which will run the appropriate cleaning option. Note that it&amp;#39;ll need the tidy plugin enabled for that - it ships with the HTML purify extension.&amp;lt;/p&amp;gt;</description>
			<pubDate>Thu, 22 Sep 2011 11:00:54 +1000</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/clean-content/</guid>
		</item>
		
		<item>
			<title>Just a couple of things</title>
			<link>http://www.mikenovember.com/blog/just-a-couple-of-things/</link>
			<description>&amp;lt;p&amp;gt;A couple of new things - I&amp;#39;ve added a new SilverStripe module for defining APIs a little bit more specifically than dealing with the rest service that comes out of the box. Instead of being an XML/JSON wrapper around data objects, it&amp;#39;s an XML/JSON wrapper around service classes (business logic) to allow you to be specific about what end users get. It&amp;#39;s also meant to encourage re-usable service layer code, that can be used from your controller layer too.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[WebServices module](&amp;lt;a href=&amp;quot;https://github.com/nyeholt/silverstripe-webservices&amp;quot;&amp;gt;https://github.com/nyeholt/silverstripe-webservices&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;I&amp;#39;ve also been playing around with [Porthole](&amp;lt;a href=&amp;quot;http://ternarylabs.github.com/porthole/&amp;quot;&amp;gt;http://ternarylabs.github.com/porthole/&amp;lt;/a&amp;gt;) for doing cross-frame-domain javascript communication (more on that project another time). It&amp;#39;s a little barebones for what I need it for, so I wrote a wrapper around it to enable some more structured communication. This allows for registering a handler class (with methods) to handle the incoming communication, and for sending communication to specific methods of bound handlers. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// this call must be made, as it sets up the appropriate data comms &amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// to the child frame&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;ProxyFrameManager.listenTo(&amp;#39;FrameName&amp;#39;);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// to send to the child&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;ProxyFrameManager.send(&amp;#39;FrameName&amp;#39;, &amp;#39;methodName&amp;#39;, &amp;#39;param1&amp;#39;, {and: &amp;#39;so on&amp;#39;});&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Then in the child... &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;ProxyFrameManager.listenTo(&amp;#39;$ParentPageProxyUrl&amp;#39;, {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;    methodName: function (param, objectParam) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// do something to handle the call here&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;    }&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;});&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[Proxy Frame Manager](&amp;lt;a href=&amp;quot;https://github.com/nyeholt/proxy-frame-manager&amp;quot;&amp;gt;https://github.com/nyeholt/proxy-frame-manager&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;A demo can be [found here](&amp;lt;a href=&amp;quot;http://demo.mikenovember.com/proxy-frame/parent/&amp;quot;&amp;gt;http://demo.mikenovember.com/proxy-frame/parent/&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;</description>
			<pubDate>Tue, 16 Aug 2011 22:29:20 +1000</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/just-a-couple-of-things/</guid>
		</item>
		
		<item>
			<title>An update to the Pixlr module</title>
			<link>http://www.mikenovember.com/blog/an-update-to-the-pixlr-module/</link>
			<description>&amp;lt;p&amp;gt;One thing I&amp;#39;ve regularly found missing from SilverStripe is the ability to paste a screenshot directly into the CMS. Of course, that&amp;#39;s not yet possible using JS or Flash directly, but Java does give you the option to access the clipboard, and using an applet, I&amp;#39;ve hooked this capability into the CMS. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;![Paste an image](assets/pasted/pixlr-paste-edit.png)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It&amp;#39;s not as fluent as clicking the wysiwyg and hitting Ctrl+V (though I&amp;#39;m sure someone could script those actions...), but clicking ctrl+shift+V when the &amp;quot;Insert Image&amp;quot; toolbar is open will paste to the applet, then you need to manually click the &amp;#39;Upload&amp;#39; button. This will select the image for you in the list on the right, so you then can just click &amp;quot;Insert Image&amp;quot;. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The other nice thing is being able to hook into the Pixlr editor. If you have the &amp;#39;and Edit&amp;#39; box checked, then the pixlr editor will be launched after clicking upload, allowing you to modify the image immediately. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;![Editing with pixlr](assets/pasted/edit-with-pixlr.png)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;You can get it from [Github](&amp;lt;a href=&amp;quot;https://github.com/nyeholt/silverstripe-pixlr&amp;quot;&amp;gt;https://github.com/nyeholt/silverstripe-pixlr&amp;lt;/a&amp;gt;). It&amp;#39;s currently self signed, so you&amp;#39;ll get a java nag warning, and I&amp;#39;ve found that it performs terribly on OpenJDK on Ubuntu (though no problems with the Sun JRE). So let me know if you have any specific issues.&amp;lt;/p&amp;gt;</description>
			<pubDate>Sat, 23 Jul 2011 22:43:09 +1000</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/an-update-to-the-pixlr-module/</guid>
		</item>
		
		<item>
			<title>Mostly quiet</title>
			<link>http://www.mikenovember.com/blog/mostly-quiet/</link>
			<description>&amp;lt;p&amp;gt;Not been a great deal going on other than Work and Real Life lately. I was up in Brisbane for a meetup hosted by the guys at [Hive](&amp;lt;a href=&amp;quot;http://hivewebhosting.com/webdesign/&amp;quot;&amp;gt;http://hivewebhosting.com/webdesign/&amp;lt;/a&amp;gt;), which was awesome, and will be up in Sydney at the end of the month for a SydneyPHP meetup (more details to come). &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;In the meantime, [check this out](&amp;lt;a href=&amp;quot;http://blog.tojicode.com/2011/05/ios-rage-rendered-with-webgl.html&amp;quot;&amp;gt;http://blog.tojicode.com/2011/05/ios-rage-rendered-with-webgl.html&amp;lt;/a&amp;gt;) - my JS fingers are getting itchy.&amp;lt;/p&amp;gt;</description>
			<pubDate>Tue, 17 May 2011 08:56:45 +1000</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/mostly-quiet/</guid>
		</item>
		
		<item>
			<title>Some presentations</title>
			<link>http://www.mikenovember.com/blog/some-presentations/</link>
			<description>&amp;lt;p&amp;gt;Thanks to everyone who turned up for the meetup last week. Here&amp;#39;s some links to the presentations that were given:&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[Development overview](&amp;lt;a href=&amp;quot;http://prezi.com/rblvpg3t-qh2/silverstripe-meetup-march-2011-housekeeping/&amp;quot;&amp;gt;http://prezi.com/rblvpg3t-qh2/silverstripe-meetup-march-2011-housekeeping/&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[Sebar - a deployment tool for SilverStripe](&amp;lt;a href=&amp;quot;http://prezi.com/jr5-clx4qehk/silverstripe-meetup-march-2011-sebar/&amp;quot;&amp;gt;http://prezi.com/jr5-clx4qehk/silverstripe-meetup-march-2011-sebar/&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[SilverStripe 3.0 overview](&amp;lt;a href=&amp;quot;http://prezi.com/oxmtf2fz7xzl/silverstripe-meetup-march-2011-silverstripe-30/&amp;quot;&amp;gt;http://prezi.com/oxmtf2fz7xzl/silverstripe-meetup-march-2011-silverstripe-30/&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;</description>
			<pubDate>Thu, 24 Mar 2011 05:02:58 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/some-presentations/</guid>
		</item>
		
		<item>
			<title>An introduction to SilverStripe</title>
			<link>http://www.mikenovember.com/blog/an-introduction-to-silverstripe/</link>
			<description>&amp;lt;p&amp;gt;I just found the link to some slides that Andrew Short prepared with a bit of input from myself that he gave at the Sydney PHP User Group meetup a few months ago. If I can make it, I&amp;#39;ll probably roll them out at the Melbourne User Group soon...&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[Slides on slideshare](&amp;lt;a href=&amp;quot;http://www.slideshare.net/ajshort/silverstripe-from-a-developers-perspective&amp;quot;&amp;gt;http://www.slideshare.net/ajshort/silverstripe-from-a-developers-perspective&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;</description>
			<pubDate>Mon, 14 Mar 2011 22:40:58 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/an-introduction-to-silverstripe/</guid>
		</item>
		
		<item>
			<title>Adding scheduling to data objects with the Queued Jobs module</title>
			<link>http://www.mikenovember.com/blog/adding-scheduling-to-data-objects-with-the-queued-jobs-module/</link>
			<description>&amp;lt;p&amp;gt;I&amp;#39;ve added a new piece of code to the Queued Jobs module that allows you to quickly add scheduling to any data object. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It&amp;#39;s very straight forward to add&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;* Install the [queuedjobs module](&amp;lt;a href=&amp;quot;https://github.com/nyeholt/silverstripe-queuedjobs&amp;quot;&amp;gt;https://github.com/nyeholt/silverstripe-queuedjobs&amp;lt;/a&amp;gt;) and configure the appropriate cronjob&amp;lt;br /&amp;gt;* Add the ScheduledExecutionExtension to your data object that can have scheduled execution - `Object::add_extension(&amp;#39;MyDataObject&amp;#39;, &amp;#39;ScheduledExecutionExtension&amp;#39;);`&amp;lt;br /&amp;gt;* In your _MyDataObject_ class, define the method _onScheduledExecution()_. This is called at the appropriate scheduled time. &amp;lt;br /&amp;gt;* Run dev/build and go into your SilverStripe backend. Any object of type _MyDataObject_ should now have a &amp;quot;Schedule&amp;quot; tab, which allows you to enter a schedule for having _onScheduledExecution()_ called. Set the &amp;quot;First Execution&amp;quot; date some time in the past if you want it to be immediately executed, or for a time in the future.&amp;lt;/p&amp;gt;</description>
			<pubDate>Tue, 22 Feb 2011 04:35:36 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/adding-scheduling-to-data-objects-with-the-queued-jobs-module/</guid>
		</item>
		
		<item>
			<title>Why your dates in SilverStripe pages never show up as expected</title>
			<link>http://www.mikenovember.com/blog/why-your-dates-in-silverstripe-pages-never-show-up-as-expected/</link>
			<description>&amp;lt;p&amp;gt;In SilverStripe, users can select their locale, along with specifying a default date and time format to use. This should also be replicated throughout the site, but if you&amp;#39;re forgetful like me, sometimes it won&amp;#39;t display as expected. The secret? Making sure you set the user&amp;#39;s preference for the request!&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;In Page_Controller::init() simply add&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$member = Member::currentUser();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if(!empty($member-&amp;amp;amp;gt;Locale)) i18n::set_locale($member-&amp;amp;amp;gt;Locale);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if(!empty($member-&amp;amp;amp;gt;DateFormat)) i18n::set_date_format($member-&amp;amp;amp;gt;DateFormat);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if(!empty($member-&amp;amp;amp;gt;TimeFormat)) i18n::set_time_format($member-&amp;amp;amp;gt;TimeFormat);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;</description>
			<pubDate>Mon, 07 Feb 2011 18:09:50 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/why-your-dates-in-silverstripe-pages-never-show-up-as-expected/</guid>
		</item>
		
		<item>
			<title>Some handy git config bits and pieces</title>
			<link>http://www.mikenovember.com/blog/some-handy-git-config-bits-and-pieces/</link>
			<description>&amp;lt;p&amp;gt;Have finally updated to Ubuntu 10.10, taking the opportunity to completely clean out. Of course, this means reconfiguring everything - these two git settings are the ones that I most missed &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The following adds an indication on your command-line as to the branch you are currently on. Massively helpful. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;~~~&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;parse_git_branch() {&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;    git branch 2&amp;amp;amp;gt; /dev/null | sed -e &amp;#39;/^[^*]/d&amp;#39; -e &amp;#39;s/* \(.*\)/(\1)/&amp;#39;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;}&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;export PS1=&amp;quot;\[\033[00m\]\u@\h\[\033[01;34m\] \w \[\033[31m\]\$(parse_git_branch) \[\033[00m\]$\[\033[00m\] &amp;quot;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;~~~&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The next simply sets a global config for colours when doing things like diff and status&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;~~~&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;git config --global color.ui &amp;quot;auto&amp;quot;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;~~~&amp;lt;/p&amp;gt;</description>
			<pubDate>Tue, 11 Jan 2011 19:30:35 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/some-handy-git-config-bits-and-pieces/</guid>
		</item>
		
		<item>
			<title>Dependency Injector update</title>
			<link>http://www.mikenovember.com/blog/dependency-injector-update/</link>
			<description>&amp;lt;p&amp;gt;I&amp;#39;ve been playing around adding some [dependency injection](&amp;lt;a href=&amp;quot;http://github.com/nyeholt/injector/wiki&amp;quot;&amp;gt;http://github.com/nyeholt/injector/wiki&amp;lt;/a&amp;gt;) to SilverStripe off and on recently. One of the problems is where to actually put the configuration you need, and how to ensure the loading of the services occurs in the expected order. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The default mechanism in SilverStripe is to put things in the _config.php file for a given module. Rather than come up with something new, I decided to stick with the same methodology. However, that presents a new issue - if you specify a service configuration there that is meant to override a service configuration defined in another module, the other module might actually load AFTER yours, meaning it will take that specification. One way to enforce a module to appear first is to provide a &amp;#39;priority&amp;#39; alongside the service spec. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$config = array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;src&amp;#39; =&amp;amp;amp;gt; TEST_SERVICES.&amp;#39;/SampleService.php&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;priority&amp;#39; =&amp;amp;amp;gt; 10,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;)&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$injector-&amp;amp;amp;gt;load($config);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$config = array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;src&amp;#39; =&amp;amp;amp;gt; TEST_SERVICES.&amp;#39;/AnotherService.php&amp;#39;, &amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;id&amp;#39; =&amp;amp;amp;gt; &amp;#39;SampleService&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;priority&amp;#39; =&amp;amp;amp;gt; 1,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;)&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$injector-&amp;amp;amp;gt;load($config);&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;In this example, previously the injector would have used the AnotherService class whenever SampleService was referred to. However, because we&amp;#39;ve explicitly stated that a priority of &amp;amp;amp;gt; 10 is needed to replace it, it will NOT have its definition changed.&amp;lt;/p&amp;gt;</description>
			<pubDate>Wed, 05 Jan 2011 04:33:26 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/dependency-injector-update/</guid>
		</item>
		
		<item>
			<title>Building a development environment</title>
			<link>http://www.mikenovember.com/blog/building-a-development-environment/</link>
			<description>&amp;lt;p&amp;gt;I&amp;#39;ve just been through the process of setting up a development environment in a VM image, suitable for getting in and working with SilverStripe projects. I&amp;#39;ll be making the VM available (though where I&amp;#39;m not too sure just yet), but in the meantime, figured I&amp;#39;d dump a list of the commands I run through. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;This is Ubuntu 10.10, though the equivalent for other OSes should work (except of course Windows variants)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;br /&amp;gt;apt-get install apache2  php5  php5-sqlite  php5-tidy  php5-ldap  php5-mcrypt  php5-geoip  php5-curl  php5-xdebug  php5-pspell  php5-mysql  php5-gd  php5-dev  build-essential  git  gitk  meld&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;# Default mysql root pass is p455 in the VM&amp;lt;br /&amp;gt;apt-get install mysql-server-5.1&amp;lt;br /&amp;gt;apt-get install subversion&amp;lt;br /&amp;gt;# Note that the following need the &amp;quot;Partner&amp;quot; repositories enabled for ubuntu&amp;lt;br /&amp;gt;apt-get install sun-java6-jre&amp;lt;br /&amp;gt;apt-get install sun-java6-jdk&amp;lt;br /&amp;gt;# Download the netbeans beta&amp;lt;br /&amp;gt;chmod +x netbeans-7.0beta-ml-php-linux.sh &amp;lt;br /&amp;gt;./netbeans-7.0beta-ml-php-linux.sh &amp;lt;br /&amp;gt;cd /etc/apache2/&amp;lt;br /&amp;gt;a2enmod rewrite&amp;lt;br /&amp;gt;apache2ctl restart&amp;lt;br /&amp;gt;# Changed the default site config - see below for that&amp;lt;br /&amp;gt;vim sites-enabled/000-default &amp;lt;br /&amp;gt;apt-get install php-pear&amp;lt;br /&amp;gt;pear channel-discover pear.phpunit.de&amp;lt;br /&amp;gt;pear channel-discover components.ez.no&amp;lt;br /&amp;gt;pear channel-discover pear.symfony-project.com&amp;lt;br /&amp;gt;# Need specific version of phpunit&amp;lt;br /&amp;gt;pear install phpunit/PHPUnit-3.4.0&amp;lt;br /&amp;gt;pear channel-discover pear.phing.info&amp;lt;br /&amp;gt;pear install phing/phing&amp;lt;br /&amp;gt;# Need to enable remote debugging, see below for config&amp;lt;br /&amp;gt;vim /etc/php5/conf.d/xdebug.ini&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The 000-default config file: &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: xml&amp;quot;&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;virtualhost&amp;amp;gt;&amp;lt;br /&amp;gt;        ServerAdmin webmaster@localhost&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;        DocumentRoot /home/developer/www&amp;lt;br /&amp;gt;        &amp;amp;lt;directory/&amp;amp;gt;&amp;lt;br /&amp;gt;                Options FollowSymLinks  &amp;lt;br /&amp;gt;                AllowOverride None&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;        &amp;amp;lt;directory/&amp;amp;gt;&amp;lt;br /&amp;gt;                Options Indexes FollowSymLinks MultiViews&amp;lt;br /&amp;gt;                AllowOverride All&amp;lt;br /&amp;gt;                Order allow,deny&amp;lt;br /&amp;gt;                allow from all&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;        ErrorLog ${APACHE_LOG_DIR}/error.log&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;        # Possible values include: debug, info, notice, warn, error, crit,&amp;lt;br /&amp;gt;        # alert, emerg.&amp;lt;br /&amp;gt;        LogLevel warn&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;        CustomLog ${APACHE_LOG_DIR}/access.log combined&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;/virtualhost&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;And the xdebug.conf file&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;zend_extension=/usr/lib/php5/20090626+lfs/xdebug.so&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;xdebug.remote_enable=on&amp;lt;br /&amp;gt;xdebug.remote_handler=dbgp&amp;lt;br /&amp;gt;xdebug.remote_host=localhost&amp;lt;br /&amp;gt;xdebug.remote_port=9000&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;</description>
			<pubDate>Tue, 14 Dec 2010 05:45:53 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/building-a-development-environment/</guid>
		</item>
		
		<item>
			<title>Some SilverStripe meetups</title>
			<link>http://www.mikenovember.com/blog/some-silverstripe-meetups/</link>
			<description>&amp;lt;p&amp;gt;Not much going on at the moment outside of some client development work. A couple of projects that may throw up some interesting modules, but that will have to wait for a few weeks to  see what&amp;#39;s produced. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If you&amp;#39;re in Sydney, there&amp;#39;s a [PHP User Group meetup](&amp;lt;a href=&amp;quot;http://sydphp.org/events/?event_id=7&amp;quot;&amp;gt;http://sydphp.org/events/?event_id=7&amp;lt;/a&amp;gt;) that&amp;#39;s showcasing SilverStripe. Andrew Short will be there to give a developer&amp;#39;s insight to the platform, and Shane Weddell will be there to give a more business spin to the whole show. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Also, [SilverStripe Australia is having a meetup](&amp;lt;a href=&amp;quot;http://www.meetup.com/silverstripe-australia/&amp;quot;&amp;gt;http://www.meetup.com/silverstripe-australia/&amp;lt;/a&amp;gt;) to celebrate the end of year. There&amp;#39;ll be a few things spoken about, but it will mostly be a case of a few beers and unwinding (at least, that&amp;#39;s my plan!). I&amp;#39;ll have a couple of module things to talk about, and we&amp;#39;ve got a partner giving an overview of migrating a site to SilverStripe from MySource Matrix. Come along!&amp;lt;/p&amp;gt;</description>
			<pubDate>Mon, 22 Nov 2010 07:27:20 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/some-silverstripe-meetups/</guid>
		</item>
		
		<item>
			<title>A small testing gotcha in SilverStripe</title>
			<link>http://www.mikenovember.com/blog/a-small-testing-gotcha-in-silverstripe/</link>
			<description>&amp;lt;p&amp;gt;When making sites that need a specific initial structure in place, I make use of requireDefaultRecords to create said structure. It makes things a lot easier for other developers working on the same project to have these things in automatically created and in place when they run dev/build after updating. While very handy for getting things up and running, there&amp;#39;s a slight catch - requireDefaultRecords, by default, isn&amp;#39;t run when you execute a unit test. This means that any functionality that you have that relies on these structures existing will likely break, with often confusing results. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;How do you get around this? Make sure that the types you want requireDefaultRecords run for is specified!&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function  setUpOnce() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; parent::setUpOnce();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; $this-&amp;amp;amp;gt;requireDefaultRecordsFrom[] = &amp;#39;Page&amp;#39;;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;</description>
			<pubDate>Wed, 10 Nov 2010 00:51:17 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/a-small-testing-gotcha-in-silverstripe/</guid>
		</item>
		
		<item>
			<title>Simple frontend editing</title>
			<link>http://www.mikenovember.com/blog/simple-frontend-editing/</link>
			<description>&amp;lt;p&amp;gt;There&amp;#39;s been some discussion on the SilverStripe development list about some changes coming in SS3.0, one of which will be a frontend editing UI. Of course these plans are very much plans for the moment - the proper work of research, prototyping and putting together a clear set of features for such a UI has only just begun, which everyone needs to keep in mind. The more feedback and constructive criticism that goes into the process from those who develop with SS every day will mean that the end result will be better than if there was silence. Given that I&amp;#39;ve had an experimental frontend editing module floating around for about 12 months now, I figured I&amp;#39;d actually set up a demo site that people could play with to see my take on things, and what I&amp;#39;d like to see in future&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[See the demo here](&amp;lt;a href=&amp;quot;http://playground.mikenovember.com/frontend-editing&amp;quot;&amp;gt;http://playground.mikenovember.com/frontend-editing&amp;lt;/a&amp;gt;) - Username: admin password: silverstripe. The db will reset itself once every hour or so, but please don&amp;#39;t ruin it for everyone :). &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Some things to know&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;* Click the &amp;quot;Edit Draft Page&amp;quot; button to edit the content after logging in&amp;lt;br /&amp;gt;* You can edit the current page&amp;#39;s contents, as well as any associated pages being displayed - when outputting a field in a template, it is wrapped in a call to create an editable field if possible. &amp;lt;br /&amp;gt;* Styles can be defined in stylesheets that will appear in the Style... dropdown - these are prefixed with .wysiwyg- and automatically inserted. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Template modifications look like&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: html&amp;quot;&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;div id=&amp;quot;PageContent&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;    $EditableField(Content)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;    &amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;h2&amp;amp;gt;Child pages&amp;amp;lt;/h2&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;p&amp;amp;gt;Just to demonstrate editing other page contents contained in control lists &amp;amp;lt;/p&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;Title&amp;amp;lt;/strong&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;div&amp;amp;gt;$EditableField(Title)&amp;amp;lt;/div&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;Content &amp;amp;lt;/strong&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;div&amp;amp;gt;$EditableField(Content)&amp;amp;lt;/div&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;    &amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;lt;/div&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;This is available via my github account, but is experimental code for now. This DOES NOT have anything to do with the SS3.0 plans at all - this is something that has been sitting around for a while but may prove helpful in getting people thinking about what a proper solution should have (ie, everything that this doesn&amp;#39;t! :)).&amp;lt;/p&amp;gt;</description>
			<pubDate>Fri, 05 Nov 2010 09:39:16 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/simple-frontend-editing/</guid>
		</item>
		
		<item>
			<title>Queued jobs module ready to go</title>
			<link>http://www.mikenovember.com/blog/queued-jobs-module-ready-to-go/</link>
			<description>&amp;lt;p&amp;gt;After much tweaking and stalling, the [QueuedJobs module](&amp;lt;a href=&amp;quot;http://github.com/nyeholt/silverstripe-queuedjobs/&amp;quot;&amp;gt;http://github.com/nyeholt/silverstripe-queuedjobs/&amp;lt;/a&amp;gt;) has been released (and submitted to SilverStripe.org, should be up soon). What does it provide? &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;blockquote&amp;amp;gt;&amp;lt;br /&amp;gt; The Queued Jobs module provides a framework for SilverStripe developers to define long running processes that should be run as background tasks. This asynchronous processing allows users to continue using the system while long running tasks proceed when time permits. It also lets developers set these processes to be executed in the future.&amp;lt;br /&amp;gt;&amp;amp;lt;/blockquote&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;In essence, the goal is to not leave users with a seemingly &amp;#39;hanging&amp;#39; connection that may eventually time out when they trigger an action that might take a while to process. Not many actions in SilverStripe do this, but your site might have particular need for it. Some areas where we&amp;#39;re using it&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;* Generating google sitemap.xml files for sites with hundreds and thousands of pages. &amp;lt;br /&amp;gt;* Publishing large subtrees of pages&amp;lt;br /&amp;gt;* Re-indexing content in systems that use external search engines such as [Solr](&amp;lt;a href=&amp;quot;http://github.com/nyeholt/silverstripe-solr/&amp;quot;&amp;gt;http://github.com/nyeholt/silverstripe-solr/&amp;lt;/a&amp;gt;). &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If you want to test it out, download it from [GitHub](&amp;lt;a href=&amp;quot;http://github.com/nyeholt/silverstripe-queuedjobs/archives/1.0.0&amp;quot;&amp;gt;http://github.com/nyeholt/silverstripe-queuedjobs/archives/1.0.0&amp;lt;/a&amp;gt;) or [SilverStripe.org](&amp;lt;a href=&amp;quot;http://silverstripe.org/modules&amp;quot;&amp;gt;http://silverstripe.org/modules&amp;lt;/a&amp;gt;). After extracting it to the queuedjobs folder, and running dev/build, you&amp;#39;ll need to make sure you have a cronjob setup to run the main processor (preferably as the webserver user). &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;blockquote&amp;amp;gt;&amp;lt;br /&amp;gt;*/1 * * * * php /path/to/silverstripe/sapphire/cli-script.php dev/tasks/ProcessJobQueueTask&amp;lt;br /&amp;gt;*/15 * * * * php /path/to/silverstripe/sapphire/cli-script.php dev/tasks/ProcessJobQueueTask queue=2&amp;lt;br /&amp;gt;&amp;amp;lt;/blockquote&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[See the wiki page](&amp;lt;a href=&amp;quot;http://github.com/nyeholt/silverstripe-queuedjobs/wiki/Installing-and-configuring&amp;quot;&amp;gt;http://github.com/nyeholt/silverstripe-queuedjobs/wiki/Installing-and-configuring&amp;lt;/a&amp;gt;) for more info. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;I recommend you test out the GenerateGoogleSitemapJob to get a feel for what&amp;#39;s going on under the covers (and it actually has a functional benefit!). To create the initial instance, go to &amp;lt;a href=&amp;quot;http://path.to.silverstripe/dev/tasks/CreateDummyJob?name=GenerateGoogleSitemapJob&amp;quot;&amp;gt;http://path.to.silverstripe/dev/tasks/CreateDummyJob?name=GenerateGoogleSitemapJob&amp;lt;/a&amp;gt; which will create it (it will recreate itself as it processes. To make things easier, I&amp;#39;ll step through the code so you get an idea of what&amp;#39;s important when doing your own jobs&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function __construct() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;pagesToProcess = DB::query(&amp;#39;SELECT ID FROM &amp;quot;SiteTree_Live&amp;quot; WHERE &amp;quot;ShowInSearch&amp;quot;=1&amp;#39;)-&amp;amp;amp;gt;column();&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;currentStep = 0;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;totalSteps = count($this-&amp;amp;amp;gt;pagesToProcess);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;When constructing the job, I get a list of all the Live pages on the site (these are the only ones that are going to be indexed by google) that are set to show in the search. We&amp;#39;re only interested in the ID of these pages though, not the actual objects. This is because we&amp;#39;re going to store the full list of IDs of the pages we need to process - the `$this-&amp;amp;amp;gt;pagesToProcess` variable here gets serialized and stored in the database between processing events, enabling us to stop and start processing at any time. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function getJobType() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if ($this-&amp;amp;amp;gt;totalSteps &amp;amp;amp;gt; 100) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;return QueuedJob::LARGE;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;return QueuedJob::QUEUED;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Here we&amp;#39;re arbitrarily making the judgement that &amp;amp;amp;gt; 100 pages to generate an XML file for is enough for the job to be classified as &amp;#39;large&amp;#39;. There&amp;#39;s no real processing difference for this at the moment; the main reason for doing so is to not clog up one of the queues with a job that will take several minutes to execute. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function getSignature() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;return md5(get_class($this));&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;To prevent multiple instances of the same job being added to a queue, each job defines a signature. The base AbstractQueuedJob defines a default that should be good enough for 95% of jobs, but in some cases you want to ensure that a job is the only one of its kind, regardless of parameters. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function  setup() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;parent::setup();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;increase_time_limit_to();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$tmpfile = tempnam(getTempFolder(), &amp;#39;sitemap&amp;#39;);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (file_exists($tmpfile)) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;tempFile = $tmpfile;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The _setup()_ method is called just before a job starts for the first time. In this case, we&amp;#39;re wanting to make sure that a temporary file (that we&amp;#39;re going to build the sitemap.xml file into first) exists for us to work with. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function prepareForRestart() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;parent::prepareForRestart();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// if the file we&amp;#39;ve been building is missing, lets fix it up&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (!$this-&amp;amp;amp;gt;tempFile || !file_exists($this-&amp;amp;amp;gt;tempFile)) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$tmpfile = tempnam(getTempFolder(), &amp;#39;sitemap&amp;#39;);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (file_exists($tmpfile)) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;tempFile = $tmpfile;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;currentStep = 0;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;pagesToProcess = DB::query(&amp;#39;SELECT ID FROM SiteTree_Live WHERE ShowInSearch=1&amp;#39;)-&amp;amp;amp;gt;column();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The  _prepareForRestart()_ method is executed whenever the job has been paused then restarted. It could have been restarted by a user manually pausing, or an error that caused it to stop. Either way, it gives us a chance to check the state of the job, and if necessary restart it. We could just as easily flag the job as complete here and not continue, but in this case we&amp;#39;re making sure our temporary file still exists, and if it doesn&amp;#39;t, creating a new one from scratch. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function process() {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$remainingChildren = $this-&amp;amp;amp;gt;pagesToProcess;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// if there&amp;#39;s no more, we&amp;#39;re done!&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (!count($remainingChildren)) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;completeJob();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;isComplete = true;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;return;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// lets process our first item - note that we take it off the list of things left to do&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$ID = array_shift($remainingChildren);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// do some processing work that adds content to $tmpfile&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// ... snip ...&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// and now we store the new list of remaining children&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;pagesToProcess = $remainingChildren;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;currentStep++;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (!count($remainingChildren)) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;completeJob();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$this-&amp;amp;amp;gt;isComplete = true;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;return;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The _process()_ method is where all the actual work for this job happens, but it still needs to do a minimum of things to keep the container happy and in sync with things. First, it retrieves the list of pages still to be processed, and checks to see if there&amp;#39;s anything left, if not marking the job complete. Next, it does the actual work with the next item in the list, then updates `$this-&amp;amp;amp;gt;pagesToProcess` to make sure that next run through is onto the next item. It updates how many steps have been processed, then does another check to see whether the job has completed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;protected function completeJob() {&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// ... snip ... &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (file_exists($this-&amp;amp;amp;gt;tempFile)) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;unlink($this-&amp;amp;amp;gt;tempFile);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$nextgeneration = new GenerateGoogleSitemapJob();&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;singleton(&amp;#39;QueuedJobService&amp;#39;)-&amp;amp;amp;gt;queueJob($nextgeneration, date(&amp;#39;Y-m-d H:i:s&amp;#39;, time() + self::$regenerate_time));&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Finally, our _completeJob()_ method actually copies our temp file to the right location, then cleans up the old file. Lastly, this job creates a **NEW** job and adds it to the queue to be processed at a date in the future; in this case it executes once every day.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Okay, that was a whole lot of words, but hopefully gives an idea of what&amp;#39;s involved in writing a queued job, or more to the point, what you don&amp;#39;t have to worry about. The framework around this manages everything to do with error handling and reporting, including automatically pausing and restarting jobs and notifying on broken jobs. It manages the persistence of job state so that jobs can be picked up after they&amp;#39;ve been paused and still continue on. It also manages the scheduling of jobs in the future, so you can use the module almost as a cron replacement.&amp;lt;/p&amp;gt;</description>
			<pubDate>Mon, 01 Nov 2010 10:02:09 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/queued-jobs-module-ready-to-go/</guid>
		</item>
		
		<item>
			<title>Using dependency injection in SilverStripe</title>
			<link>http://www.mikenovember.com/blog/using-dependency-injection-in-silverstripe/</link>
			<description>&amp;lt;p&amp;gt;I&amp;#39;ve been toying with a simple [dependency injector](&amp;lt;a href=&amp;quot;http://github.com/nyeholt/injector/&amp;quot;&amp;gt;http://github.com/nyeholt/injector/&amp;lt;/a&amp;gt;) for the last few days, and have started to think about ways in which it (or another dependency injector) could benefit SilverStripe. Some ideas I&amp;#39;ve been toying with&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;* Put in authentication / authorization as part of the pre request dispatch. &amp;lt;br /&amp;gt;* Refactor authentication methods to be injected services linked in &amp;lt;br /&amp;gt;* Refactor persistence and data loading away from DataObject class directly&amp;lt;br /&amp;gt;* Using non* SQL based datastores&amp;lt;br /&amp;gt;* Refactor to use PDO or something with proper prepared statements&amp;lt;br /&amp;gt;* PermissionService *  for sites that don&amp;#39;t need complex permissions, have something that returns true, for those that do configure to use something else&amp;lt;br /&amp;gt;* VersionService&amp;lt;br /&amp;gt;* WorkflowService&amp;lt;br /&amp;gt;* SearchService&amp;lt;br /&amp;gt;* Aop filters for some things&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;* Auditing method calls&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;*  Access restriction on method calls (force developers to think before calling * &amp;amp;amp;gt;write())&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;*  Would almost work as a replacement to $this* &amp;amp;amp;gt;extend(&amp;#39;augmentXXX&amp;#39;) type functionality&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Along the lines of the first point, I put some code together to see how it works&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;// injector configuration&amp;lt;br /&amp;gt;Injector::inst(array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;class&amp;#39; =&amp;amp;amp;gt; &amp;#39;RequestProcessor&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;properties&amp;#39; =&amp;amp;amp;gt; array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;preFilters&amp;#39; =&amp;amp;amp;gt; array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;#$AuthenticationFilter&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;#$AuthorisationFilter&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;)&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;),&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;),&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;AuthenticationFilter&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;AuthorisationFilter&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;class&amp;#39; =&amp;amp;amp;gt; &amp;#39;AuthenticationService&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;properties&amp;#39; =&amp;amp;amp;gt; array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;authenticators&amp;#39; =&amp;amp;amp;gt; array(&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;#$DbAuthenticationProvider&amp;#39;,&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;)&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;),&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;),&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#39;DbAuthenticationProvider&amp;#39;,&amp;lt;br /&amp;gt;);&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;And then adding a hook in before the Director dispatches the request&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Injector::inst()-&amp;amp;amp;gt;get(&amp;#39;RequestProcessor&amp;#39;)-&amp;amp;amp;gt;preFilter($req, $session); // $session required to get around a SS quirk&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The &amp;#39;grunt&amp;#39; work comes in the AuthneticationFilter&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;lt;pre class=&amp;quot;brush: php&amp;quot;&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;class AuthenticationFilter implements RequestFilter {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;/**&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; * Automatically injected based on convention&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; */&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public $authenticationService;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function preRequest(SS_HTTPRequest $request, Session $session) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// lets try authenticating&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if (isset($_REQUEST[&amp;#39;auth&amp;#39;]) || isset($_REQUEST[&amp;#39;action_dologin&amp;#39;])) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$email = $request-&amp;amp;amp;gt;postVar(&amp;#39;Email&amp;#39;);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$pass = $request-&amp;amp;amp;gt;postVar(&amp;#39;Password&amp;#39;);&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$member = $this-&amp;amp;amp;gt;authenticationService-&amp;amp;amp;gt;authenticate($email, $pass);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if ($member) {&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$member-&amp;amp;amp;gt;logIn($request-&amp;amp;amp;gt;postVar(&amp;#39;Remember&amp;#39;));&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// dirty hack for now...&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;$session-&amp;amp;amp;gt;inst_set(&amp;#39;loggedInAs&amp;#39;, $member-&amp;amp;amp;gt;ID);&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// because we have the request here, we can do a bunch of redirects or&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// whatever we like - but this is just a poc for now so we won&amp;#39;t bother with&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;// anything else. &amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response) {&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;}&amp;lt;br /&amp;gt;}&amp;lt;br /&amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;So the actual &amp;#39;authenticate&amp;#39; work is done via an authentication service, which in turn has registered within it a bunch of **AuthenticationProvider** implementors - in this case I only have one (**DbAuthenticationProvider**) which simply calls _MemberAuthenticator::authenticate()_. I could quite easily add on any number of other providers (LDAP, OpenID, etc etc) in a chain, and let the user login via the first that succeeds. Makes for an elegant way to have a single login form. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The next step is to add some logic to the AuthorisationFilter to prevent requests to certain URLs continuing if the user is not authorized (I&amp;#39;m looking at you /dev requests). This stops unauthorised requests very early in the request cycle, and help centralise the logic for this for a single maintainable area for developers to refer to. But that&amp;#39;s for another day...&amp;lt;/p&amp;gt;</description>
			<pubDate>Tue, 26 Oct 2010 10:42:18 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/using-dependency-injection-in-silverstripe/</guid>
		</item>
		
		<item>
			<title>Another new blog</title>
			<link>http://www.mikenovember.com/blog/another-new-blog/</link>
			<description>&amp;lt;p&amp;gt;Another year another new blog. It&amp;#39;s almost like a new years resolution or something like that. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Anyway, this time around it will be focused mostly on SilverStripe development. Largely on the backend code that goes into modules, but also touching on some parts of the core, and what I actually do for SilverStripe.&amp;lt;/p&amp;gt;</description>
			<pubDate>Mon, 25 Oct 2010 23:44:01 +1100</pubDate>
			
			
			<guid>http://www.mikenovember.com/blog/another-new-blog/</guid>
		</item>
		

	</channel>
</rss>
