Archive

Archive for January, 2010

Metaprogramming with RadiantCMS

January 26, 2010 1 comment

My short stint with Radiant in the near past was actually quite interesting ! — No I did not design websites or webpages. What I am talking about is the internals – making radiant plugins and creating radius tags, the overwhelming use of meta-programing and the ease of overriding and extending the base or extensions functionality.

First-up, Radiant is NOT for newbies. If you are looking to design some static webpages or basic content, I would probably not recommend radiant – there are other tools for this. Radiant however is very exciting if you are planning on things which are more complicated than static web-pages, like authorization based views, galleries, custom website configuration, etc. etc. If you are well versed and aware of page-parts, snippets, layouts and how they all interact with each other, then you can look at Radiant

Though radiant supports ALL basic HTML tags, it also supports radius tags — loaded via extensions. The excellent open source contributions as radiant extensions leaves very little to do on your own ;) but then again – there is nothing called a free lunch.

Its easy to override any existing functionality in core radiant or its extensions by some simple meta-programing. Some good insight here

module MyExtension
  module SiteControllerExt
    def self.included(base)
      base.class_eval {
        def new_method
          ... # whatever new functionality you want to add to the site controller
        end
      }
    end
  end
end

You can then activate the SiteController by adding these additional methods in the meta-class.

def activate
  SiteController.send(:include, MyExtension::SiteControllerExt)
end

You can modify existing behavior of any method by using the alias_method_chain as in the following example:

module MyExtension
  module SiteControllerExt
    def self.included(base)
      base.class_eval {
        def site_with_clone
          ... # pre-processing
          site_without_clone
          ... # post-processing
        end

        alias_method_chain :site, :clone
    end
  end
end

The alias chain method ensures that we can write some code before or after the core method. Similarly you can override the views. More details here The above are some very simple basic rules of meta-programing.

base.class_eval {

This line of code is actually accessing the meta-class and changing it. In other words, we evaluate the Class object and update the methods in it! This helps us add or modify the functionality of the class.

Radiant Multihosting

Radius and multisite hosting is cool — but you should know how it works to reap the benefits. The following extensions help out: multi_site, scoped_admin.

Both these ensure that all pages are site_scoped. Using some basic meta-programing, each site now has its own ‘scope’. Remember the all important Page.current_site !! Sandip and  I busted our heads trying to figure out why the following was ‘wierd’. On the console

>> Site.find 13
=> #<Site id: 13, homepage_id: 74, position: 4, ... >
>> s = Site.find(13).layouts
=> []

This implies that The Site (with id 13) does not have any layouts! However, a direct find_by_sql had a different answer in store for us !

>> Layout.find_by_sql("select * from layouts where site_id=13")
=> [#<Layout id: 29, name: "Basic", content: "<html>\r\n ... >
>>

This implies that the data is there in the database BUT not available from the associations! So frigging wierd. Then we got into the details of multi_site plugin and realized the ‘error in our ways’.  Radiant is by default single site scoped. When we work with multi_site, we need to fool Radiant and tell it which site we are working with! The following works:

>> Page.current_site = Site.find(13)
>> s = Site.find(13)
>> s.layouts
=> [#<Layout id: 29, name: "Basic", content: "<head> ... lock_version: 0, site_id: 13> ]

So, it extremely important to ensure that the Page.current_site is set when working with multi-hosting. So, why did this happen or how is it so, you ask? The multi_site extension, uses some pretty cool metaprograming to override (using alias_method_chain) find, count, max, min, and other ActiveRecord methods. It defaults to ‘default_site’ if the current_site is not set !

Extension Loading and Configurations

Using Radiant extensions is what makes Radiant radiant! :) There are plenty of extensions that can be easily installed in the radiant setup. However, its important to remember the following:

  • environment.rb config.extensions is the file to ensure ‘extension load ordering’. This is very important especially if you want to override some extension functionality.
  • The :all symbol in config.extensions implies the remaining extensions. BUT remember that these extension are then loaded in ALPHABETICAL order! So, be careful to either ensure your call your extension ‘zzz_myextension’ (LoL) or ensure that any extensions you override load before you load your own extension.
  • The ‘settings’ extension is pretty cool for managing configurations. To add a configuration, you can simply do this:
  • Radiant::Config["key"] = value
  • Recommended way of adding default configurations is the have yml file use YAML::load_file in the extension activate function.
  • Remember, the configuration is saved in the database — so if you override the value from the GUI, the database gets updated — NOT the yml file. So you have to be careful.

Radius tags

Radius tags look something like this:

<r:content />
<r:gallery id="id> ... </r:gallery>

Radius tags help in managing the programing part of dynamic pages. You can add your own radius tags to ease the effort of inserting HTML code. Some cool examples are:

<r:gallery:lightbox_stuff />

This generates the HTML for loading JS and CSS for lightbox — simple. To create a lightbox:

<r:gallery id="3">
 <r:gallery:lighbox />
</r:gallery>

To add your own radius tags, you need to do the following in a module.

module MyExtensionModule
 module CustomTags

 include Radiant::Taggable

 tag "tractor" do |tag|
  desc "description of the tag"
  tag "tagname" do |tag|
    ... #custom logic
  end
 end

In the extension loader file, if you want to use the radius tags in the Pages, ensure this:

Page.send :include, MyExtensionModule::CustomTags

Enjoy the radiance!

PHPcamp – CakePHP Vs Ruby On Rails

January 10, 2010 32 comments

On 9th Jan, ’10,  I presented my topic “CakePHP Vs Rails” at PHPCamp. It was well received and it felt nice to have been able to present such a topic to PHP devs. I was expecting a ‘fight’ (infact quite a few people did too) but I did keep the tempo low and to a discussion and not a debate – expect the unexpected !

Having said this, the controversy started long before my talk though – right from the choice of the title. My opinion is that almost 90% of PHP development is web-development, so the topic – ‘PHP Vs Ruby On Rails’ was on the button. However, Amit Singh, Dhananjay Nene disagreed – they felt it was comparing apples to oranges. I complied to their request and changed the title – Fair enough. BUT how do you explain that there were 2 hands raised in a room of about 80, who said that they used PHP earlier for non web-development ;). All in all, I did finally compare Ruby with PHP and CakePHP with Rails.

PHPcamp had 2000+ registrants and the venue was ‘packed’ – it was very exciting to go a PHPcamp as a rubyist. I wondered if people sensed a wolf among the sheep (couldn’t resist that taunt, ;) my apologies ) and when I went up to the wikiwall to note my topic, I did get a few curt nods and some smiles and a Ah-you-are-the-rails-guy looks!

I kept my talk after Aditya’s talk on ‘Introduction to CakePHP’ because it would help my cause for people to know more about CakePHP when I compared it with Rails. The talk was really good — and I could see a lot of my effort reducing in explaining MVC, RESTfulness, relationships etc. the rails way. The slides are posted here.

Before I did a deep-dive, I wanted to grasp the type of audience I was dealing with and realized a decent mix of professionals, students and even a few entrepreneurs. I decided to keep my talk a little less-technical, should people sleep off ;).

I started with a brief comparison of PHP and Ruby. The Pure OO Ruby, mention of blocks and meta-programing. The idea of blocks of code being sent as parameters to methods and the idea of defining a method on an object seemed to have intrigued the crowd — however, given that I had to keep the talk basic and not too technical, I am sure it did go a little over the top. Never mind – at least I had got everyone’s attention. In a lighter moment, I did mention the use of throwing shoes as opposed to rotten tomatoes if required. I did not have the pleasure of getting as famous as famous presidents as nobody lost any shoes !

I then gave a brief comparison of CakePHP and Rails which brought me to the main discussion. CakePHP has a directory structure similar to rails and I believe it has been modeled around Rails (at least in the beginning). The model based relationships are similar to Rails, except for HasAndBelongsToMany. In Rails it has been changed to has_many :through =>  relationship. I particularly liked the ‘on the fly’ binding in CakePHP – its pretty cool. In rails this is achieved by a little bit of meta-programing and adding class methods to the model to load new functionality.

Both frameworks preach being model-heavy which is excellent. However I was a little surprised with Aditya mentioning that scaffolding should not be used extensively. I do believe that the RESTful code generators in Rails are excellent and scaffolding should be used extensively to get a jump-start.

RESTfulness was skimmed through the CakePHP talk but I re-iterated in my talk the importance of inherent RESTfulness that helps in interoperability. I could see a heads nodding when I used an example of user account creation URL — got plenty of answers, /add_user, /create_users, etc. and the look of enlightenment when I explained how HTTP verbs are used to ensure that /users (with GET) will get the list of users and /users (with POST) will create a user.

There was finally a person who raised the question of speed and performance in pure PHP code Vs Ruby Code. Now, it is indeed undeniable that PHP code interprets faster then Ruby, in fact as the gentleman said – “The 10 lines of PHP code will run faster than the 3 line of similar Ruby code”.  Agreed!

I was filled with pride that he mentioned the really cool part of Ruby coding — LESS CODE, which in turn means less bugs. (Yes – I know there will be a lot of PHP enthusiasts who will flame me for this — but it is a fact!). Ok – back to the speed and performance issue — in my opinion, CakePHP would run much slower than Rails (courtesy internal caching). However, pure PHP code would run a tad faster than Rails. This is definitely debatable but I would forgo some performance and speed in favour of lesser lines of code. In addition to this, the ruby interpreters (MRI and Jruby) are reaching epic proportions of speed in interpreting.

I then moved onto what I found missing (or lacking) in CakePHP as opposed to Rails.

  • The one thing that stands out is the use of migrations. I was shocked to see event the examples on the dev site, showing SQL file for creating and updating the database.
  • The lack of deployment information was understandable (standard Apache with mod_php I guess) but I think this is lacking. Capistrano is something I did not mention in the talk but its things like this that make deployment simple! I was talking to some of the experts later, Amit, Aditya and Shardul after the talk and they told me that most still rely on scp and ftp for production deployment! I hope that is incorrect, but was a little taken aback never-the-less.
  • There does not seem to be much information about the use of caching in CakePHP — it seemed to be more out of the do-it-yourself manual via memcached. Rails internal caching is superb – object caching, query caching and fragment caching really get things going. Though I found information about caching in CakePHP, I wonder how much people use it.
  • The Rails magic of instance variables in controllers directly being accessible in views is cool. CakePHP requires the use of set() to ensure this. Decent enough though lot of scope of mistakes, IMO.
  • Routing and RESTful routing seemed a little behind compared to rails. Aditya did mention that default RESTful routes are now available in CakePHP but from the documentation and usage it seemed lacking. I love the following routing in Rails which gives me all the RESTful CRUD automagically.
  • map.resources :users
  • Polymorphic associations were missing (but I may be wrong here — I am sure its supported).

To conclude, the fact is that CakePHP makes life unbelievably happier for PHP web development – I would call it a boon! I personally do see a lot of similarity between CakePHP and Rails – in fact I did tweet that that what Rails does, CakePHP follows. However, surprisingly, Larry E. Masters disagreed with me. His opinion is very important in the context as he is the Co-founder of CakePHP! Check out his interesting replies to my tweet here and here Now, that is spunk and attitude ideal for competitive development – Its highly appreciated as it will make things better! I would like to ‘twibate’ on it sometime, but I think that would digress from this topic :)

All in all, I say to PHP devs, — Try the real thing!

January 10, 2010 Leave a comment
Follow

Get every new post delivered to your Inbox.