Yii2 Example: Create Yii2 Custom Widget - Advanced Part

 ·  · 

1 Review

Let's review basic steps of creating a custom Yii2 widget firstly.

  • Create a PHP class extends yii\base\Widget;
  • Override init and run method of yii\base\Widget. init is used to do some initializing work, run is responsible for rendering the view of a widget.

In earlier basic tutorial, we do lots of HTML echoing work in run method. If the function of your widget is complex, the run method will be too long to be maintained. And we may also have to mix in many CSS and JavaScript codes. It's a mess.

The solution is to separate HTML view, CSS and JavaScript from run method.

 

2 Organize Views and Assets

Create new subfolders to organize view templates and assets files.

your_app (e.g. frontend)/
    - votewidget/
        - assets/
            - js/
                - votewidget.js
            - css/
                - votewidget.css
        - views/
            - _vote.php
        - VoteWidget.php
        - VoteWidgetAsset.php

2.1 Move Rendering Codes To View Template

First if all, rendering work in view file, _vote.php:

<?php
// your_app/votewidget/views/_vote.php

use yii\helpers\Html;
?>

<div>
    <h4><?= Html::encode($product->title) ?></h4>
    <div>
        <img src="<?= $product->image ?>">
    </div>
    <div>
        <a class="up-vote"><i class="fa fa-thumbs-o-up"></i></a>
        &nbsp;&nbsp;&nbsp;&nbsp;
        <a class="down-vote"><i class="fa fa-thumbs-o-down"></i></a>
    </div>
</div>

2.2 Manage Assets Files Using AssetBundle

Secondly, we will register and manage CSS and JavaScript files used by the widget using Yii2 class yii\web\AssetBundle.

In VoteWidgetAsset.php file:

<?php
// your_app/votewidget/VoteWidgetAsset.php

namespace frontend\votewidget;

use yii\web\AssetBundle;

class VoteWidgetAsset extends AssetBundle
{
    public $js = [
        'js/votewidget.js'
    ];

    public $css = [
         // CDN lib
        '//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css',
        'css/votewidget.css'
    ];

    public $depends = [
        'yii\web\JqueryAsset'
    ];

    public function init()
    {
        // Tell AssetBundle where the assets files are
        $this->sourcePath = __DIR__ . "/assets";
        parent::init();
    }
}

2.3 Register VoteWidgetAsset And Render View Template

2.3.1 Register VoteWidgetAsset

Now the run method of widget class will be quite simple and clean.

<?php
// your_app/votewidget/VoteWidget.php

namespace frontend\votewidget;

use yii\base\Widget;
use yii\helpers\Html;

class VoteWidget extends Widget
{
    public $model;

    public function init()
    {
        parent::init();
    }

    public function run()
    {
         // Register AssetBundle
        VoteWidgetAsset::register($this->getView());
        return $this->render('_vote', ['product' => $this->model]);
    }
}
?>
2.3.2 Widget View File Path

By default, views for a widget should be stored in files in the YOUR_WIDGET_PHP_CLASS_FILE_FOLDER/views directory. Alternatively, you can specify a customized view path, there are two ways to do this.

The first way, use view path directly. For example:

public function run()
{
    VoteWidgetAsset::register($this->getView());
    return $this->render('@app/views/_debug', ['product' => $this->model]);
}

Code above will render _debug.php under YOUR_APP/views/ folder.

The second way, override yii\base\Widget::getViewPath() method.

<?php
// your_app/votewidget/VoteWidget.php

namespace frontend\votewidget;

use yii\base\Widget;
use yii\helpers\Html;

class VoteWidget extends Widget
{
    public $model;

    public function init()
    {
        parent::init();
    }

    public function run()
    {
        VoteWidgetAsset::register($this->getView());
        return $this->render('_debug', ['product' => $this->model]);
    }

    public function getViewPath()
    {
        return '@app/views/';
    }
}
?>

The effect is the same as the first way.

More knowledge about Yii2 path alias please refer to Yii2 document.

It's time to use and test the widget in controller action's view now.

<?php
// view file of your test controller action

use frontend\votewidget\VoteWidget;

// a faked model
$fakedModel = (object)['title'=> 'A Product', 'image' => 'http://placehold.it/350x150'];
?>

<?= VoteWidget::widget(['model' => $fakedModel]) ?>

 

3 Summary

Write your own Yii2 widget is simple, just extend Yii2 class yii\base\Widget.

It's best practice to separate assets files and view files from widget PHP class file, which will make your widget much more maintainable.