Chronicles of a build - the theme framework 02

While trying to make my developing framework pass a first integration test, namely this simple one

    public function testThatCallingMainShowProperlyReturnsString()
{
    $this->expectOutputString('First');
    MainChild::show('First');
}

I had to make some design decision and simply tried to stick to my first desire not to burden the framework with a complex learning curve. This is made both for future users, hopefully, and thinking about me getting back to it and finding it awkward, difficult and of little use. The target is still the same, I want to be able to write WordPress theme templates like

// file index.php

<?php 
Theme::show('head'); // calls wp_head too
Theme::show('headerBanner', array('color' => '#FFF', 'bgImage' => 'unicornsAndRainbows')); // because I like white  banner background
Theme::show('sidebar', array('left'));
Theme::show('content', array('titleHeaderSize' => 'h3', 'showExcperpts' => true, 'showRelated' => true, '   coloredReadMore' => true));
Theme::show('contactFooter' , array('mail', 'skype', 'twitter'));
Theme::show('footer', array('color' => '#FFF')); //calls wp_footer too
 ?>     

And I’m pasting the file to show that no further setup is needed.

Either leave many options or take many decisions

Even thinking about myself as a WordPress theme developer using the framework I stick with the idea that “less is more” and that I’m empowering myself via a framework not by giving the user the possibility “to do more” but allowing the user “to do less”. Less set-up, less variable definition and so on.
The decisions I made are:

  • The main theme class, controllers and relative views can be anywhere in relation to the basic abstract main, controller and view classes on the disk but will have to stick to a certain folder organization
  • The main theme class, controllers and relative views can be defined in any namespace, even in the basic one, but will have to stick to a certain namespace organization
  • The extending controllers and relative view classes will have to stick to a certain file and class naming convention

The structure revolves around the location, as file to the path, of the file the class extending the Main one is at. The folder structure is expected to be set like

someFolder
    |   MyThemeMain.php // declares \Foo\Baz\MyThemeMain class
    |   controllers
    |   |   SomeController.php // declares \Foo\Baz\controllers\SomeController class
    |   |   SomeOtherController.php // declares \Foo\Baz\controllers\SomeOtherController class
    |   views
    |   |   SomeView.php // declares \Foo\Baz\views\SomeView class
    |   |   SomeOtherView.php // declares \Foo\Baz\views\SomeOtherView class

Folder structure is reflected in namespacing structure and class names are reflected in file names. Very common and easy to remember. The state of the framework at this point is tagged on GitHub.

Moving to unit-testing to define behaviours

I will use test to define expected behaviours and will do so writing tests. Since my goal is to be able to use calls like

Theme::show('something');

I will start defining some expected behaviours for the class and will do so not in the extending one but in Main, the parent abstract one.

  1. I will be calling the show method in templates and a show-stopping error will not do. Furthermore I want to be able to use the calls to show as placeholders way before I write controllers and view hence will return some valid HTML markup when trying to call in some non-existing controller.
  2. I will include just the file that declares the Main extending classes in my themes (\path\to\Theme.php in the example above) and could have made a mess of the file organization or namespacing. I want the framework to politely tell me.

In test code this becomes

    public function testCallingShowOnNonExistingControllerReturnsMessage()
{
    // Foo is not a controller
    $nonControllerName = 'Foo';
    // I expect some kind of output message containing the called controller name
    $regex = "/.*$nonControllerName.*?/uUs";
    $this->expectOutputRegex($regex);
    TestMain::show($nonControllerName);
}

The code for the Main::show method is

    public static function show($name, $args = null)
{
    // eventually inits the controllers
    self::init();
    self::$controllers[$name]->show($args);
}

and will fail the test with the result

There was 1 error:

---------
1) MainTest::testCallingShowOnNonExistingControllerReturnsMessage
ErrorException: Undefined index: Foo

#1  /Users/Luca/Dropbox/Developer/WebDeveloper/vhosts/plugins/tad-libs-for-wordpress/libs/mvc/Main.php:13
#2  /Users/Luca/Dropbox/Developer/WebDeveloper/vhosts/plugins/tad-libs-for-wordpress/tests/unit/MainTest.php:19

FAILURES!
Tests: 38, Assertions: 63, Errors: 1.

Throwing an ErrorException and failing the test. I change the Main::show method to

    public static function show($name, $args = null)
{
    // eventually inits the controllers
    self::init();
    // return good markup if a non-existing controller is called
    if (!in_array($name, self::$controllers)) {
        echo "<h3>$name is not a defined controller</h3>";

        return;
    }
    self::$controllers[$name]->show($args);
}

And the test will pass. Dealing with a messy file or namespacing organization and wanting the Main class to still be as ablative as possible I will laid out some more unit tests.