Table Helper in PHP

Custom built frameworks are always a zero-sum game. You get the freedom to build the framework completely suited to your business needs, but then you will more or less have to retread the bug ridden path of other frameworks. For our company currently, as an architect I have immense freedom to look at application from completely ‘techie’ viewpoint and keep building better and simpler solutions to make the lives of ouri developers a bit simpler.

PHP is an amazingly simple language to build webapps in. Though personally I am in favor of Python or even Ruby to build webapplications, the amount of workforce in PHP available in the market makes it an immensely favored language.

Anyways, back in my work, we have this interesting problem where we have to render hundreds of analytics reports. Pull from the DB and display the results in table format. To deal with this tedium of having to write innumerable presentation layer files to deal with table rendering we use a small function to render the tables. Its a pretty simple function that formats the data in neat table cells using

and encloses each of the resultset in the table rows.

. However, because of this limitation we had the presentation layer tainting the data with the presentation tags.

Hence the genesis of this unit test code.

require 'table_helper.lib.php';

################# FOR UNIT TESTING THE FUNCTION #######################
function url_logos($profile_id) {
  switch($profile_id) {
    case 1: return "abcde"; break;
    case 2: return "vwxyz"; break;
    default: return "NONE"; break;
  }
}

$Data = array(
  array('john', 'john carmack', 1, 75, '2008-12-1 00:0:00'),
  array('galt', 'john galt', 2, 2, '2008-06-06 06:06:06'),
  array('dagny', 'dagny taggart', 1, 180, '2008-11-00 00:0:00'),
  array('hank', 'hank rearden', 2, 200, '2008-06-02 06:06:06'),
  array('roark', 'howard roark', 1, 0, '2008-12-1 00:0:00'),
  array('john', 'john carmack', 1, 75, '2008-12-1 00:0:00'),
);
$Headers = array('Alias', 'Name', 'Profile', 'Games', 'Joining Date', 'Square');
$Templates = array(
  '"{$data[0]}"',
  '$data[1]',
  '"http://www.someurl.com/profile.php?id={$data[2]}&name={$data[0]}"',
  '"{$data[3]}"',
  '$data[4]',
  'url_logos($data[2]);'
);

TableHelper::Render($Headers, $Templates, $Data);

This led to the first version of my code for the TableHelper class which would simply use the PHP ‘eval()’ code the replace the Templates and fill it with data.

class TableHelper {
        /**
         * @func   Render($Headers, $Templates, $Data, $Prefix = 'data')
         * @desc   renders a table for the given data and the cell templates given.
         * @param1 $Headers a string array of table column headers
         * @param2 $Templates string of cell templates. The data bucket should be named 
         *         as data in the default case. If you think of any other name be sure
         *         to pass the correct prefix to the function.
         * @param3 $Data Data to fill the templates with.
         * @param4 $Prefix Default bucket for row data is 'data'. Can be anything else.
         * @note   This function now builds a template file instead of using eval.
         */
        static function Render($Headers, $Templates, $Data, $Prefix = 'data') {
                $NumCols = count($Headers);

                echo '< table>';
                echo '< tr>';
                        foreach ($Headers as $header)
                                echo '< th>'.$header.'< /th>';
                echo '< /tr>';

                foreach ($Data as $$Prefix) {
                        echo '< tr>';
                        for ($i = 0; $i < $NumCols; $i++) {
                                        eval("$_cell="$Templates[$i]";");
                                        echo '< td>',$_cell,'';
                        }
                        echo '< /tr>';   
                }
                echo '';
        }
}

As any seasoned programmer will tell you looking at the code, I was sacrificing speed (lots!) for want of better code separation by using eval(). After days of rumination I decided to use aggressive template caching in pphplace of eval(). And here’s the class with the caching mechanism built in…

# BEGIN Section Table Template Caching Section
define(CACHED_TEMPLATES_FOLDER, './cache/');

class TableHelper {
        /**
         * @func CachedFilePath($Id)
         * @desc The table template cached file is just named as unique id.tpl.php
         *       in the CACHED_TEMPLATES_FOLDER folder.
         */
        static function CachedFilePath($Id) {
                return CACHED_TEMPLATES_FOLDER.$Id.'.html.php';
        }

        /**
         * @func BuildTemplate($Id, $Headers, $Templates)
         * @desc Generates the php code for rendering the table and writes the
         *       table generation view code template to the cached folder.
         */
        static function BuildTemplate($Id, $Headers, $Templates) {
                assert(is_writeable(CACHED_TEMPLATES_FOLDER)) or die('Error THL001: Cache Folder has no Write Permissions.');

                $str = '';

                /* Build the Table Rendering PHP Code String */
                $str .= "< table>n";
                $str .= "< tr>n";
                        foreach ($Headers as $header)
                                $str .= "< th>$header< /th>n";
                $str .= "< /tr>n";
                
                $str .= '< ? php foreach ($Data as $$Prefix) { ?>';
                        $str .= "< tr>n";
                        foreach ($Templates as $template)
                                $str .= "< td>< ?= $template ?>< /td>n";
                        $str .= "< /tr>n";
                $str .= "< ? php } ?>n"; 
                $str .= "n";

                $handle = fopen(TableHelper::CachedFilePath($Id), 'w'); 
                        fwrite($handle, $str);
                fclose($handle);

                return true;
        }
        # END Section Table Template Caching Section

        /**
         * @func   Render($Id, $Headers, $Templates, $Data, $Prefix = 'data')
         * @ver    1.2
         * @desc   renders a table for the given data and the cell templates given.
         * @param1 $Headers a string array of table column headers
         * @param2 $Templates string of cell templates. The data bucket should be named 
         *         as data in the default case. If you think of any other name be sure
         *         to pass the correct prefix to the function.
         * @param3 $Data Data to fill the templates with.
         * @param4 $Prefix Default bucket for row data is 'data'. Can be anything else.
         * @note   This function now builds a template file instead of using eval.
         */
        static function Render($Id, $Headers, $Templates, $Data, $Prefix = 'data') {
                $NumCols = count($Headers);

                /* Attempt to just include the cached template file for this table */
                $cached_file_path = TableHelper::CachedFilePath($Id);
                if(!file_exists($cached_file_path)) 
                        TableHelper::BuildTemplate($Id, $Headers,$Templates);
                
                if(file_exists($cached_file_path)) {
                        include_once $cached_file_path; return;
                }

                /* If Cached File cannot be created, just do the EVAL way! */
                echo '< table>';
                echo '< tr>';
                        foreach ($Headers as $header)
                                echo '< th>'.$header.'< /th>';
                echo '< /tr>';

                foreach ($Data as $$Prefix) {
                        echo '< tr>';
                        for ($i = 0; $i < $NumCols; $i++) {
                                        eval("$_cell="$Templates[$i]";");
                                        echo '< td>',$_cell,'< /td>';
                        }
                        echo '< /tr>';   

                }
                echo '< /table>';
        }
}

Catches
The only dependency with this code is that you have to create a Apache writeable folder referenced by the CACHED_TEMPLATES_FOLDER. After that its just fun all the way! Also note that the call to the Render in the unit testing class will now have to be supplied a unique Template Id.

TableHelper::Render($Id, $Headers, $Templates, $Data);

Linux commands output in PHP

My friend Rahul was giving me a demo of their Web UI and a small but nifty feature caught my eye. They had a feature of being able to configure their systems using the Web UI (which is pretty cool in itself!) and the console output from the configuration command in turn would be displayed in a html iFrame. My company has a similar internal tool which does the same but then showing the output in a step-by-step manner would really be a huge help.

Anyways, so cooked up a quick php function for our system. Hope someone finds this snippet useful.

Erlang Ring Code

Erlang Ring Benchmark Problem:
In the Programming Erlang book by Joe Armstrong, we find this problem at the end of the Concurrent Programming chapter.

Write a ring benchmark. Create N processes in a ring. Send a message round the ring M times so that a total of N * M messages get sent. Time how long this takes for different values of N and M. Write a similar program in some other programming language you are familiar with. Compare the results. Write a blog, and publish the results on the Internet!

My contribution to the already growing list of Erlang Ring Benchmark problem. However this is just the code for the Erlang, a N ring setup and M messages moving around the ring in parallel.

Moved to WP 2.5.1

Finally moved the site to WordPress 2.5.1. My own personal blog has been on wordpress.com and that UI was quite inspiring. Now I stand inspired. And definitely the ease with which WP upgrades is quite awesome. However it would have been even greater if I could just upgrade by clicking on a button without even having to download, upload files!

Multiuser Chat using Flex and Ruby

For the last few days I had been googling for some good help for coding networked flash applications for a pet project of mine. Mostly using Flex & Ruby. There have been quite a few I saw – made with flash and using Java; but nothing to my personal liking. And hence I set to build a prototype of my own.

Being a coder and a poor (financially & aesthetically & skillfully :D) visual designer, I am totally in love with Flex for the visual quality it brings to the flash applications i can build.

Ruby for the beauty it brings to the code; but then the code is only as good as the coder. And for cooking up a quick prototype, no language has been so good of course except for Perl (for me ofcourse).

Multiplayer – thats a tricky question. Flash cannot support P2P (peer-to-peer) applications as yet. So the best choice available is to use a client-server architecture – the good ole’ sockets.

Hence using the code from a lot of different places and porting them from other languages, I managed to quickly cook up a Flex multiuser chat application with a ruby backend. Without further ado, into the code.

The server right now runs on the 9999 port of the localhost and the client connects to the same host and port. If you plan to test it on a hosting server, make sure you change the host and the port.

Note: My wordpress code plugin is fucking up the mxml code. For this part you may just download the zip file and use the client.mxml.

The Flex client:

< ?xml version="1.0"?>

	
		< ![CDATA[
			import flash.display.Sprite;
		
			import flash.net.XMLSocket;
			import flash.events.Event;
			import flash.events.DataEvent;
			import flash.events.IOErrorEvent;
			import mx.events.CloseEvent;
			import mx.controls.Alert;
	
			public var socket:XMLSocket = new XMLSocket();
			private var host:String     = "localhost";
			private var port:int        = 9999;
	
			public function init():void	{
				socket.connect(host, port);
	
				socket.addEventListener(DataEvent.DATA, onData);
				socket.addEventListener(Event.CONNECT, onConnect);
				socket.addEventListener(Event.CLOSE, onClose);
				socket.addEventListener(IOErrorEvent.IO_ERROR, onEvent);
			}
			
			private function onConnect(event:Event):void	{
				board.htmlText += "Client: Connected to server" + "
"; } private function ReconnectHandler(event:CloseEvent):void { if (event.detail == Alert.YES) init(); } private function onClose(event:Event):void { board.htmlText += "Disconnected from server" + "
"; Alert.show("Reconnect to the chat?", "Reconnect?", (Alert.YES | Alert.NO), this, ReconnectHandler); } private function onEvent(event:Event):void { board.htmlText += "Error" + "
"; trace(event); } private function onData(event:DataEvent):void { board.htmlText += event.text; } private function sendMesg():void { socket.send(username.text+ ': ' + mesg.text + "n"); mesg.text = ""; } ]]>
.marginstyle { paddingTop:12; paddingBottom:12; paddingLeft: 12; paddingRight: 12; } .spacestyle { paddingTop:2; paddingBottom:2; paddingLeft: 2; paddingRight: 2; }

To compile it to a swf
Assuming you already have the free Flex SDK just use
$> mxmlc client.mxml
which will create a client.swf file for you.

Multiuser Ruby chat server:

#!/usr/bin/ruby
require 'socket'

MSGS = {"init"    => "Server started. Waiting for connections...",
        "welcome" => "Welcome! type EXIT to quit",
        "byebye"  => "Disconnected from server"}

EOF     = "00"
HOST		= "localhost"
PORT		= 9999

server	= TCPServer.new(HOST, PORT)
puts MSGS["init"] 

# array to store all the active connections
sessions = []
while (session = server.accept)
  # push the current session(socket) in the array
  sessions < < session
  # initialize a new thead for each connection
  Thread.new(session) do |local_session|
		local_session.puts "#{MSGS["welcome"]}" + EOF

    # each time a client sends some data send it to all the connections
    while(true)
      data = local_session.gets
			
			if !data.nil?
				delim_pos = data.index(":")
				name      = data[0..delim_pos-1]
				data      = data[delim_pos+1..-1]

				if data[0] == EOF
					data = data[1..-1] 
				elsif data.chomp == "EXIT"
					sessions.delete(local_session)
					local_session.puts "#{MSGS["byebye"]}" + EOF
					local_session.close
					
					data = "#{name} disconnected from the server" + EOF
				end
			end

      sessions.each do |s| 
        begin
          s.puts "#{name}: #{data.chomp}" + EOF
        rescue Errno::ECONNRESET
          # an exception is raised, that means the connection to the client is broken
          sessions.delete(s)
        end
      end
    end
  end
end

To Run
User ruby chat_server.rb

Source Code: Download here. It contains a simple single user server – java & ruby versions [simpleServer.java & server.rb], a multiuser server [chat_server.rb] and the client [client.mxml].

Anyone, any doubts can leave a comment.

The Business of Inertia & Twittersphere experiment

Inertia is an amazing phenomenon since Newton formulated our laws of physics for it. As is the case with any enduring physical truth, there are always economic transactions built on those physics foundations.

And hence we have the M &amp; A of small client-rich companies being bought out by the 800-pound gorillas hoping to use the inertia of the clients to stick with them in the long run.

Inertia also has to its credit a fair-share of financial institutions that tap into its human counterpart – laziness. An amazing vice and a not-so-amazing virtue exploited ever so subtly by many institutions and the most obviously telling one being the credit card companies.

Sample for example, the credit cards business for individuals. It runs simply on one simple truth: that the credit card users will be lazy enough to not to pay her dues not before the due date. Its a clinchingly simple logic that trusts a basic human trait – chilling but effective.

Credit Card (henceforth called as CC) as instrument of finance taps into the deepest sacrosanct evil rule of personal finance.

  • Thou shalt not do the crime if thou can’t do the time a.k.a Don’t buy it if you can’t afford it. CC makes it chillingly simple by providing a hand-loan for a interest free period of 30 days or so.

Armed with a CC and unlimited temptations we have hundreds of well earning guys taking to the temptation and entering that unending cycle of bad financial karma.

Anyway now that we have proved beyond doubt that laziness or simply
inertia can itself be a good business model, a new wave now sweeps the golden lands of bits and bytes which is lovingly called the internet.

andrewbaron has put up his twitter account for sale which at one level is a horrid sin to the community to commit and at another level is a damn interesting social internet experiment.

A twitter account by nature of the micro content created has a single author (content creator) and many readers (followers / consumers). A follower starts following a twitter account on account of one of the following

  • he is a close friend of yours (and thus trusts the ‘author‘)
  • loves the content produced by the author (and hence again adds the user because of the trust he places on the ‘content‘).
  • just follows because he wants to track the author &amp; the activities (not trust but more of a voyeuristic pleasure)
  • just nothing better to do

On the other hand, though a buyer faces one of the following

  • People who trust the author will leave.
  • People who love the content will stay as long as the content still stays original to the soul. In this case, the buyer does not have to put in effort in marketing his twitter account as long as he is good at content.
  • People who will stay for sometime to just see where it goes.

Of this the buyer gains obviously from the second case but thats hoping that the inertia of followers will gain over the indignation of having sold their trust. And which we have already proven works! 😀

Either case this is a interesting social experiment to see how the trust networks and content communities work together.

Announcing BarcampHyderabad5 on 16th @ Google

Its that time of the year again that we folks here call the BarcampHyderabad. And Google has graciously accepted to give us some good space, free food and some goodies to let this get going. Hopefully, we will be able to sneak out some photos of the spanking new Google campus near Kondapur.

The lead team planning out and spreading the message is quite a few this time and hopefully that reflects in the turnouts & participants too.

barcamphyderabad5

What about:
Technologies, demos and startups- betting on Web2.0, Social web, Semantics Web and beyond!
Thats prolly the longest ever Barcamp topic ever! Anyways so if you are a startup guy, a been there done that guy, a research dude or a company eager to show their baby – make it a point to drop in for the party. Hopefully, yours truly too can make some presentation thats worth something.

How to participate?
Go here for joining into the party & participate. How about making a presentation on that spankingly awesome thing you were working on? Think we can get to know something about it? How about giving us a sneakpeak. We are aware of atleast of one startup planning to demo there. Why not you?

For more details and to signup for the camp, go here.

Oh and btw Spread the word!

Hyderabad has a tech community (?)

Reaching out to the right folks and nurturing a community of tech crowd has been a stumbling block for the barcamps’ campaigning. We did try a couple of initiatives – to create a blogroll, to create a hydtechblog, metroblogging for hyderabad – but nothing panned out as expected. Nada. Zilch. Nothing.

And there was the apparent conclusion that our tech community was not exactly thriving – a conclusion that ran counter to our intuition and common knowledge that there are lot of product tech companies in Hyderabad as well as some really good geek gods here.

Intuitioneva Jayate (Intuition alone triumphs). Introducing to you ladies and gentlemen (drum rolls please) Twincling – a very vibrant open source community from mana Hyderabad. Get to their page to know more about.

And if you readers, are aware of any such communities, do give us a tip about them.

the woods are lovely, dark and deep. but …

I deeply respect Vijay Anand for taking the superb initiative of starting and building Proto.in. In fact it is the push that is helping us see other other initiatives coming up viz HeadStart.in and hopefully many more. But guys can you manage your times to see that the startup crowd has access to either Proto.in and HeadStart.in for 3 months; so we as attendees dont have to choose between two platforms?

The point of this post though was this post. Sloka has been in the business for already two years since. Drishti is a four year old company at the least! And Pramati??? To highlight the above three companies as being provided a launchpad at Proto.in… now, thats suspension of disbelief. There are moments when you get carried away, when your baby grows more than your expectations, and I sincerely hope for me and other startups that need more such initiatives, that this one was that moment. It would have been great if you could have highlighted other companies that got funded because of Proto.in.

Proto.in is a trailblazer no doubt but lets not kid ourselves, there is still a very very very long way to go. Or as Robert Frost says “The woods are lovely dark and deep but I have miles to go before I can sleep sleep sleep…