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.
- 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 toshow
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. - 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.