<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>marsbomber</title>
 <link href="http://marsbomber.github.com/feed/" rel="self"/>
 <link href="http://marsbomber.github.com/"/>
 <updated>2012-03-27T15:42:10-07:00</updated>
 <id>http://marsbomber.github.com/</id>
 <author>
   <name>Jim Li</name>
   <email>jimli@elinkmedia.net.au</email>
 </author>

 
 <entry>
   <title>Ruby (1.9.3) Psych YAML parser issue</title>
   <link href="http://marsbomber.github.com/2012/01/29/ruby-psych-parser-issue"/>
   <updated>2012-01-29T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2012/01/29/ruby-psych-parser-issue</id>
   <content type="html">&lt;p&gt;Ruby 1.9.3 uses a more restrict YAML parser, Psych, instead of the old Syck parser. This caused me issues when using &lt;a href=&quot;https://github.com/binarylogic/settingslogic&quot;&gt;Settingslogic&lt;/a&gt;. Even doing what suggested by Settingslogic to set the YAML parser back to Syck didn't help.&lt;/p&gt;

&lt;p&gt;A simple test script&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1697539.js?file=yaml_parse.rb&quot;&gt;&lt;/script&gt;


&lt;p&gt;Running it under Ruby 1.9.3 outputs this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;Using: psych
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;defaults&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;cool&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;bang&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;wow&amp;quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;fruit&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;apple&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}}&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;development&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;cool&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;fruit&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;banana&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}}}&lt;/span&gt;
Using: syck
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;defaults&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;cool&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;bang&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;wow&amp;quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;fruit&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;apple&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}}&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&amp;quot;development&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;cool&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;fruit&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;banana&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You could see &quot;development&quot; lost its &quot;bang&quot; hash key.&lt;/p&gt;

&lt;p&gt;There are ways to get around the issue by re-building Ruby with libyaml flag. I consider this as harmful than helpful. So I reverted my application.yml back to its very dumb form, no default options, no merging, just duplicate all settings for all environments. It's definitely stupid to do so, but for now, it's considered as a temporary workaround.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ruote workflow engine with RabbitMQ (Part 2)</title>
   <link href="http://marsbomber.github.com/2012/01/20/ruote-with-rabbitmq-part2"/>
   <updated>2012-01-20T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2012/01/20/ruote-with-rabbitmq-part2</id>
   <content type="html">&lt;p&gt;I explained how I setup Ruote and RabbitMQ in &lt;a href=&quot;/2012/01/20/ruote-with-rabbitmq-part1/&quot;&gt;last post&lt;/a&gt;. From there on, you basically already have a working system. All there's left is to have external services subscribe to the RabbitMQ job queues, parse the workitem JSON, do whatever and post the modified/amended JSON back to RabbitMQ, default queue is named &quot;ruote_workitems&quot;, which is what the RuoteAMQP receiver listens on.&lt;/p&gt;

&lt;p&gt;In this post, I'll demonstrate how a DaemonKit generated daemon script consumes the RabbitMQ job messages and how we construct a DaemonKit compatible Ruote process definition.&lt;/p&gt;

&lt;p&gt;Generate DaemonKit project&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rvm 1.9.3@daemonkit_ruote
gem install daemon-kit
daemon-kit daemon -i ruote
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ruote
bundle
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Make daemon listen to correct AMQP queues by editing ruote.yml config&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;defaults&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;amqp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;queues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ldap_job&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email_job&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Edit participant class by adding the following 2 methods&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ldap&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;workitem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ldap&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# just to demonstrate the AMQP message carries the ID fields and it can be consumed&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;workitem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;original_cust_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workitem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;cust_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;email&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;workitem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;done&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Let's start everything up&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rabbitmq-server
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /my-ruotekit-enabled-rails-project &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rails s
&lt;span class=&quot;nv&quot;&gt;RAKE_TASK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true &lt;/span&gt;rake ruote:run_worker
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /my-daemonkit-ruote-project &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; bin/daemon
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now let's work out how we wire everything up by carefully crafting a process definition.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href=&quot;http://localhost:3000/_ruote/processes/new&quot;&gt;http://localhost:3000/_ruote/processes/new&lt;/a&gt; in your browser and enter the following as process definition&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Ruote&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process_definition&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;suspend_account&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:revision&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0.1&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ldap&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/sample/ldap&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# slot in editor to check ldap process result status&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/sample/email&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# slot in editor to check email process result status&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;notifier&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:forget&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# this could be email or final results back in notification queue&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Enter the following into the workitem fields box&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;cust_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then launch it! If everything goes well(it should!), you'll see no processes listed under the ruotekit app interface. And you'll have 4 queues listed under RabbitMQ's management interface.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;email_job, 0 job&lt;/li&gt;
&lt;li&gt;ldap_job, 0 job&lt;/li&gt;
&lt;li&gt;notify_job, 1 job&lt;/li&gt;
&lt;li&gt;ruote_workitems, 0 job&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;By popping the message out of the notify_job queue, you'll see the serialised JSON string contains ldap done and email done key-value pairs. It shows me the job is done, and all participants are exercised correctly.&lt;/p&gt;

&lt;p&gt;Now, we go back a step and explain a little on the process definition we crafted.&lt;/p&gt;

&lt;p&gt;If a remote participant will be processed by a DaemonKit daemon script, we need to give each of those participants a hash, which contains a :command key. The value for :command key needs to follow a certain convention too. The convention is &quot;/participant_class_name/method_name&quot;. DaemonKit will classify and constantize &quot;participant_class_name&quot; in to ParticipantClassName object, and &quot;method_name&quot; will be sent to it. So in our example, when the daemon script sees command &quot;/sample/ldap&quot;, it'll invoke a call to &quot;Sample#ldap&quot;.&lt;/p&gt;

&lt;p&gt;The value we entered into the workitem fields textbox is simply be merged into the initial workitem hash, and it'll be sent along to all participants.&lt;/p&gt;

&lt;p&gt;That is it. Hope it all makes sense, and please tweet me if you found I've got any bits laid out wrongly or explained wrongly.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ruote workflow engine with RabbitMQ (Part 1)</title>
   <link href="http://marsbomber.github.com/2012/01/20/ruote-with-rabbitmq-part1"/>
   <updated>2012-01-20T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2012/01/20/ruote-with-rabbitmq-part1</id>
   <content type="html">&lt;p&gt;At MYOB, I am assigned the task to build a component based workflow application. There are several requirements this application has to address. Here are a few&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decoupled components&lt;/li&gt;
&lt;li&gt;Resilient workflow&lt;/li&gt;
&lt;li&gt;Configurable workflow&lt;/li&gt;
&lt;li&gt;Every single piece of the application needs to be scalable&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;A messaging based system becomes somewhat a natural choice to address the decoupling, distributable and scalable issue. While in the hunt of a good workflow system, I was pointed to a Ruby gem called &lt;a href=&quot;http://ruote.rubyforge.org/&quot;&gt;Ruote&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/jmettraux&quot;&gt;@jmettraux&lt;/a&gt;. Ruote has also got several companion gems. One of them is &lt;a href=&quot;https://github.com/kennethkalmer/ruote-amqp&quot;&gt;ruote-amqp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/hallelujah/rails-sample-ruote-amqp&quot;&gt;Rails Sample Ruote AMQP&lt;/a&gt; is the most complete example I could find on Github. This excellent sample project almost covers all aspect. However its Rails default README file doesn't do its justice. I had to dig hard to figure out how all the pieces are put together.&lt;/p&gt;

&lt;p&gt;Enough mumbling from me. The following are the steps I implemented to get an end-to-end Ruote + RabbitMQ going on my MBP. As prerequisites, I have Homebrew and RVM installed.&lt;/p&gt;

&lt;h2&gt;Install RabbitMQ&lt;/h2&gt;

&lt;p&gt;This is rather simple with the help from Homebrew.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;brew install rabbitmq
rabbitmq-plugins &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;rabbitmq_management
rabbitmq-server
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now you can monitor your running RabbitMQ instance from the browser at &lt;a href=&quot;http://127.0.0.1:55672/mgmt/&quot;&gt;http://127.0.0.1:55672/mgmt/&lt;/a&gt; (login using guest - guest)&lt;/p&gt;

&lt;h2&gt;Setup RuoteKit enabled Rails project&lt;/h2&gt;

&lt;p&gt;Create a new rails app called lcp&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rails new lcp
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Step in the project root, create .rvmrc&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rvm 1.9.3@lcp --create
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Run bundle install after amending Gemfile with&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ruote&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;~&amp;gt; 2.2.0&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ruote-kit&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;~&amp;gt; 2.2.0.3&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ruote-amqp&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;~&amp;gt; 2.2.0&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add ruote kit initializer. As you could see, the file shown is a work in progress.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# config/initializers/ruote-kit.rb&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# TODO: move setting values into a config file&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;AMQP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#AMQP.settings[:vhost] = &amp;#39;/&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#AMQP.settings[:user] = &amp;#39;guest&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#AMQP.settings[:pass] = &amp;#39;guest&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# run ruote engine without worker&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# run ruote rake task for workers, rake ruote:run_worker&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Ruote&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Engine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RUOTE_STORAGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;RAKE_TASK&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;RuoteAMQP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Receiver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# don&amp;#39;t register participants in rake tasks&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;participant&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ldap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RuoteAMQP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ParticipantProxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ldap_job&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;participant&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RuoteAMQP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ParticipantProxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;email_job&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;participant&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:notifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RuoteAMQP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ParticipantProxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:queue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;notify_job&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:forget&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#participant :editor&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# register the catchall storage participant named &amp;#39;.+&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;catchall&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# when true, the engine will be very noisy (stdout)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noisy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add ruote worker rake task&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# lib/tasks/ruote.rake&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ruote&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Run a worker thread for ruote&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:run_worker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run_worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RUOTE_STORAGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Last not least, mount RuoteKit to our Rails app by adding the following to the routes file&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# ruote-kit&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/_ruote&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Application&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/_ruote/*path&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RuoteKit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Application&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This completes first half of the story. We now have a running RabbitMQ instance with admin monitoring, and a RuoteKit enabled Rails app. The Rails app has several RuoteAMQP participants registered, a ruote rake task ready to run Ruote workers, and of course the RuoteKit rack app that allows us to manually launch Ruote jobs.&lt;/p&gt;

&lt;p&gt;In the next post, I'll complete the full picture by implementing a DaemonKit generated Ruote daemon script, which processes the AMQP jobs published by the ruote worker running on the Rails app side.&lt;/p&gt;

&lt;p&gt;But for now, PEACE!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ruby basics - Array</title>
   <link href="http://marsbomber.github.com/2012/01/02/ruby-array-basics"/>
   <updated>2012-01-02T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2012/01/02/ruby-array-basics</id>
   <content type="html">&lt;p&gt;Here are some basic Ruby array methods that I should learn to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;amp; and |&lt;/strong&gt; Array intersection and union&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [2, 3]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 2, 3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;collect and select&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [true, false, true, false]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 3]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;delete_if and reject&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [2, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [2, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [2, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;push, pop, shift and unshift&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 2, 3, 4, 5]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 2, 3, 4, 5]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 5&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unshift&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [0, 1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [0, 1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shift&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [1, 2, 3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Ruby basics - String</title>
   <link href="http://marsbomber.github.com/2011/12/23/ruby-string-basics"/>
   <updated>2011-12-23T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2011/12/23/ruby-string-basics</id>
   <content type="html">&lt;p&gt;One night, I was studying some code written by &lt;a href=&quot;https://twitter.com/spyromus&quot;&gt;Aleksey&lt;/a&gt;. I spotted his usage of Ruby string's &quot;%&quot; notation. It shows me how elegant Ruby can be, given knowing all those Ruby basics.&lt;/p&gt;

&lt;p&gt;To confess, I learned (and still learning) Ruby from learning Rails. At this moment, I defintely think it's a bad idea! Basics should always be taught/learned before the magical frameworks. So, I'll start a series of posts to go through some of these basics.&lt;/p&gt;

&lt;h2&gt;Ruby string % notation&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;%Q&lt;/strong&gt; - Interpolated string. Character used after %Q will be used as the new string delimeter, hence it should be balanced. This makes normal string delimeters such as &quot; and ' become auto-escaped. If the new delimeter also appears in the string, it only needs to be manually escaped if it's unbalanced.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;%Q&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Don&lt;span class=&quot;s1&quot;&gt;&amp;#39;t need to escape &amp;quot; and &amp;#39;&lt;/span&gt;. Need to escape &lt;span class=&quot;se&quot;&gt;\[&lt;/span&gt; manually, but not &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; and &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;%r&lt;/strong&gt; - Similar to %Q, but constructs a Regexp object. No need to escape those slashes!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%W&lt;/strong&gt; - Feed it with a string of words separated by spaces, get back an array of words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%x&lt;/strong&gt; - Interpolated shell commands. Same as using backticks.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>New years resolutions</title>
   <link href="http://marsbomber.github.com/2011/12/22/new-years-resolutions"/>
   <updated>2011-12-22T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2011/12/22/new-years-resolutions</id>
   <content type="html">&lt;p&gt;Another year almost goes passed by. Time for doing this new years resolutions thing again.&lt;/p&gt;

&lt;p&gt;Let's look back first, and see what I have accomplished in 2011.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;Work hard on my MYOB works. Make the project we're working on a big success!&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Work smart on my freelance works. Try getting recurring income.&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Rails 3 is out for a while now. I WILL make a pet RoR app this year!&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Get myself into Test Driven Development and study Behaviour Driven Development.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Keep spending quality time with family. At least 2 road trips.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Take over the duty of sending Oscar to his childcare (that is 3 mornings a week).&lt;/del&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Okay! 5 out of 6 items are stiked out. Not too bad!&lt;/p&gt;

&lt;p&gt;Now, look forward. In 2012, here are the things I want to make happen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'll be re-joining MYOB and work on a new project. I want a big success on that!&lt;/li&gt;
&lt;li&gt;Keep working on freelance recurring income. I believe things will work out this year.&lt;/li&gt;
&lt;li&gt;Finish off my Rails 3 side project.&lt;/li&gt;
&lt;li&gt;Keep doing morning and afternoon childcare runs (3 days a week).&lt;/li&gt;
&lt;li&gt;Family time! Again, at least 2 family trips.&lt;/li&gt;
&lt;li&gt;EDITED: Do exercise to lose weight.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is it! I'll see how things are tracking by the end of 2012!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Install RVM Ruby on Ubuntu 11.10</title>
   <link href="http://marsbomber.github.com/2011/12/16/install-rvm-ruby-on-ubuntu-11-10"/>
   <updated>2011-12-16T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2011/12/16/install-rvm-ruby-on-ubuntu-11-10</id>
   <content type="html">&lt;p&gt;Because OS X crashes every 2nd day, I thought it's time to give Ubuntu another good spin. First task is to setup my Ruby working environment.&lt;/p&gt;

&lt;p&gt;On a fresh Ubuntu 11.10 VM, I firstly installed curl and git via apt-get&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo apt-get install curl git-core
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I then installed RVM using the normal RVM installation command&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;bash &amp;lt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then I tried to install Ruby 1.9.3, I ran into all sorts of issues, readline not available, yaml failed to build, etc. After some fooling around, I found that all I needed to do was to RTFM! Running the following gives me all required packages needed to install an MRI (and others) ruby...&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rvm requirements
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Believe or not, after doing the sudo apt-get install line from rvm requirements, RVM is happy as!&lt;/p&gt;

&lt;p&gt;Lesson learnt: before start blaming a tool (especially a free one!), let's check what the README says first!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ruby block and Regex</title>
   <link href="http://marsbomber.github.com/2011/12/06/ruby-block-and-regex"/>
   <updated>2011-12-06T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2011/12/06/ruby-block-and-regex</id>
   <content type="html">&lt;p&gt;Open source is fantastic! I learnt something new from reading Rails source code today again.&lt;/p&gt;

&lt;p&gt;Today's surprise was brough to me by the power of regular expression and Ruby blocks.&lt;/p&gt;

&lt;p&gt;Rails 3 Net::HTTPHeader module has the following method&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;urlencode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;force_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ASCII-8BIT&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/[^a-zA-Z0-9_\.\-]/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;%%%02x&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$&amp;amp;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;1st, I learnt the gsub method could take a block as its second argument.&lt;/p&gt;

&lt;p&gt;2nd, inside the block, all regular expression back references could be used, e.g. $&amp;amp; for referencing all matching elements.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Android screen grab</title>
   <link href="http://marsbomber.github.com/2011/11/29/android-screen-grab"/>
   <updated>2011-11-29T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2011/11/29/android-screen-grab</id>
   <content type="html">&lt;p&gt;I needed to publish an Android app for one of our clients today. Screenshots of the app is required for publishing.&lt;/p&gt;

&lt;p&gt;To do it, extremely simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get application onto testing Android device&lt;/li&gt;
&lt;li&gt;Connect Android device to computer, make sure device's debug mode is enabled.&lt;/li&gt;
&lt;li&gt;From the computer, start the DDMS program that's shipped with the Android SDK&lt;/li&gt;
&lt;li&gt;From DDMS, highlight the connected Android device, and go to menu &quot;Device&quot; - &quot;Screen capture&quot;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Not too hard. Have to say Apple's native screen capture feature on iOS devices is a lot simpler.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>RVM update</title>
   <link href="http://marsbomber.github.com/2011/11/05/rvm-update"/>
   <updated>2011-11-05T00:00:00-07:00</updated>
   <id>http://marsbomber.github.com/2011/11/05/rvm-update</id>
   <content type="html">&lt;p&gt;RVM is super easy to use, and it manages Ruby Gems well. Most of the Ruby/Rails projects I work on are using its Gemset feature.&lt;/p&gt;

&lt;p&gt;I was running RVM version 1.6 and decided to perfom and upgrade.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rvm get latest
rvm upgrade 1.9.2-p180 1.9.2-p290
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Second command from above is extremely useful. As per example above, it updates my local Ruby 1.9.2-p180 to 1.9.2-p290. All gemsets associated with the 1.9.2-p180 are also relinked to the new 1.9.2-p290. Handy!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Create SQLite DB from CSV</title>
   <link href="http://marsbomber.github.com/2011/10/22/create-sqlite-db-from-csv"/>
   <updated>2011-10-22T04:42:02-07:00</updated>
   <id>http://marsbomber.github.com/2011/10/22/create-sqlite-db-from-csv</id>
   <content type="html">&lt;p&gt;Recently a project I'm working on requires me to populate an SQLite database with CSV contents. A very straight forward task that I have done so many times before in PHP.&lt;/p&gt;

&lt;p&gt;This round Ruby is the pick. Everything just feels a bit nicer.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1305896.js?file=parser.rb&quot;&gt;&lt;/script&gt;

</content>
 </entry>
 
 <entry>
   <title>Ruby string interpolation</title>
   <link href="http://marsbomber.github.com/2011/08/20/ruby-string-interpolation"/>
   <updated>2011-08-20T03:26:23-07:00</updated>
   <id>http://marsbomber.github.com/2011/08/20/ruby-string-interpolation</id>
   <content type="html">&lt;p&gt;We store configuration strings in YAML files. It's common that we need to substitute part of the string with runtime values. Hence we introduce some kind of placeholders in the config strings. Given an example that our application may need to hit an external URL to retrieve some remote resources at runtime. To do this, we could make a config string in our application's config YAML file like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;remote_url_template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://remote.domain.com/give/me/RESOURCE1/and/RESOURCE2&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then in our code, we substitute &quot;RESOURCE1&quot; and &quot;RESOURCE2&quot; with the real resource names we require. In my early days of programming in Ruby, I used some very ordinary string substitution method like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# remote_url_template is read from the config yaml&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resource_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;coke&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resource_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;chips&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote_url_template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;RESOURCE1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resource_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;RESOURCE2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resource_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It works, but I don't really like it... So I found something better, that is to use Ruby's string interpolation methods&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# in yaml file&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote_url_template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://remote.domain.com/give/me/%s/and/%s&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# in ruby code&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# remote_url_template is read from the config yaml&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resource_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;coke&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resource_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;chips&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remote_url_template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resource_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resource_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;A lot nicer, but still can be better. Thanks to a colleague of mine, &lt;a href=&quot;http://blog.noizeramp.com/&quot; target=&quot;_blank&quot;&gt;Aleksey Gureiev&lt;/a&gt;, another more elegant way can be used&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# in yaml file&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote_url_template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://remote.domain.com/give/me/%s/and/%s&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# in ruby code&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# remote_url_template is read from the config yaml&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resource_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;coke&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resource_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;chips&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;remote_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote_url_template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resource_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resource_two&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That is satisfactory!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Manage Rails app configurations</title>
   <link href="http://marsbomber.github.com/2011/07/23/manage-rails-app-configurations"/>
   <updated>2011-07-23T06:06:12-07:00</updated>
   <id>http://marsbomber.github.com/2011/07/23/manage-rails-app-configurations</id>
   <content type="html">&lt;p&gt;Most of applications require application configuration files. The Rails applications I worked on pretty much all require an initialiser (or should it be the Rails convention initialiZer) to load a configuration YAML file. I'm aware that there are gems out there providing this kind of configuration solutions, such as SettingsLogic. For a simple problem like this one, I think we could roll our own too (oh, the not invented here syndrome).&lt;/p&gt;

&lt;p&gt;The codebase I worked on typically has an initialiser called load_config.rb. It's got something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# config/initializers/load_config.rb&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;AppConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RAILS_ROOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;config&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;config.yml&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Override config options by correct environment&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;env_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;AppConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RAILS_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;AppConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;env_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Easy and good. There's one more thing I'd love to add to this. I'd love to have a local config file, config.local.yml, that can overwrite config values defined in the config.yml. And this config.local.yml is not source controlled, means every developer can make tweak the configs to tailor to their own development environment without needing to touch the source controlled configuration file, config.yml.&lt;/p&gt;

&lt;p&gt;To do this, just add the following block of code to the load_config.rb&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;local_config_filepath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RAILS_ROOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;config&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;config.local.yml&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exist?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_config_filepath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;AppConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_config_filepath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>CoffeeScript Basics</title>
   <link href="http://marsbomber.github.com/2011/07/19/coffeescript-basics"/>
   <updated>2011-07-19T21:35:35-07:00</updated>
   <id>http://marsbomber.github.com/2011/07/19/coffeescript-basics</id>
   <content type="html">&lt;p&gt;Rails 3.1 will support CoffeeScript out of the box. I gave the new boy in town a little test. I think it'll be a great tool for web developers writing javascript code. CoffeeScript is short and precise, generated JavaScript variables are properly scoped, class inheritance is made super easy, love the syntax sugar. Oh and yes, mixing in jQuery is easy too.&lt;/p&gt;

&lt;p&gt;Here's a little play script I wrote to illustrate how a JavaScript class can be written in CoffeeScript&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;

  &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;constructor&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;

  &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;speak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;saying&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#{saying} #{fancy_name()}!&amp;quot;&lt;/span&gt;
 
  &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fancy_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Jim&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;Jimbob&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Dan&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;DanDaMan&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt;

  &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1 Person has only 1 head&amp;quot;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;jim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Jim&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;jim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;speak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hi&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The above CoffeeScript will be translated into the following JavaScript&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;jim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* private var */&lt;/span&gt;  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fancy_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* constructor */&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* public instance method */&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;speak&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;saying&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;saying&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fancy_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* private instance method */&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fancy_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Jim&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Jimbob&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Dan&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;DanDaMan&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;my_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/* class method */&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;feature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;1 Person has only 1 head&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;jim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Jim&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;jim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;speak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hi&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Background jobs on Heroku</title>
   <link href="http://marsbomber.github.com/2011/06/30/background-jobs-on-heroku"/>
   <updated>2011-06-30T02:43:19-07:00</updated>
   <id>http://marsbomber.github.com/2011/06/30/background-jobs-on-heroku</id>
   <content type="html">&lt;p&gt;I'm recently asked what my recent technology excitement is, of course in the context of programming. The name of &lt;a href=&quot;http://www.heroku.com/&quot; target=&quot;_blank&quot;&gt;Heroku&lt;/a&gt; came into my mind instantly. I've been using Heroku for all my Rails based applications recently. I'm amazed how easy it is to deploy and scale (to a degree) applications on to Heroku.&lt;/p&gt;

&lt;p&gt;Heroku's default way of running background jobs is using the &lt;a href=&quot;https://github.com/tobi/delayed_job&quot; target=&quot;_blank&quot;&gt;delayed_job&lt;/a&gt; Ruby gem, which essentially records background jobs into a database table. And on Heroku, you can start a worker to monitor and process the job queue. This involves a lot of database polling as you could imagine.&lt;/p&gt;

&lt;p&gt;So, in one of the applications I'm working on, I tried something more elegant (in my opinion). Github uses a Ruby gem called &lt;a href=&quot;https://github.com/defunkt/resque&quot; target=&quot;_blank&quot;&gt;Resque&lt;/a&gt; for their background jobs.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Resque uses a &lt;a href=&quot;http://redis.io/&quot; target=&quot;_blank&quot;&gt;Redis&lt;/a&gt; based backend to store queued jobs, so it's fast in job logging and job retrieving.&lt;/li&gt;
    &lt;li&gt;Resque allows you to separate jobs into different queues, so everything becomes better categorised.&lt;/li&gt;
    &lt;li&gt;Resque also provides a Sinatra based web interface to monitor all jobs  including failures, so better monitoring and better debugging.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;All good. I also opted to use a Resque plugin called &lt;a href=&quot;https://github.com/ajmurmann/resque-heroku-autoscaler&quot; target=&quot;_blank&quot;&gt;resque-heroku-autoscaler&lt;/a&gt;. This allows me to dynamically scale the number of Heroku workers up and down base on the jobs recorded in the queue. Since Heroku charges on worker usage, so with this auto scaler, I only pay for what's used.&lt;/p&gt;

&lt;p&gt;As for the implementation, it's scattered across many files. Here's my implementation, which handles the delivery of welcome emails upon membership creation.&lt;/p&gt;

&lt;p&gt;Gemfile&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;resque&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:require&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;resque/server&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;resque-heroku-autoscaler&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;config/resque.yml&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;development&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;127&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;127&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;config/initializers/resque.rb&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;resque&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;heroku_environments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;staging&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;production&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rails_root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;RAILS_ROOT&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/../..&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rails_env&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;RAILS_ENV&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;development&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;heroku_environments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails_env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;resque_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails_root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/config/resque.yml&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Resque&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resque_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails_env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;REDISTOGO_URL&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Resque&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;config/initializers/resque_heroku_autoscaler_setup.rb&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;resque/plugins/resque_heroku_autoscaler&amp;#39;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Resque&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HerokuAutoscaler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heroku_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;heroku_user_name&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heroku_pass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;HEROKU_PASSWORD&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heroku_app&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;HEROKU_APP&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;production?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_worker_count&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pending&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pending&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;development?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scaling_disabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;app/models/membership_observer.rb&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MembershipObserver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Observer&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;after_create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;membership&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Resque&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MailerCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;MyMailer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:welcome_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;membership&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;app/models/mailer_callback.rb&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;resque/plugins/resque_heroku_autoscaler&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MailerCallback&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Resque&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HerokuAutoscaler&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# resque queue name&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;queue&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:email_queue&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# resque callback method&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mailer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constantize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliver&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.heroku.com/&quot; target=&quot;_blank&quot;&gt;http://www.heroku.com/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/tobi/delayed_job&quot; target=&quot;_blank&quot;&gt;https://github.com/tobi/delayed_job&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/defunkt/resque&quot; target=&quot;_blank&quot;&gt;https://github.com/defunkt/resque&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://redis.io/&quot; target=&quot;_blank&quot;&gt;http://redis.io/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/ajmurmann/resque-heroku-autoscaler&quot; target=&quot;_blank&quot;&gt;https://github.com/ajmurmann/resque-heroku-autoscaler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Ruby on Rails, 2 months in</title>
   <link href="http://marsbomber.github.com/2011/04/24/ruby-on-rails-2-months-in"/>
   <updated>2011-04-24T05:41:35-07:00</updated>
   <id>http://marsbomber.github.com/2011/04/24/ruby-on-rails-2-months-in</id>
   <content type="html">&lt;p&gt;I've started my &quot;senior&quot; developer role in doing Ruby on Rails projects for a bit over 2 months. Reason I quoted the &quot;senior&quot; bit is that I'm really a newbie to it. I guess the seniority is more about general web based application development rather than RoR. Having said that, RoR isn't that foreign to me at all. I started studying it a year ago. However my self-study doesn't compensate my lack of real world working experience. In the past 2 months, lots of ideas and knowledges are exchanged between me and my peers. I learnt a lot of Rails of course. And I believe I have also contributed some non-rails thinking into the Rails project.&lt;/p&gt;

&lt;p&gt;2 months in, I learnt that Rails is moden and rapid in doing web development (I absolutely love it). However it's convention over configuration nature sometimes dictates the way developers think too much. Somehow, developers' creativities become canvased by Rails. You find yourself battling with routes, ActiveRecord models, DRY controllers a lot. The application architectural deliberating stage is somewhat overlooked, if not bypassed. Most of the time, this will lead to future potential problems, which could be security issues, scaling issues, performance issues or just tedious labour work in doing repetitive tasks.&lt;/p&gt;

&lt;p&gt;As I'm still learning, what I believe now is that don't let Rails control how you author software,&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;write non AR models to describe your domain if required&lt;/li&gt;
    &lt;li&gt;use service layer classes to encapsulate business logic if it makes sense&lt;/li&gt;
    &lt;li&gt;off load long running, non critical tasks to a job queue (loving the resque gem now) when it's appropriate&lt;/li&gt;
    &lt;li&gt;the list goes on&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Let Rails help you instead,&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;use its powerful command line tool&lt;/li&gt;
    &lt;li&gt;utilise its ecosystem, all those wonderful gems&lt;/li&gt;
    &lt;li&gt;make a use of its RESTful controllers, exposing API is never as easy as before&lt;/li&gt;
    &lt;li&gt;look into it's respond_to feature, making your RESTful API respond to XML, json, or whatever is made super easy&lt;/li&gt;
    &lt;li&gt;the list goes on&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To summarise, the basic software engineering practices apply to Rails or non Rails applications the same way.&lt;/p&gt;

&lt;p&gt;Bend the rails to let your train reach it's destination. Expect more Rails related posts from now on.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Install and setup Gitosis</title>
   <link href="http://marsbomber.github.com/2011/04/01/install-and-setup-gitosis"/>
   <updated>2011-04-01T23:14:00-07:00</updated>
   <id>http://marsbomber.github.com/2011/04/01/install-and-setup-gitosis</id>
   <content type="html">&lt;p&gt;Github is great for social coding. To get private repositories, it's starting price is cheap and fair. However for someone who already owns a Linux VPS, as well as an  adequate backup solution, you may want to do it the hard way: setup your own remote central Git server using Gitosis. This is how I did it on my Ubuntu VPS, which is hosted on MediaTemple. My setup steps are pretty much copied from 2 great Gitosis setup tutorials, which I will reference at the foot of this post. This reference post probably benefits myself more than anyone else.&lt;/p&gt;

&lt;p&gt;SSH into the remote VPS machine,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Setup Git&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo apt-get install git-core
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 2: Setup Gitosis&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo apt-get install python-setuptools
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/downloads
git clone git://eagain.net/gitosis.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;gitosis
sudo python setup.py install
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 3: Setup git user&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo adduser --system --shell /bin/sh --gecos &lt;span class=&quot;s1&quot;&gt;&amp;#39;git version control&amp;#39;&lt;/span&gt; --group --disabled-password --home /home/git git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 4: Set up Gitosis admin user access and init Gitosis admin repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From your local computer, generate (if not done before) and copy the public SSH key to the VPS server. Place and name it as &quot;/tmp/id_rsa.pub&quot;, then&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo -H -u git gitosis-init &amp;lt; /tmp/id_rsa.pub
sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Up to this point, your have done all the works required on the VPS server. You will next jump back to your local machine and admin Gitosis from there.&lt;/p&gt;

&lt;p&gt;First thing first, let's clone the Gitosis admin repository, so that you could tweak any admin configuration settings locally and update your Gitosis server with a simple git push&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/VpsAdmin
git clone git@YOUR_SERVER:gitosis-admin.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Next you'll create a new project locally, push it to the Git server hosted on the VPS, and make the new project's remoto repository accessible by other team members.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Add new project to Gitosis admin config&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;vim ~/VpsAdmin/gitosis-admin/gitosis.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add a new config block to the bottom of the file, like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;group new_shared_project&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;members&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; jim bob
&lt;span class=&quot;nv&quot;&gt;writable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; new_shared_project
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Note that &quot;new_shared_project&quot; will be your new project's remote Git repository name. &quot;jim&quot; in this case is yourself (Gitosis admin) and &quot;bob&quot; is your team member, who will also have access to this project. &quot;jim&quot; matches the name your used in your public key, which was used when setting up Gitosis from previous steps. &quot;bob&quot; matches the name, which your team member used in his public key, which will be used in the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: add team member's public SSH key to Gitosis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obtain Bob's public SSH key and put it under ~/VpsAdmin/gitosis-admin/keydir. Give it a sensible file name so that you can easily relate it back Bob in the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Commit changes and push it up to Gitosis server&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/VpsAdmin/gitosis-admin
git commit -a -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;create new repository and setup access for Bob&amp;quot;&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 4: Create new project and push it to remote Gitosis server&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/Workspace
rails new new_shared_project
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;new_shared_project
git init
git remote add origin git@YOUR_SERVER:new_shared_project.git
git add .
git commit -a -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;initial import&amp;quot;&lt;/span&gt;
git push origin master:refs/heads/master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 5: Share the remote repository with your team member&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Team member Bob can access the remote repository from any computers that have his public SSH key installed&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git clone git@YOUR_SERVER:new_shared_project.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.hackido.com/2010/01/installing-git-on-server-ubuntu-or.html&quot; target=&quot;_blank&quot;&gt;http://www.hackido.com/2010/01/installing-git-on-server-ubuntu-or.html&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.howtoforge.com/setting-up-gitosis-on-ubuntu&quot; target=&quot;_blank&quot;&gt;http://www.howtoforge.com/setting-up-gitosis-on-ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Setup Synergy</title>
   <link href="http://marsbomber.github.com/2011/03/02/setup-synergy"/>
   <updated>2011-03-02T02:26:50-08:00</updated>
   <id>http://marsbomber.github.com/2011/03/02/setup-synergy</id>
   <content type="html">&lt;p&gt;I spent some time this morning setting up Synergy. Synergy allows me to use one set of mouse and keyboard to control multiple computers. The setup is is fairly straight forward. I just downloaded the latest stable release and followed the &lt;a href=&quot;http://synergy2.sourceforge.net/running.html&quot; target=&quot;_blank&quot;&gt;instruction&lt;/a&gt; from the Synergy site. My Synergy server is my MBP, and my Synergy client is an OS X 10.6 server. After the initial setup, my mouse is successfully shared. However my keyboard sharing is not working. A &lt;a href=&quot;http://www.linkedin.com/in/tommyyli&quot; target=&quot;_blank&quot;&gt;friend&lt;/a&gt; of mine suggested me to try an old release from the Synergy2 project, so I did. I downloaded Synergy2 1.3.1 from &lt;a href=&quot;http://sourceforge.net/projects/synergy2/files/Binaries/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;, repeat the same setup procedure. Both keyboard and mouse sharing are working nicely.&lt;/p&gt;

&lt;p&gt;I then created a couple of automator applications, one on my MBP, the other on the OS X server. This allows me to start the Synergy server and client automatically on system startups.&lt;/p&gt;

&lt;p&gt;On the Synergy server (my MBP). I created an automator application. Drag &quot;Run Shell Script&quot; into the workflow. The script I'm using is&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;/PATH-TO-SYNERGY/synergys --no-daemon --config /PATH-TO-SYNERGY-CONF/synergy.conf&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;### Stop any currently running Synergy client&lt;/span&gt;
killall &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[0]##*/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;### Start the new client&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;${prog[@]}&amp;quot;&lt;/span&gt; -f &amp;gt; /tmp/synergy.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Save the automator application into /Applications. Add the new application to account login items from System Preferences.&lt;/p&gt;

&lt;p&gt;Similarly, on the Synergy client (OS X Server) machine, repeat the above steps. Substitute the script content with&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;/PATH-TO-SYNERGY/synergyc -f SERVER-MACHINE-HOSTNAME &amp;gt; /tmp/synergy.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This is it. See if this helps you in any ways and let me know if the automation bit can be improved (I'm sure there are better ways to register startup processes on os x).&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://synergy2.sourceforge.net/running.html&quot; target=&quot;_blank&quot;&gt;http://synergy2.sourceforge.net/running.html&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://sourceforge.net/projects/synergy2/files/Binaries/&quot; target=&quot;_blank&quot;&gt;http://sourceforge.net/projects/synergy2/files/Binaries/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>New job starting tomorrow</title>
   <link href="http://marsbomber.github.com/2011/02/16/new-job-starting-tomorrow"/>
   <updated>2011-02-16T00:00:00-08:00</updated>
   <id>http://marsbomber.github.com/2011/02/16/new-job-starting-tomorrow</id>
   <content type="html">&lt;p&gt;I finished my last day’s work at MYOB and will be starting a new job tomorrow straight away.&lt;/p&gt;

&lt;p&gt;It’s been a very interesting journey at MYOB for the last 7 months or so. The colleagues are not just very nice, but also very knowledgable in what they do. The product we’re building is exciting and challenging (and BIG, hopefully, it’ll be launched soon, and I can start talking about it!!!). My Zend Framework and Doctrine skills are exercised on a daily basis. Even better, MYOB’s Agile methodology adoption progress is applaudable. Having the whole business behind such a methodology is easy to say, but very hard to implement. Thumbs up!!!&lt;/p&gt;

&lt;p&gt;Moving on to the new job at ProjectProject. Technically, it’s a whole new chapter for me. Ruby will be used over PHP. To me, this change is like having dinner with knives and forks instead of chopsticks. It’ll be a new set of tools to learn and master. Luckily at the new company, the business guys are adventurous and smart, the dev guys are nice and sharp. I’m sure I’ll learn heaps and contribute heaps from and to my new role.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Open folder in Textmate</title>
   <link href="http://marsbomber.github.com/2011/01/08/open-folder-in-textmate"/>
   <updated>2011-01-08T03:51:41-08:00</updated>
   <id>http://marsbomber.github.com/2011/01/08/open-folder-in-textmate</id>
   <content type="html">&lt;p&gt;This is a note to myself. Create an automator service with&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-360&quot; title=&quot;Open folder in Textmate&quot; src=&quot;/images/posts/Open-folder-in-Textmate.png&quot; alt=&quot;&quot; width=&quot;617&quot; height=&quot;325&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Saving the script as &quot;Open in Textmate&quot;. From now on, I can right click on any file or folder from Finder to open it in Textmate.&lt;/p&gt;

&lt;p&gt;Reference: &lt;a href=&quot;http://justaddwater.dk/2009/12/08/how-to-add-open-folder-in-textmate-to-finder-context-menu/&quot; target=&quot;_blank&quot;&gt;http://justaddwater.dk/2009/12/08/how-to-add-open-folder-in-textmate-to-finder-context-menu/&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>New years resolutions - 2011</title>
   <link href="http://marsbomber.github.com/2010/12/28/new-years-resolutions-2011"/>
   <updated>2010-12-28T02:02:56-08:00</updated>
   <id>http://marsbomber.github.com/2010/12/28/new-years-resolutions-2011</id>
   <content type="html">&lt;p&gt;It's been another year. 2010 is at its end. Now it's time to review my 2010 resolutions and set goals for 2011.&lt;/p&gt;

&lt;p&gt;Goals I set for 2010. Half are achieved.&lt;/p&gt;

&lt;p&gt;I ended up having no time to make a Titanium mobile app nor a RoR pet project. This was partly caused by me starting a new job in July. As for the house, I did get a mower for the lawn. However nothing's done to the house itself. We might just leave it as it, and do something major to it later on (maybe 2012).&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;del datetime=&quot;2010-12-28T09:10:27+00:00&quot;&gt;Take a get-away holiday. It’s been almost 4 years since my last proper holiday. My wife deserves better …&lt;/del&gt;&lt;/li&gt;
    &lt;li&gt;&lt;del datetime=&quot;2010-12-28T09:10:27+00:00&quot;&gt;Cutback on freelancing and spend more time with family, especially my son, Oscar.&lt;/del&gt;&lt;/li&gt;
    &lt;li&gt;Do something with the house please … paint the doors, replace the windows, fix up the deck and more importantly let’s mow the bloody lawn.&lt;/li&gt;
    &lt;li&gt;Make one hobby mobile application using “Titanium”.&lt;/li&gt;
    &lt;li&gt;Learn Ruby on Rails by writing one side project.&lt;/li&gt;
    &lt;li&gt;&lt;del datetime=&quot;2010-12-28T09:10:27+00:00&quot;&gt;Add a portfolio page to the ElinkMedia site.&lt;/del&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Looking forward, following are the things I want to achieve in 2011.&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;Work hard on my MYOB works. Make the project we're working on a big success!&lt;/li&gt;
    &lt;li&gt;Work smart on my freelance works. Try getting recurring income.&lt;/li&gt;
    &lt;li&gt;Rails 3 is out for a while now. I WILL make a pet RoR app this year!&lt;/li&gt;
    &lt;li&gt;Get myself into Test Driven Development and study Behaviour Driven Development.&lt;/li&gt;
    &lt;li&gt;Keep spending quality time with family. At least 2 road trips.&lt;/li&gt;
    &lt;li&gt;Take over the duty of sending Oscar to his childcare (that is 3 mornings a week).&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;This is it. I'll see how I'm tracking throughout 2011.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>NHibernate - update tables with triggers</title>
   <link href="http://marsbomber.github.com/2010/11/17/nhibernate-update-tables-with-triggers"/>
   <updated>2010-11-17T22:06:05-08:00</updated>
   <id>http://marsbomber.github.com/2010/11/17/nhibernate-update-tables-with-triggers</id>
   <content type="html">&lt;p&gt;I was finishing off the windows service project I was working on. After installing the windows service on the production server, I got exceptions thrown by Castle ActiveRecord. After looking into the stack trace, I found that NHibernate was throwing exceptions like &quot;Unexpected row count: 2; expected: 1&quot;.&lt;/p&gt;

&lt;p&gt;After some investigation, I found this exception was caused by the trigger implemented on a database table that NHibernates tries to update.&lt;/p&gt;

&lt;p&gt;Not sure if this is a database specific error. My application interacts with a MS SQL Server 2005 instance. The workaround is kinda simple.&lt;/p&gt;

&lt;p&gt;In the trigger, find the statement that does the updates. Wrap it with &quot;SET NOCOUNT ON&quot; and &quot;SET NOCOUNT OFF&quot;. Issue fixed.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Enable Memcache on MAMP</title>
   <link href="http://marsbomber.github.com/2010/11/02/enable-memcache-on-mamp"/>
   <updated>2010-11-02T01:59:40-07:00</updated>
   <id>http://marsbomber.github.com/2010/11/02/enable-memcache-on-mamp</id>
   <content type="html">&lt;p&gt;I switched to MAMP from XAMPP for a while. A few days back I needed to make my localdev PHP script use Memcached servers. After some digging around, I found this nice post &lt;a href=&quot;http://www.lullabot.com/articles/setup-memcached-mamp-sandbox-environment&quot; target=&quot;_blank&quot;&gt;http://www.lullabot.com/articles/setup-memcached-mamp-sandbox-environment&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I simply followed the steps to setup my local memcached service. However when I try to enable my local MAMP with the memcache module, I ran into some issues. Since I use PHP 5.3.2 on my localdev, I couldn't find a suitable memcache.so to plugin to my MAMP installation. So, I did some research, and compiled the it myself from source. Here's how I did it&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download PHP 5.3.2 source&lt;/li&gt;
&lt;li&gt;Untar the source and place everything into /Applications/MAMP/bin/php5.3/include/php&lt;/li&gt;
&lt;li&gt;Open terminal and go to the /Applications/MAMP/bin/php5.3/include/php directory&lt;/li&gt;
&lt;li&gt;Run ./configure to generate all necessary header files, which will be used to compile memcache.so&lt;/li&gt;
&lt;li&gt;Download the stable version of memcache from PECL&lt;/li&gt;
&lt;li&gt;Unpack the source and go into that directory from terminal&lt;/li&gt;
&lt;li&gt;Run the following&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;jimli@Jim-Lis-MBP: phpize
jimli@Jim-Lis-MBP: &lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-O3 -fno-common -arch i386 -arch x86_64 -g -Os&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;LDFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-O3 -arch i386 -arch x86_64&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CXXFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-O3 -fno-common -arch i386 -arch x86_64 -g -Os&amp;#39;&lt;/span&gt; ./configure --disable-dependancy-tracking --disable-shared -enable-static
jimli@Jim-Lis-MBP: make
jimli@Jim-Lis-MBP: sudo cp modules/memcache.so /Applications/MAMP/bin/php5.3/lib/php/extensions/no-debug-non-zts-20090626/.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Enable memcache from php.ini, restart MAMP&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;That's it. Hope you find it's useful.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.lullabot.com/articles/setup-memcached-mamp-sandbox-environment&quot; target=&quot;_blank&quot;&gt;http://www.lullabot.com/articles/setup-memcached-mamp-sandbox-environment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Castle AR and NHibernate</title>
   <link href="http://marsbomber.github.com/2010/08/01/castle-an-nhibernate"/>
   <updated>2010-08-01T05:23:08-07:00</updated>
   <id>http://marsbomber.github.com/2010/08/01/castle-an-nhibernate</id>
   <content type="html">&lt;p&gt;It's been a while since my last post. So a bit update first.&lt;/p&gt;

&lt;p&gt;Lots of things actually happened or happening in July. I started a new job from the start of the July, hence very busy! I also needed to help out my former employer for the hiring of the new developer. The interview process was quite tiring, but very different and very challenging. I actually enjoyed it and I believe I learnt a lot from it.&lt;/p&gt;

&lt;p&gt;As for the technical development side, with my new job, I'm doing a new project in Zend Framework of course. I'm getting my grasp of it and hopefully I can make some valuable contributions along the way. I'm also finishing off a C#.Net project for my former employer as well. This blog post will be about the 2 .Net libraries that I used for this project.&lt;/p&gt;

&lt;p&gt;For this .Net project, I started with using the NHibernate ORM library. I found my hate of XML configuration pretty soon after I kick started the project. Consider the complexity of this application is quite low, I jumped on the Castle ActiveRecord library, which uses NHibernate as the underlying ORM.&lt;/p&gt;

&lt;p&gt;Don't want to offend anyone, but the documentation of both libraries are quite average. So here are some STUFF I had to trial and error to find out myself.&lt;/p&gt;

&lt;p&gt;1st, for a ASP.Net project, here's part of the Web.config to get Castle going and also logging the raw SQLs that are generated by NHibernate.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;configSections&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- your normal stuff ... --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;section&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;activerecord&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;section&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;log4net&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;log4net.Config.Log4NetConfigurationSectionHandler, log4net&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configSections&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;activerecord&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;isWeb=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;isDebug=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;config&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;connection.provider&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernate.Connection.DriverConnectionProvider&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;dialect&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernate.Dialect.MsSql2000Dialect&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;connection.driver_class&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernate.Driver.SqlClientDriver&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;connection.connection_string&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Data Source=JIMLIWIN7\SQLEXPRESS;Initial Catalog=DBNAME;Persist Security Info=True;User ID=USER;Password=PASSWORD&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;proxyfactory.factory_class&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;show_sql&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/config&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/activerecord&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;log4net&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;appender&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernateRollingFileAppender&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;log4net.Appender.RollingFileAppender&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;file&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;LogNHibernate.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;appendToFile&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;rollingStyle&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Size&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;datePattern&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;yyyyMMdd&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;maxSizeRollBackups&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;10&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;maximumFileSize&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;10MB&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;layout&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;log4net.Layout.PatternLayout&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;conversionPattern&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;%date - %message%newline&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/layout&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/appender&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;logger&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernate.SQL&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;additivity=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;level&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;DEBUG&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ALL, DEBUG, INFO, WARN, ERROR, FATAL or OFF --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;appender-ref&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ref=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;NHibernateRollingFileAppender&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/logger&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/log4net&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;2nd, in my entity classes, I have properties that are linked to nullable fields. To get this whole AR thing happy, I do the following. The trick is the &quot;?&quot;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;n&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_dateDeleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;DateDeleted&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ColumnType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Timestamp&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateDeleted&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_dateDeleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_dateDeleted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;There are other things that have killed me hours. But I think those are just because of my own stupidity and incompetency in .NET ... So I'll keep those to myself. Bye for now.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Zend Framework 1 and Doctrine 2 integration - modular setup</title>
   <link href="http://marsbomber.github.com/2010/06/19/zf1-doctrine2-integration-modular"/>
   <updated>2010-06-19T19:11:12-07:00</updated>
   <id>http://marsbomber.github.com/2010/06/19/zf1-doctrine2-integration-modular</id>
   <content type="html">&lt;p&gt;This is a follow up post to my previous &quot;&lt;a href=&quot;http://blog.elinkmedia.net.au/2010/06/19/zf1-doctrine2-integration/&quot;&gt;Zend Framework 1 and Doctrine 2 integration&lt;/a&gt;&quot;.&lt;/p&gt;

&lt;p&gt;I've created a new branch on my Github project &quot;zf1-doctrine2&quot;. The &quot;modular_setup&quot; branch shows how we could setup Zend Framework with the modular approach, while still be able to use Doctrine 2 as the ORM for each module.&lt;/p&gt;

&lt;p&gt;Oh well, the idea is to make each module decoupled with the rest of the application, so really, you could use whatever database handling mechanism in each module.&lt;/p&gt;

&lt;p&gt;Check it out from my Github project &lt;a href=&quot;http://github.com/marsbomber/zf1-doctrine2/tree/modular_setup&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://github.com/marsbomber/zf1-doctrine2/tree/modular_setup&quot; target=&quot;_blank&quot;&gt;http://github.com/marsbomber/zf1-doctrine2/tree/modular_setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Zend Framework 1 and Doctrine 2 integration</title>
   <link href="http://marsbomber.github.com/2010/06/18/zf1-doctrine2-integration"/>
   <updated>2010-06-18T21:18:37-07:00</updated>
   <id>http://marsbomber.github.com/2010/06/18/zf1-doctrine2-integration</id>
   <content type="html">&lt;p&gt;Doctrine 2 is in beta. It is for sure one of the most exciting things that caught my attention recently.&lt;/p&gt;

&lt;p&gt;As a Zend Framework user, I started looking into ways to integrate Doctrine 2 with Zend Framework (currently in version 1).&lt;/p&gt;

&lt;p&gt;The same as any other times, the solutions are already out there. The integration's already been done by Giorgio Sironi's nakedphp project.&lt;/p&gt;

&lt;p&gt;So ... I borrowed code from nakedphp and put up a skeleton ZF projects myself.&lt;/p&gt;

&lt;p&gt;My sample project is available on Github. You can find it &lt;a href=&quot;http://github.com/marsbomber/zf1-doctrine2&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have a play, let me know if anything. Hope it'll help people like myself, who cannot wait to try out new and cool things.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://github.com/marsbomber/zf1-doctrine2&quot; target=&quot;_blank&quot;&gt;http://github.com/marsbomber/zf1-doctrine2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Compile APC for XAMPP on Snow Leopard</title>
   <link href="http://marsbomber.github.com/2010/05/03/compile-apc-for-xampp-on-snow-leopard"/>
   <updated>2010-05-03T22:34:14-07:00</updated>
   <id>http://marsbomber.github.com/2010/05/03/compile-apc-for-xampp-on-snow-leopard</id>
   <content type="html">&lt;p&gt;I'm using XAMPP as my local development environment on Snow Leopard. The XAMPP package does not include APC (Alternative PHP Cache). If we simply do a PECL install, you'll find that PHP complains about the APC architecture. This happens because the XAMPP for OS X is 32 bit, and Snow Leopard is 64 bit, hence PECL builds a 64 bit apc.so.&lt;/p&gt;

&lt;p&gt;To overcome this issue, we need to manually compile APC from source and here is how I did it.&lt;/p&gt;

&lt;p&gt;First, download APC source from &lt;a href=&quot;http://pecl.php.net/package/APC&quot; target=&quot;_blank&quot;&gt;http://pecl.php.net/package/APC&lt;/a&gt; and double click on the tar file within finder will unzip it.&lt;/p&gt;

&lt;p&gt;Then&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/Downloads/APC-3.1.3p1/APC-3.1.3p1/
phpize
&lt;span class=&quot;nv&quot;&gt;MACOSX_DEPLOYMENT_TARGET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10.6 &lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;-arch i386 -g -Os  -pipe -no-cpp-precomp&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CCFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;-arch i386 -g -Os  -pipe&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CXXFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;-arch i386 -g -Os  -pipe&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;LDFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;-arch i386 -bind_at_load&amp;quot;&lt;/span&gt; ./configure --enable-apc --with-apxs --with-php-config&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Applications/XAMPP/xamppfiles/bin/php-config-5.3.1
make
sudo cp modules/apc.so /Applications/XAMPP/xamppfiles/lib/php/php-5.3.1/extensions/no-debug-non-zts-20090626/.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We should see no errors and we should have the new APC so file copied into our PHP extension directory.&lt;/p&gt;

&lt;p&gt;Next, enable APC from php.ini by adding the following 2 lines&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;err&quot;&gt;extension=apc&lt;/span&gt;.&lt;span class=&quot;nb&quot;&gt;so&lt;/span&gt;
apc.shm_size = &lt;span class=&quot;m&quot;&gt;32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now if you do php -m from command line, you'll see APC listed as a loaded module.&lt;/p&gt;

&lt;p&gt;Hope it helps and save you from pulling your hair out.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://pecl.php.net/package/APC&quot; target=&quot;_blank&quot;&gt;http://pecl.php.net/package/APC&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://snipt.net/mik/compile-php-extension-on-mac-pro-64-bit-os-x-leopard/&quot; target=&quot;_blank&quot;&gt;http://snipt.net/mik/compile-php-extension-on-mac-pro-64-bit-os-x-leopard/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Integrate Zend_Tool with Netbeans 6.9 beta</title>
   <link href="http://marsbomber.github.com/2010/04/26/integrate-zend_tool-with-netbeans-6-9-beta"/>
   <updated>2010-04-26T21:27:50-07:00</updated>
   <id>http://marsbomber.github.com/2010/04/26/integrate-zend_tool-with-netbeans-6-9-beta</id>
   <content type="html">&lt;p&gt;I've recently read a lot about Zend Framework (Zend_Tool) integration with Netbeans. Today I decided to download the Netbeans 6.9 beta and setup everything on my local development machine (OS X).&lt;/p&gt;

&lt;p&gt;Here is how I did it on OS X with XAMPP.&lt;/p&gt;

&lt;p&gt;First, I included Zend Framework library via a PEAR repository hosted on Google Code.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo pear channel-discover zend.googlecode.com/svn
sudo pear install zend/zend
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Completing the above will make Zend Framework available through PEAR, which should be in your PHP include_path.&lt;/p&gt;

&lt;p&gt;Next, I downloaded and extracted the minimal Zend Framework package. Then I did&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/Downloads/ZendFramework-1.10.3-minimal/bin
sudo cp zf.php /Applications/XAMPP/xamppfiles/bin/zf.php
sudo cp zf.sh /Applications/XAMPP/xamppfiles/bin/zf
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;After this, I can run zf from command line without having any errors. So ... I did this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;zf --setup storage-directory
zf --setup config-file
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I can now download the latest Netbeans 6.9 beta and do the normal install. After installation, start up Netbeans, go to &quot;Netbeans&quot; -&gt; &quot;Preferences&quot; from the menu bar. Navigate to the &quot;PHP&quot; -&gt; &quot;Zend&quot; section. Enter &quot;/Applications/XAMPP/xamppfiles/bin/zf&quot; into the &quot;Zend script&quot; input box. Then click on &quot;Register Provider&quot; button.&lt;/p&gt;

&lt;p&gt;Now Netbeans should have updated the zf config file, which I created by running the &quot;zf --setup config-file&quot; command. And at this stage, I can create Zend Framework based projects and run &quot;zf&quot; commands to manipulate my projects within Netbeans.&lt;/p&gt;

&lt;p&gt;However, if I jump back to the terminal shell, I would notice the good old &quot;zf&quot; command is broken and complaining it cannot find a file called &quot;NetBeansCommandsProvider.php&quot;. Since I still want my terminal command line zf script working, I did this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo ln -s /Applications/NetBeans/NetBeans&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;6.9&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Beta.app/Contents/Resources/NetBeans/php/zend/NetBeansCommandsProvider.php /Applications/XAMPP/xamppfiles/lib/php/pear/NetBeansCommandsProvider.php
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now I am happy. Hope someone find it's useful&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Config phpUnderControl for ZF based applications</title>
   <link href="http://marsbomber.github.com/2010/03/21/config-phpundercontrol-for-zf-apps"/>
   <updated>2010-03-21T17:35:49-07:00</updated>
   <id>http://marsbomber.github.com/2010/03/21/config-phpundercontrol-for-zf-apps</id>
   <content type="html">&lt;p&gt;I recently reinstalled my MacBook Pro, and it proves that my earlier post on &lt;a href=&quot;http://blog.elinkmedia.net.au/2010/02/04/setup-phpundercontrol-on-snow-leopard/&quot;&gt;how to setup phpUnderCotnrol on Snow Leopard&lt;/a&gt; work well. I just followed the steps and phpUnderControl's up and running again.&lt;/p&gt;

&lt;p&gt;Now, I want to go into the details a bit to show the configurations I have done to use phpUnderControl to do continuos integration for my Zend Framework based applications. The testing application I used here is the ZFDoctrine12 project I've created. You could pull down the source code of it from &lt;a href=&quot;http://github.com/marsbomber/zf-with-doctrine/&quot; target=&quot;_blank&quot;&gt;my github project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, I create the necessary folder structure for a new phpUnderControl project, as well as the ant build file.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12
sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12/source
sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12/build
sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12/build/api
sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12/build/coverage
sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12/build/logs
sudo mkdir /opt/cruisecontrol/projects/zfdoctrine12/build/php-code-browser
sudo touch /opt/cruisecontrol/projects/zfdoctrine12/build.xml
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Next, the ant build file content. You can see it's fairly minimal, but you should get the idea and know how to beef it up&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;zfdoctrine12&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;default=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;basedir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;depends=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;php-codesniffer,phpunit&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;php-codesniffer&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;exec&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;executable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phpcs&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;${basedir}/source&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;output=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;${basedir}/build/logs/checkstyle.xml&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;error=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/var/tmp//checkstyle.error.log&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;arg&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;line=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;-n --report=checkstyle --standard=ZEND application&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/exec&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;target&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phpunit&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;exec&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;executable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phpunit&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;${basedir}/source/tests&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;failonerror=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;arg&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;line=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot; --log-junit ${basedir}/build/logs/phpunit.xml --coverage-clover ${basedir}/build/logs/phpunit.coverage.xml --coverage-html ${basedir}/build/coverage&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/exec&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Next, I want to clone the project from my local git repository into my phpUnderControl monitored project directory. To do this, we do&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /opt/cruisecontrol/projects/zfdoctrine12/source/
sudo git clone ~/Sites/zfdoctrine12/ .
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can see that I'm only cloning the project from my local project repository, however this can be easily changed to utilise a remote git repository. e.g. repositories hosted on github.&lt;/p&gt;

&lt;p&gt;I admit that after doing the git clone, I had to manually create and copy a couple of files. This was because of my .gitignore file from my local repository. So, go to the .gitignore file from your project repo, and do whatever changes that make sense to you.&lt;/p&gt;

&lt;p&gt;Now, let's setup the phpUnderControl config.xml file, to make phpUnderControl become aware of our newly created project. Add the following XML snippet to your /opt/cruisecontrol/config.xml.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;zfdoctrine12&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;listeners&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;currentbuildstatuslistener&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;logs/${project.name}/status.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/listeners&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;modificationset&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;quietperiod=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;60&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;git&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;localWorkingCopy=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/source/&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/modificationset&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;bootstrappers&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;gitbootstrapper&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;localWorkingCopy=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/source/&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/bootstrappers&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;schedule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;interval=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;300&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ant&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;anthome=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;apache-ant-1.7.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;buildfile=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build.xml&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/schedule&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;log&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;logs/${project.name}&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;merge&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/logs/&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/log&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;publishers&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/api&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;subdirectory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/coverage&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;subdirectory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;coverage&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;execute&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;command=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phpcb&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;              --log projects/${project.name}/build/logs&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;              --source projects/${project.name}/source&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;              --output projects/${project.name}/build/php-code-browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/php-code-browser&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;subdirectory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;php-code-browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;execute&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;command=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/Applications/XAMPP/xamppfiles/bin/phpuc graph logs/${project.name} artifacts/${project.name}&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;buildresultsurl=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://localhost:8080/cruisecontrol/buildresults/zfdoctrine12&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;mailhost=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;smtp.gmail.com&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;mailport=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;465&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;usessl=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;username=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;USERNAME&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;password=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;PASSWORD&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;returnaddress=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;SENDER_EMAIL&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;always&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;address=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;RECIPIENT_EMAIL&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/publishers&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The above project config tells CruiseControl to look for VCS (git in this case) changes, if any changes are detected, a build will be triggered every 5 min. The result is then emailed out to a nominated email address.&lt;/p&gt;

&lt;p&gt;This is it. It should give you a start point, and then it's up to you to tune it yourself. Hope it helps for people like myself, who is a beginner in Continuous Integration.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt; &lt;a href=&quot;http://blog.elinkmedia.net.au/2010/02/04/setup-phpundercontrol-on-snow-leopard/&quot; target=&quot;_blank&quot;&gt;http://blog.elinkmedia.net.au/2010/02/04/setup-phpundercontrol-on-snow-leopard/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://cruisecontrol.sourceforge.net/main/configxml.html&quot; target=&quot;_blank&quot;&gt;http://cruisecontrol.sourceforge.net/main/configxml.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Day 1 of learning Symfony</title>
   <link href="http://marsbomber.github.com/2010/03/06/day-1-of-learning-symfony"/>
   <updated>2010-03-06T20:51:37-08:00</updated>
   <id>http://marsbomber.github.com/2010/03/06/day-1-of-learning-symfony</id>
   <content type="html">&lt;p&gt;Long weekend. I'll try to keep it short.&lt;/p&gt;

&lt;p&gt;I'm a Zend Framework devotee. However Symfony is always on my to-learn list. I'm finally motivated today to give it a crack. Not to deny, a potential job lead also plays an important part in this.&lt;/p&gt;

&lt;p&gt;I just spent the last 2 hours to download the library via SVN, follow the &quot;Practical symfony&quot; guide to setup a project and everything. All pretty straight forward. I'm on &quot;Day 5&quot; of the guide now. I'll stop here and finish the &quot;tech&quot; part of the day with this post (before my wife goes mad at me ...).&lt;/p&gt;

&lt;p&gt;So, what do I think about Symfony?&lt;/p&gt;

&lt;p&gt;People talk about the steep learning curve of studying Symfony, but I didn't find it's too hard to follow. I think this is because of 2 reasons. 1, I understand the MVC pattern pretty well from my Zend Framework projects. 2, Symfony has got heaps of similarity to Ruby on Rails and I have finished reading my RoR book at the start of the year.&lt;/p&gt;

&lt;p&gt;I quite like the Symfony view helpers, the YAML style configurations, the out of the box modular approach and the command line generators.&lt;/p&gt;

&lt;p&gt;If time allows, I'll blog more about Symfony in the future. For the next a couple of weeks or so, I might have to do some C#.Net for my next project.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.symfony-project.org/jobeet/1_4/Doctrine/en/&quot; target=&quot;_blank&quot;&gt;http://www.symfony-project.org/jobeet/1_4/Doctrine/en/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Modal window over flash objects</title>
   <link href="http://marsbomber.github.com/2010/02/19/modal-window-over-flash-objects"/>
   <updated>2010-02-19T00:44:53-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/19/modal-window-over-flash-objects</id>
   <content type="html">&lt;p&gt;I've been working on a WordPress site for a client. All pretty straight forward stuff. Only special requirement from the client is to have a categorised file repository as a WordPress page, which allows users to download files. One of the categories needs to be protected. So users click on a file download link and see a modal window with a form. Fill in the details, download the file.&lt;/p&gt;

&lt;p&gt;The issue surfaced when we replaced the site banner with a flash (this is of course IE specific ...). The popup modal window slides behind the flash object. This turned out to be a common issue and the fix is simple.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;object&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;classid=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;clsid:D27CDB6E....&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;1151&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;209&amp;quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    .... you other flash params stuff ...
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;param&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;wmode&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;transparent&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/object&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The &quot;wmode&quot; transparent is the key!&lt;/p&gt;

&lt;p&gt;I'm using SimpleModal, a jQuery plugin modal library.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.ericmmartin.com/projects/simplemodal/&quot; target=&quot;_blank&quot;&gt;http://www.ericmmartin.com/projects/simplemodal/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Zend Framework on shared host</title>
   <link href="http://marsbomber.github.com/2010/02/09/zend-framework-on-shared-host"/>
   <updated>2010-02-09T03:09:14-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/09/zend-framework-on-shared-host</id>
   <content type="html">&lt;p&gt;I came across &lt;a href=&quot;http://akrabat.com/zend-framework/zend-framework-on-a-shared-host/&quot; target=&quot;_blank&quot;&gt;an article&lt;/a&gt; made by Rob Allen (author of Zend Framework in Action) today. It gives us a very nice solution on how to host a Zend Framework project on a shared host.&lt;/p&gt;

&lt;p&gt;The issue with running Zend Framework based application on a shared host is that sometimes you simply do not have the luxury to have &quot;public&quot; as your document root.  When I say &quot;public&quot;, I refer to the web root created in Zend Framework (the directory that contains index.php). Sometimes, your FTP root is your document root. This means you are forced to dump all other Zend Framework folders inside the document root.&lt;/p&gt;

&lt;p&gt;2 issues with that,&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;Security, everything becomes exposed to the web.&lt;/li&gt;
    &lt;li&gt;Ugly URL, you'll end up with something like http://mydomain.com/public/&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Rob's post addressed this problem really well.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://akrabat.com/zend-framework/zend-framework-on-a-shared-host/&quot; target=&quot;_blank&quot;&gt;http://akrabat.com/zend-framework/zend-framework-on-a-shared-host/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Netbeans debugger with Zend Framework</title>
   <link href="http://marsbomber.github.com/2010/02/08/netbeans-debugger-with-zend-framework"/>
   <updated>2010-02-08T01:28:06-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/08/netbeans-debugger-with-zend-framework</id>
   <content type="html">&lt;p&gt;Are you sick of doing var dumps on browser screens or error logs when you need to debug some errors? Have you seen the .Net guys step through their code line by line to figure out what went wrong? With PHP, you can do the same. Here's how I do it.&lt;/p&gt;

&lt;p&gt;The IDE I use is Netbeans (6.8 on Mac). It's shipped with a built-in debugger, which works with Xdebug.&lt;/p&gt;

&lt;p&gt;So ... we first need to make sure our PHP is running Xdebug instead of Zend. I have explained how I have Xdebug setup on my XAMPP stack on Mac from one of my previous posts, &lt;a href=&quot;http://blog.elinkmedia.net.au/2010/02/04/setup-phpundercontrol-on-snow-leopard/&quot; target=&quot;_blank&quot;&gt;Setup phpUnderControl on Snow Leopard&lt;/a&gt;. We can verify whether Xdebug is setup properly by loading up our phpinfo page. We should see something like this (notice the last line prints Xdebug)&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-232&quot; title=&quot;xdebug-php&quot; src=&quot;/images/posts/xdebug-php.png&quot; alt=&quot;&quot; width=&quot;609&quot; height=&quot;86&quot; /&gt;Now, let's go to Netbeans. Netbeans out of the box listens on port 9000, which is the exact port number we set our Xdebug remote_port to in our previous step. This means if we are not running our application with mod_rewrite, we now should be able to set a breakpoint in our code, hit the debug icon, and have everything going.&lt;/p&gt;

&lt;p&gt;But ... there's always a but. When we develop Zend Framework based applications, in fact any applications that utilising mod_rewrite. We will run into trouble. We'll find the debugger always hits the index controller, index action. To overcome this, we need to do the following.&lt;/p&gt;

&lt;p&gt;Go to the Zend Framework application's project property in Netbeans. Go to the &quot;Run Configuration&quot; option. Click on Advanced. For &quot;Debug URL&quot;, choose &quot;Ask Every Time&quot;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-238&quot; title=&quot;zf-project-property&quot; src=&quot;/images/posts/zf-project-property1.png&quot; alt=&quot;&quot; width=&quot;721&quot; height=&quot;428&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, if we want to debug the email action from the index controller, when we hit the debug icon in Netbeans, it'll pop up a dialog box asking us to type in the debug URL.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-235&quot; title=&quot;set-debug-url&quot; src=&quot;/images/posts/set-debug-url1.png&quot; alt=&quot;&quot; width=&quot;648&quot; height=&quot;294&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once we Ok the dialog, Firefox will fire up (after you install the Netbeans debugger), and off you go!&lt;/p&gt;

&lt;p&gt;The screenshots above are grabbed from my &lt;a href=&quot;http://github.com/marsbomber/zf-with-doctrine&quot; target=&quot;_blank&quot;&gt;ZFWithDoctrine project&lt;/a&gt; on github.&lt;/p&gt;

&lt;p&gt;That's it, and hope it helps.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>File include cache in Zend Framework</title>
   <link href="http://marsbomber.github.com/2010/02/06/file-include-cache-in-zend-framework"/>
   <updated>2010-02-06T18:12:18-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/06/file-include-cache-in-zend-framework</id>
   <content type="html">&lt;p&gt;Another box of tissue gone ... runny nose syndrome continues ... still cannot type or think ...&lt;/p&gt;

&lt;p&gt;Let me now blog something simple, but handy.&lt;/p&gt;

&lt;p&gt;Problem ... Zend Framework uses many types of plugins, how do we efficiently tell the application where to find the plugin files? For example, when we use a view helper, should our application find it in the Zend library directory? Should our application find it in the application view helpers directory? Or should the application find it at our own custom library directory?&lt;/p&gt;

&lt;p&gt;Fix ... it's easy.&lt;/p&gt;

&lt;p&gt;Make the following extra line of config in your application config file&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;err&quot;&gt;cache&lt;/span&gt;.&lt;span class=&quot;nb&quot;&gt;classFileIncludeCache&lt;/span&gt; = APPLICATION_PATH &lt;span class=&quot;s2&quot;&gt;&amp;quot;/../data/pluginLoaderCache.php&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add the following code to your Bootstrap.php&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;/**&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt; * Setup include file cache to increase performance&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt; * @return void&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt; * @author Jim Li&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt; */&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;protected function _initFileInlcudeCache()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    $classFileIncCacheOptions = $this-&amp;gt;getOption(&amp;#39;cache&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    $classFileIncCache = $classFileIncCacheOptions[&amp;#39;classFileIncludeCache&amp;#39;];&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;    if(file_exists($classFileIncCache)) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        include_once $classFileIncCache;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Attention: make sure the &quot;/data/&quot; directory is writable by your web server.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://framework.zend.com/manual/en/zend.loader.pluginloader.html#zend.loader.pluginloader.performance.example&quot; target=&quot;_blank&quot;&gt;http://framework.zend.com/manual/en/zend.loader.pluginloader.html#zend.loader.pluginloader.performance.example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Zend Framework integrate with Symfony DI Container</title>
   <link href="http://marsbomber.github.com/2010/02/06/zend-framework-integrate-with-symfony-di-container"/>
   <updated>2010-02-06T03:57:25-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/06/zend-framework-integrate-with-symfony-di-container</id>
   <content type="html">&lt;p&gt;I want to integrate Symfony DI Container and Zend Framework together. It's been put on the back burner for a while. After trashed a box of tissue because of my runny nose today, I finally got something up. And let me share it here.&lt;/p&gt;

&lt;p&gt;I'm not going to explain what dependency injection means, and how the Symfony DI Contain works here ... I'm actually not going to explain anything here today(I feel really crap at the moment) ... I'll find another time to get into the details.&lt;/p&gt;

&lt;p&gt;For now, you can head to github, download the source code and have a play. Just make sure that the &quot;/data/&quot; directory is writable by your web server, hence it is used to store the generated DI service class file.&lt;/p&gt;

&lt;p&gt;Download&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://github.com/marsbomber/zf-with-doctrine&quot; target=&quot;_blank&quot;&gt;http://github.com/marsbomber/zf-with-doctrine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://blog.starreveld.com/2009/11/using-symfony-di-container-with.html&quot; target=&quot;_blank&quot;&gt;http://blog.starreveld.com/2009/11/using-symfony-di-container-with.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Beautify Zend Framework project error pages</title>
   <link href="http://marsbomber.github.com/2010/02/04/beautify-zend-framework-project-error-pages"/>
   <updated>2010-02-04T04:20:57-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/04/beautify-zend-framework-project-error-pages</id>
   <content type="html">&lt;p&gt;Thanks to Udo Schochtert (http://www.psiop.ch/), I become aware of this really nice Agavi style error handler. I basically followed http://www.iezzi.ch/archives/397 to get most of it going. However there are 2 little glitches I want to point out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you follow http://www.iezzi.ch/archives/397, most likely you'll forget, or not even aware of this (Thanks to Udo again, he pointed this out in the original blog's comments section). In the application.ini file, we need to add&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;resources.frontController.errorview = shiny&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Since I'm beautifying the ErrorController and its pages in my zf-with-doctrine project (http://github.com/marsbomber/zf-with-doctrine). I ran into issues with displaying the ZFDebug menu on the error pages. What I had to do was simple. Go to the ErrorController.php, errorAction method, and add 2 lines to disable the ZFDebug plugin&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;// Disable ZFDebug plugin&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;$frontController = Zend_Controller_Front::getInstance();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;$frontController-&amp;amp;gt;unregisterPlugin(&amp;#39;ZFDebug_Controller_Plugin_Debug&amp;#39;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;If interested, you can check my zf-with-doctrine project out from github, http://github.com/marsbomber/zf-with-doctrine&lt;/p&gt;

&lt;p&gt;Hope you like it and find it's useful.&lt;/p&gt;

&lt;p&gt;Download&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://github.com/marsbomber/zf-with-doctrine&quot; target=&quot;_blank&quot;&gt;http://github.com/marsbomber/zf-with-doctrine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.iezzi.ch/archives/397&quot; target=&quot;_blank&quot;&gt;http://www.iezzi.ch/archives/397&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Setup phpUnderControl on Snow Leopard</title>
   <link href="http://marsbomber.github.com/2010/02/03/setup-phpundercontrol-on-snow-leopard"/>
   <updated>2010-02-03T19:28:18-08:00</updated>
   <id>http://marsbomber.github.com/2010/02/03/setup-phpundercontrol-on-snow-leopard</id>
   <content type="html">&lt;p&gt;Once in a while, people do pointless things. So ... here I am. I setup phpUnderControl on Snow Leopard last night ... that's right. I know you probably will not ever run your central continuous integration service on a Mac ... but you know ... just in case. Having said this, after I installed phpUnderControl on my &quot;LOCAL&quot; machine, I think it does give me a good view of what's happening with me project, which is quite cool.&lt;/p&gt;

&lt;p&gt;First of all, I use XAMPP stack on OS X for my development. XAMPP provides us some important modules to complete the whole puzzle. Here's what I did. I'm not sure if they are all necessary, but at least I know it worked for me.&lt;/p&gt;

&lt;p&gt;With XAMPP, there are 2 important bits, the PHP and PEAR executable. I have the following&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;jimli@Jim-Lis-MacBook-Pro~: ll /usr/bin/pear
lrwxr-xr-x  1 root  wheel  39 29 Nov 08:45 /usr/bin/pear -&amp;gt; /Applications/XAMPP/xamppfiles/bin/pear
jimli@Jim-Lis-MacBook-Pro~: ll /usr/bin/php
lrwxr-xr-x  1 root  wheel  38 28 Nov 18:50 /usr/bin/php -&amp;gt; /Applications/XAMPP/xamppfiles/bin/php
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;First of all, let's install xdebug. Download the precompiled xdebug.so file from http://aspn.activestate.com/ASPN/Downloads/Komodo/RemoteDebugging&lt;/p&gt;

&lt;p&gt;Open /Applications/XAMPP/xamppfiles/etc/php.ini in an editor, append the file with&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;err&quot;&gt;[xdebug]&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;zend_extension=/Applications/XAMPP/xamppfiles/lib/php/php-5&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;3&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;0/extensions/no-debug-non-zts-20090626/xdebug&lt;/span&gt;.&lt;span class=&quot;nb&quot;&gt;so&lt;/span&gt;
xdebug.remote_enable=on
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;remote_handler=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dbgp&lt;/span&gt;
xdebug.remote_host=localhost
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;remote_port=9000&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;file_link_&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; = &lt;span class=&quot;s2&quot;&gt;&amp;quot;txmt://open?url=file://%f&amp;amp;line=%l&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Make sure the extension path is where you put the downloaded xdebug.so file to.&lt;/p&gt;

&lt;p&gt;Now, let's install a few things&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo pear channel-discover components.ez.no
sudo pear install -a ezc/Graph
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Need to set preferred_state to alpha to get phpDocumentor for some reason.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo pear config-set preferred_state alpha
sudo pear channel-discover pear.phpunit.de
sudo pear install --alldeps phpunit/phpUnderControl
sudo pear config-set preferred_state stable
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can see, we did not install phpUnit, I believe phpUnit should be shipped with the latest XAMPP by default.
Now, Download cruisecontrol &lt;a href=&quot;http://sourceforge.net/projects/cruisecontrol/files/CruiseControl/2.8.2/&quot;&gt;here&lt;/a&gt;. Locate your download from a shell and do&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo unzip cruisecontrol-bin-2.8.2.zip -d /opt
sudo ln -s /opt/cruisecontrol-bin-2.8.2 /opt/cruisecontrol
sudo phpuc install /opt/cruisecontrol
sudo phpuc example /opt/cruisecontrol
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ok. I also assume you have subversion and Java installed.
Make sure you set the JAVA_HOME path in your environment. I did this by editing ~/.bashrc&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;JAVA_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home&amp;quot;&lt;/span&gt;;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;JAVA_HOME
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You may change the path accordingly base on your Java setup.&lt;/p&gt;

&lt;p&gt;Now, edit /opt/cruisecontrol/config.xml, it should have something like&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;cruisecontrol&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;connectfour&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;listeners&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;currentbuildstatuslistener&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;logs/${project.name}/status.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/listeners&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;bootstrappers&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;antbootstrapper&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;anthome=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;apache-ant-1.7.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;buildfile=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build.xml&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;target=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;clean&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/bootstrappers&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;modificationset&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;quietperiod=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;30&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- touch any file in connectfour project to trigger a build --&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;filesystem&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;folder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/modificationset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;schedule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;interval=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;300&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ant&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;anthome=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;apache-ant-1.7.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;buildfile=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build.xml&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/schedule&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;log&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;merge&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/target/test-results&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/log&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;publishers&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;onsuccess&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/target/${project.name}.jar&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/onsuccess&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/publishers&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;php-under-control&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;listeners&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;currentbuildstatuslistener&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;logs/${project.name}/status.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/listeners&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;modificationset&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;alwaysbuild/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/modificationset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;bootstrappers/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;schedule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;interval=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;300&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ant&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;anthome=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;apache-ant-1.7.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;buildfile=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build.xml&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/schedule&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;log&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;logs/${project.name}&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;merge&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/logs/&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/log&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;publishers&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/api&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;subdirectory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;api&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/coverage&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;subdirectory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;coverage&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;      &lt;span class=&quot;nt&quot;&gt;&amp;lt;execute&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;command=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phpcb --log projects/${project.name}/build/logs --source projects/${project.name}/source/src --output projects/${pro&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;ject.name}/build/php-code-browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;      &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactspublisher&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dir=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;projects/${project.name}/build/php-code-browser&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;subdirectory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;php-code-brow&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;ser&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;execute&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;command=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/Applications/XAMPP/xamppfiles/bin/phpuc graph logs/${project.name} artifacts/${project.name}&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/publishers&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/cruisecontrol&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now you can start and stop cruisecontrol by doing&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /opt/cruisecontrol
sudo -E ./cruisecontrol.sh

&lt;span class=&quot;nb&quot;&gt;kill&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;cat /opt/cruisecontrol/cc.pid&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;After cruisecontrol is started, you can go to http://localhost:8080/cruisecontrol/ in your browser. Now everything should be good, except the metrics page. After some googling, I found this http://criticallog.thornet.net/?p=39
Basically you need to do&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /Applications/XAMPP/xamppfiles/lib/php/pear/phpUnderControl/Graph/Input/
sudo mv ClassComplexityInput.php ClassComplexityInput.php.bak
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Everything should now work!&lt;/p&gt;

&lt;p&gt;Reference:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://techportal.ibuildings.com/2009/03/03/getting-started-with-phpundercontrol/&quot; target=&quot;_blank&quot;&gt;http://techportal.ibuildings.com/2009/03/03/getting-started-with-phpundercontrol/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://criticallog.thornet.net/?p=39&quot; target=&quot;_blank&quot;&gt;http://criticallog.thornet.net/?p=39&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://aspn.activestate.com/ASPN/Downloads/Komodo/RemoteDebugging&quot; target=&quot;_blank&quot;&gt;http://aspn.activestate.com/ASPN/Downloads/Komodo/RemoteDebugging&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Doctrine tricks</title>
   <link href="http://marsbomber.github.com/2010/01/29/doctrine-tricks"/>
   <updated>2010-01-29T18:45:47-08:00</updated>
   <id>http://marsbomber.github.com/2010/01/29/doctrine-tricks</id>
   <content type="html">&lt;p&gt;I have been using Doctrine ORM for a while now. Here I want to discuss 2 tricky issues I have encountered and resolved.&lt;/p&gt;

&lt;p&gt;First, I'm paranoid of deleting records from the database. Things like registered users, I would rather have them marked as &quot;DELETED&quot;, but still keep the record in the database, just in case ...&lt;/p&gt;

&lt;p&gt;With Doctrine, the SoftDelete behaviour is perfect for this purpose. When a model is enabled with the SoftDelete behaviour, an extra field &quot;deleted_at&quot; is automatically added to the corresponding database table by default. So, when you call the delete() function on a model object, the corresponding data row in the database receives a timestamp on the &quot;deleted_at&quot; field. Data having values on the &quot;deleted_at&quot; field will not be returned by any find methods in the future.&lt;/p&gt;

&lt;p&gt;It all sounds good, right? Not until you start trying to cascade &quot;delete&quot; on associations. Since we are not really deleting the record, DBMS level delete cascading will simply not work (In Doctrine YAML schema term, the &quot;onDelete: CASCADE&quot; will not work). Now, I'll illustrate the problem and the solution with a typical blog example.&lt;/p&gt;

&lt;p&gt;In a blog application, we have 2 entities, article and comment. 1 article has many comments. When an article is &quot;soft deleted&quot;, all the associated comments should go to. The schema YAML is something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;Article:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  actAs: [Timestampable, SoftDelete]&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  columns:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    article_content:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    type: string()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  relations:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    Comments:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      foreign: article_id&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      type: many&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      cascade: [delete]&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;Comment:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  actAs:[Timestampable, SoftDelete]&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  columns:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    article_id:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      type: integer&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    comment_content:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      type: string()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  relations:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    Article:&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      foreign: id&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      type: one&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;So, you can see, the trick is done on line 10 of the yaml file. With &quot;cascade: [delete]&quot; specified. You now can soft delete an article and all associated comments by doing something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;$article = Doctrine_Core::getTable(&amp;#39;Article&amp;#39;)-&amp;gt;findOneById(1);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;$article-&amp;gt;delete();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now it works as expected.&lt;/p&gt;

&lt;p&gt;One thing I need to point out is performance. Doing SoftDelete means Doctrine will do a lot separate update queries behind the scene (to set the deleted_at field). For models with a big association list, performance could degrade dramatically. I normally enable SoftDelete on all necessary models to start with. As the project continues, my understanding of the problem domain improves too, then I look at taking the SoftDelete off some unnecessary models. If some models do need to keep historical data, and performance is becoming a problem because of SoftDelete, I then look at other data archiving strategies so that we could fix up the bottle neck again by removing the SoftDelete behaviour on the offending models.&lt;/p&gt;

&lt;p&gt;Let's move onto the next issue.&lt;/p&gt;

&lt;p&gt;There are times that your application will need to obtain a model record, hold it memory, massage some attribute values, then save it back to the database. The issue raised is that after a record (we call this record A) is retrieved and before it's saved back, if another part of your application code retrieves the same record again. By default, Doctrine will flush record A and set all attributes back to its original values. This means any changes you make in memory on record A are lost. Let's use the article model again here to illustrate the issue in code.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;$articleOne = Doctrine_Core::getTable(&amp;#39;Article&amp;#39;)-&amp;gt;findOneById(1);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;$articleOne-&amp;gt;article_contents = &amp;quot;replace old with new&amp;quot;;&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;$articleOneDup = Doctrine_Core::getTable(&amp;#39;Article&amp;#39;)-&amp;gt;findOneById(1);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;// you will see the article_contents will be reset back to its original value, changes are lost&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;var_dump($articleOne);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This is the default behaviour of Doctrine. If you ever want to change this behaviour, you could use something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;Doctrine_Manager::getInstance()-&amp;gt;setAttribute(Doctrine::ATTR_HYDRATE_OVERWRITE, false);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That's it. Hope someone find this useful.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Authentication service</title>
   <link href="http://marsbomber.github.com/2010/01/26/auth-service"/>
   <updated>2010-01-26T01:22:47-08:00</updated>
   <id>http://marsbomber.github.com/2010/01/26/auth-service</id>
   <content type="html">&lt;p&gt;This is a followup to my previous post &quot;&lt;a href=&quot;http://blog.elinkmedia.net.au/2010/01/24/zf-authentication-using-doctrine/&quot;&gt;ZF Authentication using Doctrine&lt;/a&gt;&quot;. After posting my implementation of using a ZendX doctrine auth adapter. I got some feedback from Jon Lebensold from &lt;a href=&quot;http://www.zendcasts.com/&quot; target=&quot;_blank&quot;&gt;ZendCasts&lt;/a&gt;. The issue raised is that my implementation makes the controller fat, which is considered as a bad practice. I cannot agree more on that. So ... I tried to refactor the code and come up with the introduction of a service layer class named &quot;AuthenticationService&quot;.&lt;/p&gt;

&lt;p&gt;Now the LoginController class is made thinner with the following code.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;public function loginAction()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    $authService = new Model_AuthenticationService();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    if($authService-&amp;gt;isAuthenticated() == true) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $this-&amp;gt;_redirect(&amp;#39;/index&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;    if($this-&amp;gt;getRequest()-&amp;gt;isPost()) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $this-&amp;gt;view-&amp;gt;headTitle(&amp;#39;Login&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        // collect the data from the user&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $loginUsername = $this-&amp;gt;getRequest()-&amp;gt;getParam(&amp;#39;username&amp;#39;, &amp;#39;&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $loginPassword = $this-&amp;gt;getRequest()-&amp;gt;getParam(&amp;#39;password&amp;#39;, &amp;#39;&amp;#39;);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        $authResult = $authService-&amp;gt;authenticate(&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $loginUsername,&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $loginPassword&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        );&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        if($authResult == true) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            // auth good, do your logic&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        else {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            // auth bad, do your logic&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    } else {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $this-&amp;gt;_redirect(&amp;#39;/login&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Code for AuthenticationService.php&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class Model_AuthenticationService&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    private $_authenticationMessage = &amp;#39;&amp;#39;;&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;    public function getAuthenticationMessage()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        return $this-&amp;gt;_authenticationMessage;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;    public function isAuthenticated()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        return Zend_Auth::getInstance()-&amp;gt;hasIdentity();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;    public function authenticate($username, $password)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $doctrineAuthAdapter = new ZendX_Doctrine_Auth_Adapter(&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            Doctrine_core::getConnectionByTableName(&amp;#39;Model_User&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        );&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $doctrineAuthAdapter-&amp;gt;setTableName(&amp;#39;Model_User u&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setIdentityColumn(&amp;#39;u.username&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setCredentialColumn(&amp;#39;u.password&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setIdentity($username)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setCredential(Model_Utility::encryptPassword($password));&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        $myAuth = Zend_Auth::getInstance();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $authResult = $myAuth-&amp;gt;authenticate($doctrineAuthAdapter);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        if(!$authResult-&amp;gt;isValid()) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $this-&amp;gt;_authenticationMessage = &amp;#39;You have entered invalid username and password.&amp;#39;;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            return false;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        } else {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $identity = $doctrineAuthAdapter-&amp;gt;getResultRowObject(null, &amp;#39;password&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $myAuth-&amp;gt;getStorage()-&amp;gt;write($identity);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            return true;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;As we can see, the AuthenticationService class is now doing most of the heavy lifting stuff. The controller is left with the duty of checking user login state and dispatching appropriate actions when necessary.&lt;/p&gt;

&lt;p&gt;Hope this makes sense, and again more than happy to discuss.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://blog.elinkmedia.net.au/2010/01/24/zf-authentication-using-doctrine/&quot; target=&quot;_blank&quot;&gt;http://blog.elinkmedia.net.au/2010/01/24/zf-authentication-using-doctrine/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://zendcasts.com&quot; target=&quot;_blank&quot;&gt;http://zendcasts.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>ZF authentication using Doctrine</title>
   <link href="http://marsbomber.github.com/2010/01/23/zf-authentication-using-doctrine"/>
   <updated>2010-01-23T14:27:21-08:00</updated>
   <id>http://marsbomber.github.com/2010/01/23/zf-authentication-using-doctrine</id>
   <content type="html">&lt;p&gt;Edit: There's a follow up article &lt;a href=&quot;http://blog.elinkmedia.net.au/2010/01/26/auth-service/&quot;&gt;http://blog.elinkmedia.net.au/2010/01/26/auth-service/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As one of my everyday morning tasks, I just checked the rss feeds from my news reader. Interesting enough, one of my favourite blog authors, Jon Lebensold from ZendCasts, just published a new post on &quot;&lt;a href=&quot;http://www.zendcasts.com/writing-a-zend_auth_adapter-with-doctrine/2010/01/&quot; target=&quot;_blank&quot;&gt;Writing a Zend_Auth_Adapter with Doctrine&lt;/a&gt;&quot;.&lt;/p&gt;

&lt;p&gt;The issue that we are trying to solve is to handle user login authentication from an application, which uses Zend Framework and Doctrine ORM. Jon took the approach of writing a custom zend auth adaptor to accomplish the task. I watched the video from ZendCasts, and clearly this is another quality video and it will just work for you.&lt;/p&gt;

&lt;p&gt;However here, I want to show you an alternative approach to solve the same problem. I basically used an already written authentication doctrine adapter from the ZendX incubator. The class file can be found &lt;a href=&quot;http://framework.zend.com/svn/framework/extras/incubator/library/ZendX/Doctrine/Auth/Adapter.php&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To autoload the ZendX_Doctrine_Auth_Adapter class file, obviously you need to include the file in the correct directory inside the &quot;library&quot; directory. So that is &quot;library/ZendX/Doctrine/Auth/Adapter.php&quot;.&lt;/p&gt;

&lt;p&gt;Now let's look at some code. Please note that I am only showing topic-related code here, all other security checking, error checking code have been taken out.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class LoginController extends Zend_Controller_Action&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    public function loginAction()&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        // collect the data from the user&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $loginUsername = $this-&amp;gt;getRequest()-&amp;gt;getParam(&amp;#39;username&amp;#39;, &amp;#39;&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $loginPassword = $this-&amp;gt;getRequest()-&amp;gt;getParam(&amp;#39;password&amp;#39;, &amp;#39;&amp;#39;);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        $myAuth = Zend_Auth::getInstance();&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        // do the authentication&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $authAdapter = $this-&amp;gt;_getAuthAdapter($loginUsername, $loginPassword);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $result = $myAuth-&amp;gt;authenticate($authAdapter);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        if (!$result-&amp;gt;isValid()) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            // take care of invalid login&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        } else {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            // empty password&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $identity = $authAdapter-&amp;gt;getResultRowObject(null, &amp;#39;password&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            $myAuth-&amp;gt;getStorage()-&amp;gt;write($identity);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;            // all good, do you redirect or whatever&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;    protected function _getAuthAdapter($username, $password)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;        $authAdapter = new ZendX_Doctrine_Auth_Adapter(Doctrine::getConnectionByTableName(&amp;#39;Model_User&amp;#39;));&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        $encryptedPassword = Model_Utility::encryptPassword($password);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        $authAdapter-&amp;gt;setTableName(&amp;#39;Model_User u&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setIdentityColumn(&amp;#39;u.username&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setCredentialColumn(&amp;#39;u.password&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setIdentity($username)&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;            -&amp;gt;setCredential($encryptedPassword);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;        return $authAdapter;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ok. Most of the code should be pretty self explanatory. The authentication is done with the following assumptions.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Your login users are stored in a table called &quot;user&quot;, with at least 2 columns, &quot;username&quot; and &quot;password&quot;.&lt;/li&gt;
    &lt;li&gt;You have your Doctrine &quot;Model_User&quot; class setup.&lt;/li&gt;
    &lt;li&gt;If you store encrypted or hashed passwords in your database (I do), the encryption logic is handled by a static method call from a utility class, &quot;Model_Utility&quot;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is it. In our case, we do not need to create an authentication method in &quot;Model_User&quot; as Jon showed us in his video tutorial. The authentication magic is all done by the &quot;ZendX_Doctrine_Auth_Adapter&quot; class.&lt;/p&gt;

&lt;p&gt;Hope you find this useful and let me know if you have issues or suggestions.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.zendcasts.com/writing-a-zend_auth_adapter-with-doctrine/2010/01/&quot; target=&quot;_blank&quot;&gt;http://www.zendcasts.com/writing-a-zend_auth_adapter-with-doctrine/2010/01/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>New year's resolution</title>
   <link href="http://marsbomber.github.com/2010/01/06/new-years-resolution"/>
   <updated>2010-01-06T02:20:01-08:00</updated>
   <id>http://marsbomber.github.com/2010/01/06/new-years-resolution</id>
   <content type="html">&lt;p&gt;It's 2010 and it's again time to set goals. It's important that the goals are realistic and achievable. So ... here they are&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;Take a get-away holiday. It's been almost 4 years since my last proper holiday. My wife deserves better ...&lt;/li&gt;
    &lt;li&gt;Cutback on freelancing and spend more time with family, especially my son, Oscar.&lt;/li&gt;
    &lt;li&gt;Do something with the house please ... paint the doors, replace the windows, fix up the deck and more importantly let's mow the bloody lawn.&lt;/li&gt;
    &lt;li&gt;Make one hobby mobile application using &quot;Titanium&quot;.&lt;/li&gt;
    &lt;li&gt;Learn Ruby on Rails by writing one side project.&lt;/li&gt;
    &lt;li&gt;Add a portfolio page to the ElinkMedia site.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;It really sounds like a relaxing year from the programming side. That's right! Family is this year's focus.&lt;/p&gt;

&lt;p&gt;I'll keep updating this post and hopefully I can tick off all 6 items at the end of year 2010.&lt;/p&gt;

&lt;p&gt;Happy new year!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>ZF, Doctrine and Unit Tests</title>
   <link href="http://marsbomber.github.com/2009/12/03/zf-doctrine-and-unit-tests"/>
   <updated>2009-12-03T02:44:13-08:00</updated>
   <id>http://marsbomber.github.com/2009/12/03/zf-doctrine-and-unit-tests</id>
   <content type="html">&lt;p&gt;Recently there are a lot of very interesting blog posts about using Zend Framework with the Doctrine ORM. I am really glad to see more and more people start talking about application design patterns, test driven development, etc. This trend means the PHP community is preparing to take PHP into the next level (enterprise? no?) . As a PHP developer, I see a lot of things to learn.&lt;/p&gt;

&lt;p&gt;Back to the topic. I've been testing to use both Zend Framework and Doctrine for a while now. As a matter of fact, I never really have them hook up perfectly. The issue I faced was about the Doctrine command line tool. I just cannot manage to bootstrap the Doctrine command line script correctly. I can get Doctrine command line script to drop database, create database, generate models in PEAR style (which is used by the Zend Framework) from the yaml schema file. But I cannot get it to create tables, generate SQL, etc.&lt;/p&gt;

&lt;p&gt;This did not seem to be a real issue until I started wondering about unit test my Doctrine model classes. Ideally, when I do my unit tests, I can re-create my testing database, reload my data fixture file. So ... I started digging.&lt;/p&gt;

&lt;p&gt;Eric Leclerc made a really helpful &lt;a href=&quot;http://www.danceric.net/2009/10/29/doctrine-1-2-is-zend-framework-friendly/&quot; target=&quot;_blank&quot;&gt;blog post&lt;/a&gt; recently about setting up Zend Framework and Doctrine. Even better, Eric kindly created a &lt;a href=&quot;http://github.com/danceric/zfdebugdoctrine&quot; target=&quot;_blank&quot;&gt;sample application&lt;/a&gt; on github. I downloaded it, had a play, worked really well!&lt;/p&gt;

&lt;p&gt;Next is unit testing. Lucky we still have Jon Lebensold, the creator of ZendCasts. Jon just made another great podcast on &quot;&lt;a href=&quot;http://www.zendcasts.com/writing-doctrine-unit-tests-with-zend_test/2009/12/&quot; target=&quot;_blank&quot;&gt;Writing Doctrine Unit Tests with Zend_Test&lt;/a&gt;&quot; yesterday. I downloaded the source code from Jon's episode. I started merging it with Eric's sample application.&lt;/p&gt;

&lt;p&gt;After some tweaks and changes. I believe I finally have a working copy. That is Zend Framework + Doctrine + ZFDebug + Zend_Test. All in one project (no need to create models in a model generator project with Doctrine, copy them across to my ZF application).&lt;/p&gt;

&lt;p&gt;I have pushed my sample application to github to share with others who are interested in using Doctrine with Zend Framework. You can find the application at &lt;a href=&quot;http://github.com/marsbomber/zf-with-doctrine&quot;&gt;http://github.com/marsbomber/zf-with-doctrine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope it helps. And also, my sincere thanks to Eric Leclerc and Jon Lebensold.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.danceric.net/2009/10/29/doctrine-1-2-is-zend-framework-friendly/&quot; target=&quot;_blank&quot;&gt;http://www.danceric.net/2009/10/29/doctrine-1-2-is-zend-framework-friendly/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://github.com/danceric/zfdebugdoctrine&quot; target=&quot;_blank&quot;&gt;http://github.com/danceric/zfdebugdoctrine&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.zendcasts.com/writing-doctrine-unit-tests-with-zend_test/2009/12/&quot; target=&quot;_blank&quot;&gt;http://www.zendcasts.com/writing-doctrine-unit-tests-with-zend_test/2009/12/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://github.com/marsbomber/zf-with-doctrine&quot; target=&quot;_blank&quot;&gt;http://github.com/marsbomber/zf-with-doctrine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Titanium development platform</title>
   <link href="http://marsbomber.github.com/2009/11/14/titanium-dev-platform"/>
   <updated>2009-11-14T22:58:56-08:00</updated>
   <id>http://marsbomber.github.com/2009/11/14/titanium-dev-platform</id>
   <content type="html">&lt;p&gt;There are occasions that desktop application become required as part of a project. To me, as a PHP application developer, this is almost impossible. PHP is a scripting language used by the web. Desktop application and PHP almost do not link at all.&lt;/p&gt;

&lt;p&gt;Until recently I came across the Titanium solution. It bridges the gap between PHP and the native OS platform. With Titanium, I can enjoy building desktop, even mobile, applications using the technology that I am comfortable with. That is build desktop and mobile applications with PHP, HTML, CSS and Javascript. Sounds familiar? That's right! We can now utilise the whole web development technology to build desktop apps. Just like Adobe Air, minus the learning curve of flash, actionscripts, etc. Having said this, PHP just became supported by Titanium. So things are just shaping out, but I believe we should have a very workable platform once Titanium comes out of its beta.&lt;/p&gt;

&lt;p&gt;The lack of PHP support might not be an issue if we think about application design. The desktop application we build might just be a thin client, which acts as a browser replacement. It might be a good practice to actually keep all the complex domain logic on the web/application server. We could then use the SOA approach to make thin client functional by calling exposed web service methods by the server.&lt;/p&gt;

&lt;p&gt;Anyway, we should definitely keeping an eye on this one! &lt;a href=&quot;http://www.appcelerator.com/&quot; target=&quot;_blank&quot;&gt;http://www.appcelerator.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's next? I'm having a break from my freelancing works at the moment. I'm actually waiting for my Ruby on Rails book, Agile Web Development with Rails, to arrive (Right! I'm self-learning RoR). Amazon seems to be running out of stock on this particular one ... Luck that I borrowed a book from a good friend of mine last night. It'll keep me busy for a while, and my friend has got another book that I'll borrow and read (Currently have &quot;Domain-Driven Design&quot; by Eric Evans, and &quot;Patterns of Enterprise Application Architecture&quot; by Martin Fowler is on the list).&lt;/p&gt;

&lt;p&gt;Hopefully I should be able to talk something about the &quot;Domain-Driven Design&quot; book in my next post. Keep tuned!!!&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.appcelerator.com/&quot; target=&quot;_blank&quot;&gt;http://www.appcelerator.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Application logging with Zend_Log</title>
   <link href="http://marsbomber.github.com/2009/10/22/application-logging-with-zend_log"/>
   <updated>2009-10-22T18:20:34-07:00</updated>
   <id>http://marsbomber.github.com/2009/10/22/application-logging-with-zend_log</id>
   <content type="html">&lt;p&gt;It's been a while since my last post here... I've been pretty busy with projects and other things. However I did manage to finish the book I recently bought, Zend Enterprise PHP Patterns. It's an interesting book. Even the book title mentions PHP Patterns, it's actually more about good practice with Zend related technologies. It's a shame that not every PHP developer will have the chance to access those Zend products (me included ...), however I did manage to get some interesting ideas out of the book. To name one, application logging. I have to say, I have over looked the aspect of application level logging for a long time. I so rely on the server access and error log, and there are instances that I fail to find necessary information from those big ... massive server log files.&lt;/p&gt;

&lt;p&gt;So here's how I did my application logging with Zend_Log.&lt;/p&gt;

&lt;p&gt;In my Bootstrap.php, I added the following init method. You can see the logger object is then stored in the registry. You can see I'm not doing anything fancy here, just logging to a file, which is specified in my ini file.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;protected  function _initApplicationLogger(){&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  // init firebug log writer&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFirebug = new Zend_Log_Writer_Firebug();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $filterFirebug = new Zend_Log_Filter_Priority(Zend_Log::DEBUG, &amp;#39;==&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFirebug-&amp;gt;addFilter($filterFirebug);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  // log file&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $logFile = Zend_Registry::get(&amp;#39;config&amp;#39;)-&amp;gt;logFiles;&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  // application log writer&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFileApplication = new Zend_Log_Writer_Stream($logFile-&amp;gt;application);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $filterFileApplication = new Zend_Log_Filter_Priority(Zend_Log::INFO, &amp;#39;&amp;amp;lt;=&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFileApplication-&amp;gt;addFilter($filterFileApplication);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  // error log writer&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFileApplicationError = new Zend_Log_Writer_Stream($logFile-&amp;gt;error);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $filterFileApplicationError = new Zend_Log_Filter_Priority(Zend_Log::ERR, &amp;#39;==&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFileApplicationError-&amp;gt;addFilter($filterFileApplicationError);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  // security log writer&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFileApplicationSecurity = new Zend_Log_Writer_Stream($logFile-&amp;gt;security);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $filterFileApplicationSecurity = new Zend_Log_Filter_Priority(Zend_Log::ALERT, &amp;#39;==&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $writerFileApplicationSecurity-&amp;gt;addFilter($filterFileApplicationSecurity);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  // add writers to logger&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $logger = new Zend_log($writerFirebug);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $logger-&amp;gt;addWriter($writerFileApplication);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $logger-&amp;gt;addWriter($writerFileApplicationError);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $logger-&amp;gt;addWriter($writerFileApplicationSecurity);&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  Zend_Registry::set(&amp;quot;logger&amp;quot; , $logger);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Next, I want to log my application errors, so the natural place to do this is the ErrorController.php file.  I just added the following lines to the bottom of the errorAction() method&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;$this-&amp;gt;logger-&amp;gt;log($errors-&amp;gt;exception-&amp;gt;getMessage() . PHP_EOL . $errors-&amp;gt;exception-&amp;gt;getTraceAsString(), Zend_Log::ERR);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Since the application I'm writing is accessible by authenticated users only,  it is important to log security breaches. How I did this is a bit interesting. I think there must be better ways to do this ... but I don't know how ... so here it is.&lt;/p&gt;

&lt;p&gt;I have implemented my own controller action class, MyApp_Controller_Action. It extends the standard Zend_Controller_Action. So all my protected controllers extend MyApp_Controller_Action instead of Zend_Controller_Action.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class MyApp_Controller_Action extends Zend_Controller_Action {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  ...&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  protected $logger;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  public function init() {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    ...&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    $this-&amp;gt;logger = Zend_Registry::get(&amp;quot;logger&amp;quot;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  }&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  ...&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  public function checkAcl() {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    ...&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    if($noGood) {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      $this-&amp;gt;logSecurityBreach();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  }&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  protected function logSecurityBreach() {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    // log some basic info here. extend it to include extra info that you need&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    $errorLog = &amp;#39;Invalid Access Attempt&amp;#39; . PHP_EOL .&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      &amp;#39;Resource: &amp;#39; . $this-&amp;gt;getRequest()-&amp;gt;getRequestUri() . PHP_EOL .&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      &amp;#39;Offending IP: &amp;#39; . $this-&amp;gt;getRequest()-&amp;gt;getClientIp() . PHP_EOL .&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      &amp;#39;Offending user: &amp;#39; . $this-&amp;gt;identity-&amp;gt;Username;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      $this-&amp;gt;logger-&amp;gt;log($errorLog, Zend_Log::ALERT);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Since the logSecurityBreach function is made &quot;protected&quot;, so that in the controllers, who extend MyApp_Controller_Action, can call the logSecurityBreach method whenever there are any other access control violations. For example, a specific security error can be logged if a logged in user tweaked the URL (like an ID param/token in the URL) to access some other resources that should not be visible to his login.&lt;/p&gt;

&lt;p&gt;So here it is. A basic use of Zend_Log. Hope it makes sense.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.apress.com/book/view/9781430219743&quot; target=&quot;_blank&quot;&gt;http://www.apress.com/book/view/9781430219743&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Best practices of PHP development</title>
   <link href="http://marsbomber.github.com/2009/09/19/best-practices-of-php-development"/>
   <updated>2009-09-19T06:52:40-07:00</updated>
   <id>http://marsbomber.github.com/2009/09/19/best-practices-of-php-development</id>
   <content type="html">&lt;p&gt;I just finished listening to this ZendCon podcast. It's about some good practice tips in doing PHP development. They are quite basic, but I'm sure that not all PHP developers follow their suggestions ... At least I know I'm still some way apart from the suggested &quot;Best Practices&quot;.&lt;/p&gt;

&lt;p&gt;People, who are interested, can find it &lt;a href=&quot;http://www.phppodcasts.com/2009/09/18/the-zendcon-sessions-episode-26-best-practices-of-php-development/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. To save you some time, the companion PDF slides can also be downloaded &lt;a href=&quot;http://blog.elinkmedia.net.au/wp-content/uploads/2009/09/Best-Practices-of-PHP-Development.pdf&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.phppodcasts.com/2009/09/18/the-zendcon-sessions-episode-26-best-practices-of-php-development/&quot; target=&quot;_blank&quot;&gt;http://www.phppodcasts.com/2009/09/18/the-zendcon-sessions-episode-26-best-practices-of-php-development/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>GIT on Windows with Netbeans</title>
   <link href="http://marsbomber.github.com/2009/09/16/git-on-windows-with-netbeans"/>
   <updated>2009-09-16T23:58:21-07:00</updated>
   <id>http://marsbomber.github.com/2009/09/16/git-on-windows-with-netbeans</id>
   <content type="html">&lt;p&gt;I've been using SVN (via Tortoise SVN) on my windows development machine for a while. The experience is quite average. It does what I need, but I still had to play with my local Apache configuration and the speed is not that impressive. GIT is apparently becoming the industry version control program these days, so I decided to give it a try!&lt;/p&gt;

&lt;p&gt;To set it up on Windows, it's actually quite simple. You first need to download &quot;msysgit&quot;, available from Google Code. Follow the instruction to install it. Since we are using Windows, to play safe, I chose the installation location to be at &quot;C://GIT&quot;, so that we will not potentially run into the infamous &quot;C://Programs Files&quot; issue.&lt;/p&gt;

&lt;p&gt;So ... after installation, we are pretty much good to go. Fire up the newly installed Git Bash, you then pretty much work in a &quot;linux-like&quot; shell, with only git of course :)&lt;/p&gt;

&lt;p&gt;I'm using Netbeans for my development and am naturally lazy, so that I thought it'll be better if I can do my version control stuff inside the IDE. I got lucky again. Download &quot;NBGit&quot; from Google Code (wonder why the downloads are not from GitHub ...), and load it up with Netbeans. All good.&lt;/p&gt;

&lt;p&gt;I then ask, how do I push the source code to a remote location/computer, so that if my local computer crashes, I can still have my version controlled copies of everything?&lt;/p&gt;

&lt;p&gt;If you don't mind others to see and grab your code, go to GitHub. If you don't mind spending some dollars every month to be able to host private projects and you want to access the files from everywhere , go to GitHub. Otherwise read on ...&lt;/p&gt;

&lt;p&gt;If you have a spare machine sitting at home and not doing much, you then might want to load it up with your favorite Linux OS. Install git-core, and SSH server. All you need to do now is to setup a few empty GIT repositories on the Linux machine, note down the Linux machine's IP and your empty GIT repository locations. You have a remote GIT server. I'm not going to describe how to do each of these tasks in details, since there are a lot good tutorials on the net already.&lt;/p&gt;

&lt;p&gt;Anyway, that's the setup I use, and I hope you may find it's useful.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Common library files organization in ZF</title>
   <link href="http://marsbomber.github.com/2009/09/05/common-library-files-organization-in-zf"/>
   <updated>2009-09-05T01:07:29-07:00</updated>
   <id>http://marsbomber.github.com/2009/09/05/common-library-files-organization-in-zf</id>
   <content type="html">&lt;p&gt;Once you have used ZF for a couple of projects, you will find that there are library files actually live independent to whichever application you are implementing. These common library files should be reusable by all you ZF projects. Now the question is where you should place these files so that a typical ZF project can make use of them without a glitch?&lt;/p&gt;

&lt;p&gt;I have described my ZF project structure in an earlier post &lt;a href=&quot;http://blog.elinkmedia.net.au/2009/08/27/my-zend-framework-project-setup/&quot; target=&quot;_blank&quot;&gt;HERE&lt;/a&gt;, and now I want to elaborate a bit more on folder &quot;library/MyApp&quot;, because that's where I keep my common library files.&lt;/p&gt;

&lt;p style=&quot;text-align: left;&quot;&gt;&lt;img class=&quot;size-full wp-image-72 aligncenter&quot; title=&quot;ZF_Lib_MyApp&quot; src=&quot;/images/posts/ZF_Lib_MyApp.jpg&quot; alt=&quot;ZF_Lib_MyApp&quot; width=&quot;187&quot; height=&quot;126&quot; /&gt;I have a rather simple version shown here. Basically only 3 things to look at.&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;Let's start with &quot;MyApp/View/Helper&quot;. &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the place where I keep all my project independent View Helper files. Things like&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;baseUrl, as the name says, return the base URL for your application&lt;/li&gt;
    &lt;li&gt;loginUserInfo, assemble things like login username, last login time, and even your application logout text/link&lt;/li&gt;
    &lt;li&gt;flashMessenger, I use a customized view helper in conjunction with ZF's flash messenger action helper to make different markups for different type of error messages. i.e. good message in green, bad message in red.&lt;/li&gt;
    &lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I assume you already know that you need to follow ZF's naming conversion for these helpers files to make  autoloading painless. For example, the baseUrl view helper, you will end up with something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class MyApp_View_Helper_BaseUrl {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  function baseUrl() {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    $fc = Zend_Controller_Front::getInstance();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    return $this-&amp;amp;gt;_baseUrl =  $fc-&amp;amp;gt;getBaseUrl();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  }&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Next, let's look at ViewSetup.php file under &quot;MyApp/Controller/Plugin&quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I basically have this file built based on Rob Allen's book &quot;&lt;a href=&quot;http://www.zendframeworkinaction.com/&quot; target=&quot;_blank&quot;&gt;Zend Framework in Action&lt;/a&gt;&quot;. This is the file that sets up your view using various view related hooks. Particularly I have 3 hooks looked after.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;dispatchLoopStartup
Use this hook to setup things like doctype, application common JS and CSS file. And also register our MyAPP view helpers&lt;/li&gt;
    &lt;li&gt;preDispatch
I personally use this hook to inject more CSS and/or JS into the script header. Because at this point, we know the view is dispatched by which controller. We could then load in any controller specific resources.&lt;/li&gt;
    &lt;li&gt;postDispatch
I use this hook to set my application HTML head title. ZF allows you to set a separator for your header title tokens. And I always add 1 more token, which is the application name to the title. So ... your paper header title can look something like this &quot;ActionName - ControllerName - ApplicationName&quot;. It somewhat makes sense to me, but if you do not like the idea, just do not implement this hook.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To make a use of this ViewSetup file, I have this too init function in my bookstrap&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;protected function _initCustomLibraryNamespaces() {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $loader = Zend_Loader_Autoloader::getInstance();&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $loader-&amp;gt;registerNamespace(&amp;#39;MyApp_&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;protected function _initViewHelpers() {&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $frontController = Zend_Controller_Front::getInstance();&lt;/span&gt;

&lt;span class=&quot;x&quot;&gt;  $frontController-&amp;amp;gt;registerPlugin(new MyApp_Controller_Plugin_ViewSetup(), 98);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  $this-&amp;amp;gt;bootstrap(&amp;#39;layout&amp;#39;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;OK, last bit, let's talk about &quot;MyApp/Controller/Action.php&quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A bit background first, I recently just started looking into Ruby on Rails as a self learning course. One RoR programming principle is DRY (Don't Repeat Yourself). The same motivation made me implement this &quot;MyApp/ControllerAction.php&quot; file. There are a lot of common things you do with pretty much all your application controller classes. Things like authentication, maybe ACL (depends on your application specific requirement), flash messenger, logger, etc. I hate repeat myself, that's why I have these common tasks or methods implemented here. So ... the Action.php class declaration goes like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class MyApp_Controller_Action extends Zend_Controller_Action&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It actually extends the Zend_Controller_Action, so that it should not work any unexpected at all.
and a typical application controller will have something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class IndexController extends MyApp_Controller_Action&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;and of course if a certain controller does NOT require any extras implemented in the customized Action.php file, you can make it easily fall back to something like this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;x&quot;&gt;class ErrorController extends Zend_Controller_Action&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That's it! Hope it helps and let me know if you have better ways.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>jQuery library and plugins</title>
   <link href="http://marsbomber.github.com/2009/09/03/jquery-library-and-plugins"/>
   <updated>2009-09-03T06:51:47-07:00</updated>
   <id>http://marsbomber.github.com/2009/09/03/jquery-library-and-plugins</id>
   <content type="html">&lt;p&gt;No need to mention, most of the web developers have long suffered from the chaotic but must-have JavaScript hand coding days ... I was &quot;lucky&quot; enough to learn JavaScript the hard way from my first job. Traversing the DOM was like a nightmare, repeating the same form validation 20 times, running into browser compatibility issues (tell me about it!!!), etc.&lt;/p&gt;

&lt;p&gt;Tasks are made easy now with quite a number of JavaScript frameworks. I started with YUI, and now try to do more with jQuery. What I found with YUI is that I still need to write quite some code to do a task. On the other hand, with jQuery, I tend to write very little. I think this is because of the number of quality jQuery plug-ins. That's the same story with Firefox and its Addons.&lt;/p&gt;

&lt;p&gt;Anyway, in most of my recent applications, I pretty much have the following plugins loaded in one minified .js file&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;cmxform&lt;/li&gt;
    &lt;li&gt;ajaxupload&lt;/li&gt;
    &lt;li&gt;jquery.autocomplete&lt;/li&gt;
    &lt;li&gt;jquery.metadata&lt;/li&gt;
    &lt;li&gt;jquery-validate&lt;/li&gt;
    &lt;li&gt;jquery-tablesorter&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;and of course the jQuery UI js combined with any necessary widgets.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>About robots.txt</title>
   <link href="http://marsbomber.github.com/2009/08/31/about-robots-txt"/>
   <updated>2009-08-31T17:52:21-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/31/about-robots-txt</id>
   <content type="html">&lt;p&gt;A while ago, I was asked the question of how we can tell search engine spiders how and where to search and index our site. We know the answer is robots.txt. Placing this special file under your site root will do the trick. I've been handcrafting the robots.txt file since I know its existence until I recently found there are generators out there can help you with the job ... silly me!&lt;/p&gt;

&lt;p&gt;To save you some time, &lt;a href=&quot;http://www.mcanerin.com/en/search-engine/robots-txt.asp&quot; target=&quot;_blank&quot;&gt;http://www.mcanerin.com/en/search-engine/robots-txt.asp&lt;/a&gt; is what I use now.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Connect to MS SQL Server using PDO</title>
   <link href="http://marsbomber.github.com/2009/08/29/connect-to-ms-sql-server-using-pdo"/>
   <updated>2009-08-29T23:06:55-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/29/connect-to-ms-sql-server-using-pdo</id>
   <content type="html">&lt;p&gt;I am not sure if having PHP talking to SQL Server is a common practice, but I have to do it recently with a new Zend Framework based project. Using the Zend Framework means I will not  use my good old pear MDB2 database abstraction mechanism to make my PHP application talk to SQL Server. PDO is used to handle this task. And of course, as soon as you move out of your comfort zone, you have problems.&lt;/p&gt;

&lt;p&gt;My local server, hosted on XAMPP, cannot establish connection to my local 2005 SQL Server. After spending hours on this problem, I found it is caused by a DLL file shipped with the pre-compiled PHP was out dated. The updated ntwdblib.dll file can be downloaded from &lt;a href=&quot;http://www.dlldll.com/ntwdblib.dll_download.html&quot; target=&quot;_blank&quot;&gt;http://www.dlldll.com/ntwdblib.dll_download.html&lt;/a&gt; or &lt;a href=&quot;http://www.userscape.com/ntwdblib.dll&quot; target=&quot;_blank&quot;&gt;http://www.userscape.com/ntwdblib.dll&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a XAMPP installation, you will need to paste the DLL file in &lt;em&gt;&quot;C:\xampp\php&quot;&lt;/em&gt; and &lt;em&gt;&quot;C:\xampp\apache\bin&quot;&lt;/em&gt;. After this, everything should be good to go!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Setup local PHP development environment on Windows</title>
   <link href="http://marsbomber.github.com/2009/08/29/setup-local-php-development-environment-on-windows"/>
   <updated>2009-08-29T01:00:40-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/29/setup-local-php-development-environment-on-windows</id>
   <content type="html">&lt;p&gt;Here I want to show you how I have my local php development environment setup with XAMPP, Xdebug and PHPUnit. With this setup, you will be able to develop and run your PHP applications on your windows localhost, be able to unit test your PHP application and have a code coverage report generated by PHPUnit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's download and install XAMPP first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is very straight forward. We just need to download the latest XAMPP zip file from http://www.apachefriends.org/en/xampp-windows.html and extract all contents to &lt;em&gt;&quot;C:\xampp&quot;&lt;/em&gt;. I use &lt;em&gt;&quot;C:\xampp&quot;&lt;/em&gt; to avoid windows permission issues. To verify the XAMPP installation, find and double click on the &lt;em&gt;&quot;&lt;em&gt;C:\xampp&amp;lt;/em&gt;xampp-control.exe&quot;&lt;/em&gt; file to bring up the control panel, click on the &quot;Start&quot; button next to &quot;Apache&quot; to start the Apache web server. Now, start your browser and go to http://localhost, you should see the XAMPP default welcome page. Your localhost document root is at &lt;em&gt;&quot;C:\xampp\htdocs\&quot;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next, let's install and configure Xdebug.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Download the latest precompiled Xdebug DLL from http://www.xdebug.org/download.php. Put the DLL inside &lt;em&gt;&quot;C:\xampp\php\ext\&quot;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We need to tell our PHP installation to use Xdebug. There are 2 php.ini files come with XAMPP, &lt;em&gt;&quot;C:\xampp\php\php.ini&quot;&lt;/em&gt; and &lt;em&gt;&quot;C:\xampp\apache\bin\php.ini&quot;&lt;/em&gt;. The file under &lt;em&gt;&quot;C:\xampp\&quot;&lt;/em&gt; controls the command line PHP. Obviously the php.ini under &lt;em&gt;&quot;C:\xampp\apache\bin\&quot;&lt;/em&gt; controls the Apache PHP module. For some reason, enabling Xdebug for the Apache PHP module will lead to unexpected Apache server crashes. So I only have Xdebug enabled for my command line PHP. 2 reasons for this. One is that I really do not have time to figure out why it's not working for my Apache PHP module. Second is my motivation of installing Xdebug at the first place. I'm using Zend Framework for my PHP project development, I get a comprehensive error stack trace from the framework already. I want to install Xdebug, so that when I run my PHP unit tests, I can let PHPUnit generate a nice looking code coverage report (Xdebug is required for this job).&lt;/p&gt;

&lt;p&gt;So ... to configure Xdebug for my command line PHP, I need to modify &lt;em&gt;&quot;C:\xampp\php\php.ini&quot;&lt;/em&gt;. In the ini file, find sections for &quot;[Zend]&quot;, comment out all lines under it. Find section &quot;[XDebug]&quot;, comment out all lines, and put in this&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;err&quot;&gt;[XDebug]&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;remote_enable=1&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;remote_host=&amp;quot;localhost&amp;quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;remote_port=9000&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;xdebug&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;remote_handler=&amp;quot;dbgp&amp;quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;zend_extension_ts=&amp;quot;C:\xampp\php\ext\php_xdebug-2&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;5-5&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;2&lt;/span&gt;.&lt;span class=&quot;err&quot;&gt;dll&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Okay. we now can move onto PHPUnit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can download and install PHPUnit with XAMPP's pear support. Open windows command prompt as administrator and do the following&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;c:&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt;ampp&lt;span class=&quot;se&quot;&gt;\p&lt;/span&gt;hp
go-pear.bat
PEAR_ENV.reg
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We should now have PHPUnit download and configured at &lt;em&gt;&quot;C:\xampp\php\PEAR\PHPUnit\&quot;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We now have a working local copy of PHP, MySQL, Xdebug and PHPUnit. With this setup, we are ready to develop and test our applications on the localhost.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Zend Framework project setup</title>
   <link href="http://marsbomber.github.com/2009/08/27/my-zend-framework-project-setup"/>
   <updated>2009-08-27T02:57:40-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/27/my-zend-framework-project-setup</id>
   <content type="html">&lt;p&gt;When starting implementing a new project, I want to start working on a basic code base, so that I can jump in the project specific coding. I believe I'm not alone, and that's why people fall in love with the rapid development scaffolding idea from Symfony, RoR, etc. I personally prefer a different path. I try to make a clean, generic project skeleton to cover the common ground. Building this skeleton project itself is a very valuable learning process. It makes you learn every single step you do, as opposed to the scaffolding approach, which does things for you without needing you to understand it.&lt;/p&gt;

&lt;p&gt;Here is what I have done with learning and working on Zend Framework.&lt;/p&gt;

&lt;p&gt;When I first started using Zend Framework, I was simply following the quick start guide and making it into my own project skeleton. I then start building my project from the skeleton project.&lt;/p&gt;

&lt;p&gt;I then bought and read the book, Zend Framework in Action, by Rob Allen (It's a great book on Zend Framework even the sample code throughout the book have errors and mistakes and sometimes the topics from chapter to chapter do not follow very smoothly. It is still a very good book for developers just got across the ZF newbie mark). From the book, I adapted Rob's project structure and a lot of good ideas. I, of course, updated my home made ZF skeleton project.&lt;/p&gt;

&lt;p&gt;From there on, I constantly learn new ideas from the ZF blogs and posts, hence keep enhancing my skeleton project. I want to share my skeleton project structure here, and hope it might help ZF adopters have a shortened learning curve.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;size-full wp-image-58 &quot; title=&quot;zf_skeleton&quot; src=&quot;/images/posts/zf_skeleton.jpg&quot; alt=&quot;Elink Media ZF Skeleton&quot; width=&quot;271&quot; height=&quot;533&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It's very basic and very similar to the file structure generated by Zend_Tool.&lt;/p&gt;

&lt;p&gt;I have 4 top level folders&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;admin. The &quot;admin&quot; folder is my project web root. Instead of &quot;admin&quot;, it can be rename to anything.&lt;/li&gt;
&lt;li&gt;application. The &quot;application&quot; folder holds the project core.&lt;/li&gt;
&lt;li&gt;library. The library folder contains a local copy of Zend Framework, and also my own library files under sub folder &quot;MyApp&quot;.&lt;/li&gt;
&lt;li&gt;tests. Folder &quot;tests&quot; holds my unit testing files and the PHPUnit generated code coverage report&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;I deliberately expanded the &quot;application&quot; - &quot;models&quot; folder. Under &quot;models&quot;, I have a sub folder &quot;Db&quot;  and other PHP model files. Reason is I am using a hybrid approach here to handle database interactions.&lt;/p&gt;

&lt;p&gt;Sub folder &quot;Db&quot; contains domain objects implementing &quot;Table Data Gateway&quot; and &quot;Row Data Gateway&quot; design patterns using the Zend Framework shipped Zend_Db support.&lt;/p&gt;

&lt;p&gt;Files on the same level as folder &quot;Db&quot; are domain classes that typically require resources from many table. These &quot;shortcut&quot; classes can be used under the situation where using the domain classes under the &quot;Db&quot; will impose too much of a performance hit. Using these &quot;shortcut&quot; classes means we are sacrificing abstraction to gain performance. These classes hence should be implemented and used carefully.&lt;/p&gt;

&lt;p&gt;I am also looking at implementing Doctrine together with Zend Framework in my skeleton project. I'll post an updated diagram in a future post.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>MVC & Zend Framework</title>
   <link href="http://marsbomber.github.com/2009/08/26/mvc-zend-framework"/>
   <updated>2009-08-26T18:26:24-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/26/mvc-zend-framework</id>
   <content type="html">&lt;p&gt;As high speed internet becomes available to more and more people, the computer world gets its focus back to the centralised computing style. This opens up  opportunities to web development companies. They are no longer just building &quot;another website&quot;. More complicated web applications get in the radar. The increased complexity in developing web applications requires web development methodology change, as well as web developers' programming mindset change.&lt;/p&gt;

&lt;p&gt;Programmers can no longer hack their way through, for a decent sized project anyway. A typical web application project will take longer time to develop and require a lot more resources to complete the work. And thanks to our high speed internet again, these people resources can be everywhere around the globe. A clean and structured way of developing projects becomes required. For the sake of not reinventing the wheels, having a jump start and working on a robust code base, a web development framework(s) is normally used.&lt;/p&gt;

&lt;p&gt;The MVC pattern becomes a de facto to web applications these days. I'm not saying MVC is the only pick. We can still implement our project in other styles just as efficient and effective. MVC is however commonly adapted and used in the community (the PHP community at least). If you are not sure about what MVC is, you can have a look on Wikipedia or go &lt;a href=&quot;http://www.phppatterns.com/docs/design/archive/model_view_controller_pattern&quot; target=&quot;_blank&quot;&gt;HERE&lt;/a&gt; for a PHP specific explanation.&lt;/p&gt;

&lt;p&gt;The guidance of MVC should lead us to have a clean and purposely build project structure, which should be self-explanatory in terms of what class does what.&lt;/p&gt;

&lt;p&gt;To take the MVC approach further, we will then naturally start hunting for a well developed, enhanced and maintained framework. There are quite a number of PHP framework libraries out there. They all have pros and cons and I'll leave that to your own research.&lt;/p&gt;

&lt;p&gt;I have used the Zend Framework for over a year and a half now. The reason I chose Zend over the others is because of its &quot;use at will&quot; characteristics. This means for those adhoc and small through-away jobs, I can still benefit from using Zend Framework's robust base classes as my external libraries, without the constraints of having to follow the MVC pattern. This means you are never forced to over engineer projects. Let's face it, there are always jobs that you never need a full blown MVC design. Determine a project implementation strategy is a separate issue to this post. Hopefully we can do another post on that later.&lt;/p&gt;

&lt;p&gt;Apart from the &quot;use at will&quot; flexibility, we have to mention the robust code base that Zend and the PHP community provides. Zend Framework gives us a jump start on any MVC styled projects. We can use Zend_Tool to generate a basic Zend Framework recommended project file structure. However we still have the flexibility to alter and change the structure to make it fit in our company's  convention, as long as it makes sense to the developers. From there on, any developers who are familiar with Zend Framework should be able to jump in and start working.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Enterprise PHP</title>
   <link href="http://marsbomber.github.com/2009/08/24/enterprise-php"/>
   <updated>2009-08-24T06:55:49-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/24/enterprise-php</id>
   <content type="html">&lt;p&gt;As my first blog post at the elink media blog, I want to start with a discussion on this &quot;Enterprise PHP&quot; topic.&lt;/p&gt;

&lt;p&gt;Doing a search on Google, the most interesting posts are posted back in 2004 and 2005. You will find people taking about the strength and weaknesses of PHP, comparing with JAVA of course (enterprise de facto? pretty much).&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;http://www.procata.com/blog/archives/2004/10/12/enterprise-php/&quot; target=&quot;_blank&quot;&gt;post&lt;/a&gt; is particularly interesting, because of the writing itself and one of the user comments. Martin Fowler's enterprise application definition was quoted and used as a measurement to check if PHP is enterprise ready. According to Martin, PHP should be nowhere near his enterprise grade. However I found one of the replies (replied in 2004) actually matches what I always believe.&lt;/p&gt;

&lt;p&gt;PHP will not fit in Martin Fowler's enterprise definition back in 2004, the statement is made and based on the enterprise definition defined long time ago. We know that IT moves world faster than ever. And I would say, web moves IT faster than ever too. This makes me question whether Martin Fowler's definition is still correct. Or has the definition of enterprise itself evolved over the past decade?&lt;/p&gt;

&lt;p&gt;Having said that, I am a fan of Martin Fowler's enterprise design patterns. It helped me a lot with my jobs. If you've never come across him, I strongly recommend you do a Google search and read about his design patterns. Not saying you need to follow it, but at least you should be able to get some good ideas out of it.&lt;/p&gt;

&lt;p&gt;Let's leave this as an open discussion. I'll discuss this further after I finish reading the &quot;Zend Enterprise PHP Patterns&quot; book I just bought.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Happy blogging</title>
   <link href="http://marsbomber.github.com/2009/08/23/happyblogging"/>
   <updated>2009-08-23T10:58:29-07:00</updated>
   <id>http://marsbomber.github.com/2009/08/23/happyblogging</id>
   <content type="html">&lt;p&gt;Welcome to the elink media blog. This is a technical blog to highlight and discuss any technical aspects that elink media is focusing on. Some tips and tricks or simply some useful links will also be shared to all audiences.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>

