Guides

Consistent UI with YiiBooster

October 29, 2013

Imagine for a moment what it takes to write UI using the Twitter Bootstrap UI toolkit in the views of Yii-based web application.

  1. You have to remember what CSS classes do the thing you need and where to put them.

    For example, it’s certainly not obvious that you have to write class="label label-info" instead of, let’s say class="label-info" or even class="info" directly on the paragraph element.

  2. You have to remember what HTML structure should be for what widget.

    For example, you are sure you truly remember by heart that to make an alert panel with close button you have to write the following:

         <div class="alert">
             <button type="button" class="close" data-dismiss="alert">&times;</button>
             <strong>Warning!</strong> Best check yo self, you're not looking too good.
         </div>
    

    ?

  3. You have to stuff your domain data from models in between all of this stuff somehow.

Don’t know about you, but as for us here at Clevertech it’s not only harmful and error-prone, but also just plain boring.

YiiBooster

YiiBooster was created because of that very reason. Cristopher Niska laid the groundwork for us by wrapping all of Bootstrap widgets in Yii, erm, widgets, constructing the Yii-Bootstrap project and then Antonio Ramirez came and began stuffing third-party UI controls in there until it became the YiiBooster. From there, we are constantly improving it, in the quest to make it the best widget toolkit library for PHP applications ever.

That’s how you write the minimal HighCharts plot in your views, given that YiiBooster is installed into your Yii application:

    $this->widget('bootstrap.widgets.TbHighCharts', [
        'options' => [
            'series' => [
                'data' => $your_PHP_array_of_one_dimensional_data
            ]
        ]
    ]);

Well, you also need PHP 5.4 to write arrays this way, but nevertheless. All you have to remember is the name of widget and what options are accepted by the original highcharts javascript library.

You see, this alleviates the following issue also:

  • You have to remember what Javascript libraries where and in what order you have to include in your page.

Please, note that for quite a long time YiiBooster will not migrate to Bootstrap 3, because it will break so much of already existing UI of users of old YiiBooster. Or maybe of people who dislike flat buttons.

Consistency with Yii widgets and helpers

Let’s say you already have the menu being rendered with

$this->widget('zii.widgets.CMenu', ['items' => $menu_items]);

If you decided to install YiiBooster and migrate your UI to Twitter Bootstrap goodness, all you have to do to convert the menu above is to change zii.widgets.CMenu to bootstrap.widgets.TbMenu. Items declaration is fully backwards-compatible.

Another example is Detail View:

    $this->widget(
        'zii.widgets.CDetailView',
        [
            'data' => $model,
            'attributes' => array_keys($model->attributes)
        ]
    );

(in real world you probably will not want to just flush all of model attributes like that).

Let’s style it according to Bootstrap goodness:

    $this->widget(
        'bootstrap.widgets.TbDetailView',
        [
            'data' => $model,
            'attributes' => array_keys($model->attributes)
        ]
    );

«But it’s all the YiiBootstrap», you will say. «Where’s the YiiBooster?».

Here’s how you convert this Detail View to have each field freaking inline editable, courtesy of X-Editable plugin:

    $this->widget(
        'bootstrap.widgets.TbEditableDetailView',
        [
            'data' => $model,
            'url' => $endpoint,
            'attributes' => array_keys($model->attributes)
        ]
    );

All you have to do is add the url setting value which is the URL of the endpoint handling the update requests. Also, here you most possibly will not want all of model attributes, as TbEditableDetailView (currently) works only with safe attributes.

We will not claim that compatibility is 100% for every widget in the YiiBooster library (to setup TbSelect2 dropdown you’ll need to provide completely different configuration than for CHtml::dropDownList), but the compatibility with vanilla Yii code is one of the goals.

An example of consistency with CActiveForm helper methods:

    $form = $this->beginWidget('bootstrap.widgets.TbActiveForm');

    echo $form->datepickerRow($user, 'birthDate', [
        'options' => [
            'orientation' => "top right"
        ],
        'style' => 'width:486px' // sorry about that
    ]);
    echo $form->select2Row($user, 'knownLanguages', [
        'asDropDownList' => false,
        'options' => [
            'tags' => ['en', 'ru', 'es', 'ja', 'sa'],
            'placeholder' => 'two-letter language code, please',
            'width' => 500
        ]
    ]);
    echo $form->ckEditorRow($user, 'dossier', [
        'options' => [
            'plugins' => $onlyBasicPlugins,
            'width' => 500
        ]
    ]);

    $this->endWidget();
    unset($form);

Yes, even CKEditor Row. We included most feature-packed version of CKEditor, just because to disable existing features is simpler than to enable not installed ones.

Example of how the form looks like made with TbActiveForm

TbActiveForm will be totally rewritten by one of awesome contributors, PR is already there at GitHub. This will bring crazy easy methods to extend your active form definitions with your own widgets, but under the same interface.

A Framework Only

It’s worth noting that YiiBooster is not intended to write less code, it’s your job to write shortcuts. It’s intent is to write consistent and easy to change code.

For example, to write the marker for important stuff you have to write the following in vanilla HTML:

    <span class="label label-important">Important</span>

But you’ll have to write the following using YiiBooster to get the exactly same markup:

    $this->widget(
        'bootstrap.widgets.TbLabel',
        [
            'type' => 'important',
            'label' => 'Important',
        ]
    );

It’s, you know, 51 char versus 148 char, threefold increase in typing. However, if you have a lot of paragraphs having this markers at the beginning, nothing prevents you to write the following in the controller:

    public function important($contents)
    {
        $type = 'important';
        $label = ucfirst($type);
        $toString = true;
        $marker = $this->widget('bootstrap.widgets.TbLabel', compact('type', 'label'), $toString);
        echo CHtml::tag('p', [], sprintf('%s %s', $marker, $contents));
    }

And then you can write the whole paragraph like that in your views:

    $this->important('You have to was hands before dinner, always.');

And forget about the label widget configuration altogether.

But We Have Helpers, Too

Despite the previous section’s disclaimer, we like helpers and shorthands. So, we included two javascript-only libraries into YiiBooster, just because. They’re not a HTML+CSS+Javascript widgets, but just a helpers for you to write concise meaningful Javascript UI.

It’s a Bootbox.js modals library and Notify.js notification library.

When you have YiiBooster installed in your project, you can rely on the existance of following features:

    bootbox.alert('You forgot to wash hands!');

This will imitate in-browser alert call using Bootstrap modals.

bootbox.alert example result

Same for confirm and prompt:

    bootbox.confirm('Have you washed your hands?', callback);

bootbox.confirm example result

    bootbox.prompt('Tell me, what do you think about the current geopolitical situation in the world:', callback);

bootbox.prompt example result

See the bootbox.js documentation for details. Just note that we are using version 3.3 of this library, as it’s the last version to support Bootstrap 2.3.2.

Also notifications:

    $.notify('Ding! I\'m here in topright corner!');

global notification example screenshot

See that little blob in topright corner of the screen?

You can make notification appear from any jQuery-findable object:

    $('a[title="Developer package"]').notify('Do not forget to RTFM, btw.');

local notification example screenshot

See the notify.js documentation for details.

Grid Views

By the way, we have stuff which probably is not a “widget”, but a full-blown user interface itself in YiiBooster. It’s an TbExtendedGridView, by the courtesy of Antonio Ramirez only.

It’s so full of features that we’ll not dare to describe them in this relatively short overview article. Just go to the showcase page for Extended Grid View at our documentation website and read the details there.

Also note, having experimented with grid views a lot, we accumulated quite many different separate implementations of various features, spread out in whole bunch of classes: TbGridView, TbExtendedGridView, TbJsonGridView and even TbGroupGridView. This horror has to be ended, so we’re going to redesign the grids into something absolutely spectacular, the same way it was done with TbActiveForm. Most possibly make an united grid widget for all of this separate features, but this will take time, of course.

Work In Progress Disclaimer

We have to note that currently YiiBooster is in active development state and while we are doing everything we can to keep it stable between releases, there’ll be inevitable backwards-incompatible changes when we’ll add something cool or fix something not so cool.

For example, a Grand Redesign of Grid View is coming, and most possibly your existing TbGridView, TbExtendedGridView and TbJsonGridView all will need to be migrated to new structure.

Of course the goal of such a changes is not for our users become frustrated, but to provide to them next level of ease of configuration. We are really merciless to old code in such situations.

Also, documentation is work in progress, too, so for now for some parts of YiiBooster your best bet is to read the widgets' source code. Just remember that documentation is work in progress, not abandoned completely.

Conclusion

Well, this is it. Hopefully, YiiBooster will bring you personally the same benefits we envision in this library, will help you write readable view files describing consistent UI.

If you are interested in contributing something clever and useful to YiiBooster, welcome to its GitHub repo, pull requests with new features and bug reports are always welcome there.

Previous: How to package and use Yii framework in PHAR Next: Making Websites With YiiBoilerplate