Converting a simple XML snippet to an array

2010
14
December

The need to convert a snippet of XML to a PHP array is something you are bound to encounter if you develop in PHP and are making calls to web services. Since everything has to be mashable these days, this includes more or less every PHP developer out there.

So I thought I'd share a tiny code snippet that will convert simple XML snippets in to an array. Keep in mind that when I say simple I mean SIMPLE. It doesn't support attributes, namespaces or any other goodies.

I packed the snippet wrapped in a class for tidiness and published it on GitHub so go fetch: XmlToArray.php


Splitting up your Habari plugin in smaller logical modules

2010
23
November

Today I'll show a way of splitting up a plugins logic into multiple files without losing all the magic that makes writing habari plugins so easy and more importantly without making the plugin overly complex.

I assume you are already somewhat familiar with the Habari plugin system and of course that you know PHP. I will not explain anything in detail so don't expect a cut and paste tutorial. I'm just explaining the concept, the implementation I leave for you to experiment with.

The basics

Writing a plugin for Habari couldn't be easier. For instance all you have to do in order to expose a new method to your theme is add a public function whose name starts with "theme_" to your plugin.

Below is the comments_number function made famous by WordPress, implemented in a Habari plugin.


public function theme_comments_number($theme, $zero, $one, $more)
{
    $c = $theme->post->comments->moderated->count;
    switch ($c)
    {
        case '0':
                return $zero;
            break;
        case '1':
                return str_replace( '%s', '1', $one );
            break;
        default :
            return str_replace( '%s', $c, $more);
    }    
}

The call to "comments_number" from the theme would look like this:


<h2><?php $theme->comments_number('No Responses', 'One Response', '%s Responses' );?></h2>

While this is quite powerful and good enough for most cases, sometimes you need a little flexibility. In Habari we can solve this with the "alias" method.

Hooking the aliases

The Habari documentation says:
"By creating a method named alias() in the pluggable class that returns an associative array, a plugin or theme can specify functions to use for specifically named hooks."

Habari exposes a set of predefined hooks that can be used by a plugin to alter the behavior of themes or in some cases Habari internal functions. In our very first example we talked about the function "theme_comments_number". Although this is not a Habari built in function it is regarded as a hook nonetheless. The only difference is that the hook is defined by the theme and not Habari core.


// single hook
function alias()
{
  return array(
    'my_hook_function' => 'filter_spam_filter',
  );
}
// multiple hooks
function alias()
{
  return array(
    'my_hook_function' => array( 'action_post_content_out', 'action_post_content_excerpt', 'action_post_content_summary' ),
  );
}

A simple module system

Using what we've learned so far we could easily build a plugin module system that loads the plugin logic from other files. For simple plugins there would be little to gain from this but for complex plugins that expose multiple logically separated functionality this would if nothing else increase the readability and maintainable of the plugin. A very basic module system could be implemented with just a handful of lines of code, where the heavy lifting is done by the "alias" and "__call" methods.

First we would need a way of loading modules. This could be a simple function that included all php files in a certain directory. The modules would then have to implement a specific interface exposing a function for our plugin/module handler to gather information of what functions to expose. Directly after plugin instantiation the alias() function, if it exists, will be called. This makes it an ideal place to trigger the loading of our modules. As mentioned above Habari expects the alias method to return a list of hooks and functions for the plugin, so we make sure our modules report back what functionality they expose when they are first loaded.

Because multiple modules may hook the same functions we need to keep track of which module loaded what somehow. One way of doing it would be to have an internal registry in our plugin, but for this example I chose to let Habari keep track for me by extending the name of the module function with the module name. That way we will know what module a function belongs to when the call goes through "__call".


    public function alias()
    {
        $this->loadModules(); // loads our modules in to $this->modules

        $aliases = array();
        foreach( $this->modules as $name => $module )
        {
            $prepArray = function($module_name, $array)
            {
                $result = array();
                foreach($array as $key => $val)
                {
                    if ( strpos($key, $module_name) !== 0 )
                    {
                        $key = $module_name .'_'. $key;
                    }
                    
                    $result[$key] = $val;
                }
                
                return $result;
            };
            
            $aliases = array_merge_recursive( $aliases, $prepArray($name, $module->aliases()) );
        }

        return $aliases;
    }

Since Habari expects all functions registered in alias() to be functions in the main plugin class we need to add someway to listen for them. The easiest way to do that is using the magic function "__call". All we need to do in __call is find out what module the call belongs to and then pass it along together with all the parameters, and since we added the module name to the function names in alias() this is quite simple.


	public function __call($method, $params)
	{
	    if ( strstr($method, '_') )
	    {
	        list($module_name, $method_name) = explode('_', $method, 2);
	        if ( isset($this->modules[$module_name]) && method_exists($this->modules[$module_name], $method_name))
	        {
	            return call_user_func_array( array($this->modules[$module_name], $method_name), $params );
	        }
	    }
        
        return false;
	}

We can now write a simple module that will automatically be loaded, resulting in the function "my_test_method" to be exposed to the blog theme.


class myplugin_mymodule
{
    public function aliases()
    {
        return array(
        	'test' => 'theme_my_test_method',
        );
    }

    public function test()
    {
       return 'fiskar';
    }
}

Beautiful isn't it?


lighttpd redirect quirk

2010
29
October

You know how sometimes it seems like the entire world is against you? The other day was like that for me.

I wanted to add a simple url redirect for a vhost using url.redirect in lighttpd, but It seemed like no matter what I tried it just wouldn't work. The vhost configuration contained a rewrite rule that would rewrite all non static file requests to the same file. I knew that this catch-all rule would capture the request I wanted to redirect so I added the redirect rule at the top of the configuration as I would have done had this been an apache environment.

Turns out that unlike apache, lighttpd will always trigger rewrites before redirects regardless of their order in the configuration. This is another one of those undocumented quirks that makes it difficult to move from apache to lighttpd. To me this behavior is quite strange. Why waste cpu-cycles rewriting an url if you are going to redirect the visitor away from your site?

Once I knew about the rewrite quirk the solution was quite simple, just add another rewrite rule that does nothing if the request url matches your redirect pattern. It's a bit clumsy but it works.

ex:


url.redirect = ("^/foobar/(.*)$" => "http://somewhereelse.com/$1")
url.rewrite = (
    "^/foobar/(.*)$" => "$0",
    "^/(?!(_css|_js|_img))" => "/mvc.php"
)

This was even more annoying than when I spent a few hours trying to get each of my vhosts to write to their own error log. It doesn't work, lighttpd only supports one error log. gaAH!! ;)


Civilization 5 addiction

2010
18
October

On September 24th (21th in North America) of this year something horrible happened, Firaxis released Civilization V. You are probably wondering why this is so bad. Well, if you are a recovering civilization addict like myself, a new Civ game can be devastating to your productivity and social life. Unfortunately for me the new game did have exactly that effect, something my girl friend would confirm if you asked her (sorry babe ;)).

Because of the game that we will no longer mention by name, a month has passed since my last post. While this is not uncommon it's not a good thing and I'd like to change that trend.

A while back we decided to use GitHub for the open source code that we produce at Flattr and as a result of that I had to create a GitHub account. Most of the code that we produce at Flattr is not, for obvious security reasons, open sourced. Which is also quite evident if you look at my GitHub profile.

Yesterday I decided that I'd upload something so that my profile page wouldn't be quite so desolate. I also wanted to update this blog somehow and thought I'd kill two birds with one stone, so to speak. This desire, coupled with my before mentioned addiction to Civilization V <argh! I said it>, lead to what I like to call the 'Civ5 Addictionometer' or Civ5 Habari plugin if you like to get technical.

The Civ5 Addictionometer is a plugin for the Habari blog system (tested on 0.6.4) that when added to your blog will say just how much time you've wasted spent playing Civilization 5. While this might seem utterly pointless to some, to me it's genius. Now when people are wondering why they haven't heard from me in a few days they can instantly see (by visiting my blog of course) that the reason for this is that I've been busy ruling the world (on Civilization 5). Now one could argue that it would be better if I stopped playing the game but that would just be nonsense. Nonsense I tell you!

If you, like me, suffer from Civ addiction and happen to run a Habari blog you can get the plugin from GitHub.


Bit flags

2010
14
September

As hardware has gotten cheaper and with the advance of high level programming languages developers rarely have to consider cpu, memory limitations, or efficiency when they write their code. The obvious exception being developers working on drivers, operating systems or other low level operations.

The pros of this are obvious to most developers but one con that is often overlooked is that certain idioms and tricks of the trade have become something of a lost art.

more