1 Review
Let's review basic steps of creating a custom Yii2 widget firstly.
- Create a PHP class extends
yii\base\Widget
; - Override
init
andrun
method ofyii\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>
<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.