Requests for comment/MVC framework

From mediawiki.org
Request for comment (RFC)
MVC framework
Component General
Creation date
Author(s) Owen Davis
Document status in draft

Summary[edit]

Wikia has developed an MVC framework called Nirvana. Documentation is available here: Developer Wiki Rather than try to use a third party MVC library, we built one that addressed some of the limitations of the way HTML is usually generated in MediaWiki extensions and was aware of it's quirks (like, having a good way to use global variables without having to coyp them all over the place). We feel like it provides improvements over the core QuickTemplate and XML objects, and we have used it to build our Skin and all extensions for about 2 years now.


Description[edit]

The implementation is similar to the existing QuickTemplate combined with a DataTransferObject pattern. The main goal was to separate data from presentation and get away from the Xml object by just using plain PHP templates with simple variables and loops allowed in the template. The templates are still PHP files but by convention we do not put (much) logic there. We have also added support for Mustache templates to allow use of the same templates in the front end code. Those are pure data with no loops allowed. Any controller class can provide a PHP array (for internal callers), JSON data for javascript, and a rendered HTML template for UI. There is also "Service" class that just provides data. Most of the functionality is oriented towards making it easier to build skins, special pages and ajax functions.

Comments[edit]

I think moving away from xml is a great step, after all PHP is best at templating. I would be cautious of using Moustache, it's PHP implementation used to be very slow (about two orders of magnitude slower than PHP templating, tested this 2 years ago. Hopefully has improved) . If you are set in sharing templates perhaps handlebars php implementations is worth considering. Handlebars extends mustache with if/else constructs and loops. A template engine without those constructs is very limited. For example, a basic case that a template engine should satisfy is printing a table with different color rows depending whether the row is even or odd, this in Handlebars is trivial, in Mustache is not so friendly. The logic of whether a row is green and the next one red should only be in the template, if that knowledge needs to be passed from elsewhere it shows a deficiency of the template engine.

Couple other cases that a template engine needs to be able to trivially support: Link construction and client side translations with parameter substitution, two things that are, again, very easy to do in a engine that allows to plug in code (Handlebars) but are not easily done in Mustache.

A possible handlebars php implementation: https://github.com/XaminProject/handlebars.php NRuiz (WMF) (talk) 10:26, 26 March 2014 (UTC)[reply]

Problems[edit]

This is currently interwoven with some unrelated utility code that would need to be separated. We would be interested in reviewing this code with some other developers to see if it might be useful to the Foundation for building new core special pages and extensions. The framework is specific to Mediawiki right now, which we consider to be an advantage. It could also be considered a "mini-framework" and separated into a standalone library without much work.

Examples[edit]

Example code:

class HelloWorldController extends WikiaController {
  // default method=index 
  public function index() {
    $this->data1 = "Hello";
    // normal web request from Context
    $this->data2 = $this->request->getData("helloparameter", "World");
    $this->msg1 = 'hello-message';
  }
}

Example template. All public controller properties are exported as globals to the template context. HTML fragments or entire HTML doc, either is fine :

<ul>
  <li>Hello World</li>
  <li><?= $data1 ?> <?= $data2 ?> </li>
  <li><?= wfMessage($msg1)->text(); ?> </li>
</ul>

To call this controller and use this template from a second template you can include/render it with a single line in a couple of ways

<?= $this->renderView('HelloWorld', 'Index') ?>
// This uses the same template but not the controller function, just pass in your own data
<?= $this->renderPartial('HelloWorld, 'Index', ['data1' => "Hello World", 'data2' => "Hello World", 'msg1' => 'hello-message']); ?>