Create Yii Extension by Example - EPrism
This is the tutorial about how to make a simple Yii extension. It would be most useful to people who are just starting with Yii framework. The tutorial is step-by-step guide using an EPrism extension as a base. This would be really helpful if for example you found a nice JavaScript plugin and want to use it as a part of framework rather than just adding it statically in your application.
1. Set up
Everything needs to start from something, so do the following steps to have a base on which you can build your extension:
- Create a folder
EPrism
for extension - Create an extension file name
EPrism.php
inside the folder - Create a class
EPrism
which extends a framework class ofCWidget
in theEPrism.php
file - Add
init()
andrun()
methods
CWidget
class is a base class for widgets. You can think of a widget as a self-contained component that may generate presentation based on model data.
The init()
method initializes the widget.
The run()
method executes the widget.
Step results
By now your folder structure should be:
EPrism/
└── EPrism.php
The contents of EPrism.php
file should be:
class EPrism extends CWidget
{
public function init()
{
return parent::init();
}
public function run()
{
}
}
2. Add extension assets
To be able to use the extension out of the box, you need to add the assets for it. Start by creating a folder assets
which will contain the extension assets.
Now go to the Prism download page, generate the wanted configuration, and download provided code. Save JavaScript code as prism.js
in assets
folder, and CSS code as prism.css
in the same folder.
To use the downloaded assets you will need to add the code to run()
method.
First you want to publish your assets to a web accessible directory:
$assets = Yii::app()->getAssetManager()->publish(dirname(__FILE__) . '/assets');
Also get ClientScript component to help you with registering your assets:
$cs = Yii::app()->getClientScript();
Because Prism only needs the asset files added to page for it to run, all that is left is to register the assets:
$cs->registerCssFile($assets . '/prism.css');
$cs->registerScriptFile($assets . '/prism.js');
The registerCssFile()
and registerScriptFile()
adds the CSS and JavaScript files to the rendered page. If you needed to run some JavaScript code to run the plugin then you will need to add a call to registerScript()
method which will add your JavaScript code to the page.
And this is it. You only need this much code to create a simple Yii extension. But of course it can be improved so continue reading if you want to get some ideas how to improve your extensions after having the minimal needed code.
Step results
By now your folder structure should be:
EPrism/
├── EPrism.php
└── assets
├── prism.css
└── prism.js
The contents of EPrism.php
file should be:
class EPrism extends CWidget
{
public function init()
{
return parent::init();
}
public function run()
{
$assets = Yii::app()->getAssetManager()->publish(dirname(__FILE__) . '/assets');
$cs = Yii::app()->getClientScript();
$cs->registerCssFile($assets . '/prism.css');
$cs->registerScriptFile($assets . '/prism.js');
}
}
3. Add customizations for script
The extension currently does what it's supposed to do, but how about adding a couple of customizations like allowing to change the position of where script is inserted and disabling automatic highlighting.
Change script position
First add the class variable which will tell where JavaScript files should be inserted:
public $scriptPosition;
Then add the following code at the start of init()
method:
if (is_null($this->scriptPosition)) {
$this->scriptPosition = Yii::app()->clientScript->defaultScriptFilePosition;
}
It will make sure that if you don't set a custom script position for the extension, the default position for all script files will be used.
To finish it off just set the position then registering script file in run()
method:
$cs->registerScriptFile($assets . '/prism.js', $this->scriptPosition);
Now if for example you need to have some script loaded in the <head>
element while your application is configured to add all scripts before closing <body>
it is very simple to do in a widget configuration.
Disable automatic highlighting
Prism automatically highlights the code in your page, but you can turn it off by adding data-manual
attribute to the <script>
element which loads the plugin.
You will need to add two variables, one for holding all the options for script and another as a flag for manual highlighting:
private $scriptOptions = [];
public $manualHighlight = false;
The $scriptOptions
variable is private because you don't want anyone changing it (the widget will populate it with needed values). To make sure it happens add the following code in the init()
method before returning parent method:
if ($this->manualHighlight) {
$this->scriptOptions['data-manual'] = true;
}
And then add options then registering your script file:
$cs->registerScriptFile(
$assets . '/prism.js',
$this->scriptPosition,
$this->scriptOptions
);
Now you can disable the automatic highlighting when you call the widget just by setting manualHighlight
attribute to true
.
Allow to use custom asset files
To make extension re-usable and easy to use we added the JavaScript and CSS assets to it, but in some cases you might not want to use them. Maybe you only need to use a small portion of highlighter or maybe you have all the needed code in another file. To take care of those cases lets make asset files configurable using the following rules:
- If value is
false
don't register asset - If value is
null
register default asset - If value is
string
register the provided value
To allow for this configuration first add the following class variables:
public $cssFile
public $scriptFile
And then change the asset registration lines with extended logic:
if ($this->cssFile !== false) {
$cs->registerCssFile(
$this->cssFile ? $this->cssFile : $assets . '/prism.css'
);
}
if ($this->scriptFile !== false) {
$cs->registerScriptFile(
$this->scriptFile ? $this->scriptFile : $assets . '/prism.js',
$this->scriptPosition,
$this->scriptOptions
);
}
This simple change allows you to be much more flexible with widget usage.
Step results
You folder structure hasn't changed so it will be the same as before.
The contents of EPrism.php
file should be:
class EPrism extends CWidget
{
private $scriptOptions = [];
public $manualHighlight = false;
public $scriptPosition;
public $cssFile;
public $scriptFile;
public function init()
{
if (is_null($this->scriptPosition)) {
$this->scriptPosition = Yii::app()->clientScript->defaultScriptFilePosition;
}
if ($this->manualHighlight) {
$this->scriptOptions['data-manual'] = true;
}
return parent::init();
}
public function run()
{
$assets = Yii::app()->getAssetManager()->publish(dirname(__FILE__) . '/assets');
$cs = Yii::app()->getClientScript();
if ($this->cssFile !== false) {
$cs->registerCssFile(
$this->cssFile ? $this->cssFile : $assets . '/prism.css'
);
}
if ($this->scriptFile !== false) {
$cs->registerScriptFile(
$this->scriptFile ? $this->scriptFile : $assets . '/prism.js',
$this->scriptPosition,
$this->scriptOptions
);
}
}
}
Bonus points: Sharing is caring
At this point you have a working, customizable extension which will kick ass in your project. But how about sharing it with your fellow programmers?
Simply add readme explaining how to use your extension and some comments in the code explaining what is what. Even if you're not going to share the extension with others, you will thank yourself later when the time comes to improve it. Include the composer.json
file to make it possible to use your extension through Composer and just share it on GitHub or somewhere else for everyone to enjoy.
Conclussion
Now you can relax and take a well deserved cup of tea.