Back to work means back to problems and possibilities and the theme I’m working on will need, for its subscription via front-end process, to use AJAX; the simple use of JavaScript to hide and show the right text part would not make it as I need to save the state of the subscriptions, as in the “what the user was actually compiling”, and different subscription phases will lead to different views to be shown. Think of, as an example, showing a subscribing user some options based on some initial choices.
Who’s calling the shots?
Ajax in WordPress is not such a chore and it all comes down to:
- Registering the Ajax action via a call to
add_action
function - Enqueueing the JS script that will actually fire the action
Having adopted a proto-MVC model, VC actually, it only makes sense that it’s the Controller
responsibility to take care of both the steps above. Since each Controller
object knows nothing of the other controllers the glue among them will be the Theme
class.
This means that controllers could:
- Register an AJAX action
- Tell
Theme
to enqueue a JS file - Tell
Theme
to enqueue a CSS file (to style their own view)
To deal with the fact that having n controllers enqueueing n JS files and n CSS file is very bad optimization I will delegate the Theme
class the task to actually enqueue one single JS file and one single CSS file.
Views, controllers, scripts, styles: it’s becoming crowded in here
Since I’ve gone with folder organization to structure the framework, and made some assumptions about it, I will stay on that path:
- Controllers are in the
/controllers
folder - Views are in the
/views
folder - Scripts will be in the
/scripts
folder - Styles will be in the
/styles
folder
and the folder structure will be updated to the general structure
/root
| Main.php
| /controllers
| | FirstController.php
| | SecondController.php
| /views
| | FirstView.php
| | SecondView.php
| /scripts
| | FirstScript.js
| | SecondScript.js
| /styles
| | FirstStyle.css
| | SecondStyle.css
Where a Controller
extending class might as well not have any script or style to enqueue.
Outsourcing the name resolution
Since the framework puts so much weight on names, those of files and namespaces, it’s not feasible any more to rely on the single classes to take the responsibility to resolve them, furthermore the classes implementing the function are two already, Controller
and Main
, and this is a violation of the DRY principle . It makes sense to build a separate class to do the job and will design it with tests first like
- the class should return a View name given a Controller name
- the class should return a Controller name given a View name
- the class should return a View name given just an element name (like “First”) in the example above
- the class should return a Controller name given just an element name
- …
and so on; using codeception I set-up a unit test class, NamebotTest
, and get down to write some tests to watch them fail.
/**
* @dataProvider nameProvider
*/
public function testWillReturnProperNames($elementName, $controllerName, $viewName, $scriptName, $styleName)
{
// get proper names from the element name
$this->assertEquals($controllerName, NameBot::getControllerName($elementName));
$this->assertEquals($viewName, NameBot::getViewName($elementName));
$this->assertEquals($scriptName, NameBot::getScriptName($elementName));
$this->assertEquals($styleName, NameBot::getStyleName($elementName));
// get proper names from the controller name
$this->assertEquals($elementName, NameBot::getElementName($controllerName));
$this->assertEquals($viewName, NameBot::getViewName($controllerName));
$this->assertEquals($scriptName, NameBot::getScriptName($controllerName));
$this->assertEquals($styleName, NameBot::getStyleName($controllerName));
// get proper names form the view name
$this->assertEquals($elementName, NameBot::getElementName($viewName));
$this->assertEquals($controllerName, NameBot::getControllerName($viewName));
$this->assertEquals($scriptName, NameBot::getScriptName($viewName));
$this->assertEquals($styleName, NameBot::getStyleName($viewName));
// get proper names from the script name
$this->assertEquals($elementName, NameBot::getElementName($scriptName));
$this->assertEquals($viewName, NameBot::getViewName($scriptName));
$this->assertEquals($controllerName, NameBot::getControllerName($scriptName));
$this->assertEquals($styleName, NameBot::getStyleName($scriptName));
// get proper names from the style name
$this->assertEquals($elementName, NameBot::getElementName($styleName));
$this->assertEquals($viewName, NameBot::getViewName($styleName));
$this->assertEquals($scriptName, NameBot::getScriptName($styleName));
$this->assertEquals($controllerName, NameBot::getControllerName($styleName));
}
the method providing the test data simply returns an array of arrays in the form
array(
'SomeNameWith3Numb3rs1inIt',
'SomeNameWith3Numb3rs1inItController',
'SomeNameWith3Numb3rs1inItView',
'SomeNameWith3Numb3rs1inItScript',
'SomeNameWith3Numb3rs1inItStyle'
)
and will use those to test for possible combinations. After some time and some red to green light transition the NameBot
class passes all the tests. The class code is here on Github.
I will move to namespacing and filename resolution then.