Tuesday, November 08, 2011

How to Write a symfony Plugin

One of the main things that makes symfony great is its thorough, clearly-written documentation. However, the documentation on how to write a plugin seems a trifle incomplete, so I will attempt to supplement it here by writing a comprehensive, step-by-step tutorial.

First let me point out what is already out there. The official documentation on how to write a symfony plugin is here. There is also a slideshow here (apparently authored by Fabien himself) that sheds some more light on the subject. Using these two sources I was able to piece together a plugin of my own but it took some head scratching. My goal here is to walk you through the plugin creation process with minimal cognitive strain.

The Plugin: jsHelloWorldPlugin

The plugin we will write today will be called jsHelloWorldPlugin. A quick note about the name: The "sf" prefix is reserved for symfony-ordained plugins. I chose "js" for my initials but the first two letters can, of course, be whatever you want them to be. The name of the plugin should end in "Plugin".

To keep things simple, we'll have this plugin perform one simple (and classic) task: print "Hello, world!" to the screen. We'll accomplish this by creating a symfony task.

Installing sfTaskExtraPlugin

The sfTaskExtraPlugin has a nifty task bundled with it that lets you kick off your plugin creation by running a simple command. Let's start by installing that:

$ php symfony plugin:install sfTaskExtraPlugin 

Generating the Task

We can now generate the plugin by running the following command:

$ php symfony generate:plugin jsHelloWorldPlugin 

Writing the Task

Next we'll create a task. As you can see in the symfony task documentation, you can create a task using generate:task. We'll call our task helloWorld, so we'll run this command:

$ php symfony generate:task helloWorld

This generates a task at lib/task/helloWorldTask.class.php. This isn't ultimately where we'll want it but we'll leave it there for now while we get the task working. Since all we need to do is print "Hello, world!", let's clear the contents of the execute() method and put our own code in:

 protected function execute($arguments = array(), $options = array()) {   echo 'Hello, world!'."\n"; }

Let's see what happens when we try to run the task:

 $ php symfony helloWorld Hello, world!

Success! Now that we have that task working, let's move it from our project and into our plugin. First we'll have to create a lib/task directory in our plugin folder:
$ mkdir plugins/jsHelloWorldPlugin/lib/task
Now let's move the task:
$ mv lib/task/helloWorldTask.class.php plugins/jsHelloWorldPlugin/lib/task/
If you try to run the task again, you'll notice that it won't work. That's okay. We have to install the plugin properly in order for the task to work again.

Getting the Plugin Ready For Installation

There are certain things that need to (or at least should) be in place in order for people to be able to install our plugin. First let's make a README file at jsHelloWorldPlugin/README

jsHelloWorldPlugin =================  This plugin prints "Hello, World!" to the screen.  Installation ------------    * Install the plugin          $ symfony plugin:install jsHelloWorldPlugin.tgz    * Clear the cache          $ symfony cache:clear  Documentation -------------  Once the plugin is installed, run the following command:    $ symfony helloWorld

Next we'll create a license file at plugins/jsHelloWorldPlugin/LICENSE:

Copyright (c) 2010 Jason Swett  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Now we'll take the important step of creating a package.xml file atplugins/jsHelloWorldPlugin/package.xml. You can see what a package file is supposed to look likehere. Ours can look like this:

 <?xml version="1.0" encoding="UTF-8"?> <package packagerversion="1.4.6" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">  <name>jsHelloWorldPlugin</name>  <channel>plugins.symfony-project.org</channel>  <summary>sample plugin</summary>  <description>Just a test plugin</description>  <lead>   <name>Jason Swett</name>   <user>jasonswett</user>   <email>jason.swett@gmail.com</email>   <active>yes</active>  </lead>  <date>2010-09-08</date>  <time>15:54:35</time>  <version>   <release>1.0.0</release>   <api>1.0.0</api>  </version>  <stability>   <release>stable</release>   <api>stable</api>  </stability>  <license uri="http://www.symfony-project.org/license">MIT license</license>  <notes>-</notes>  <contents>   <dir name="/">    <file role="data" name="README" />    <file role="data" name="LICENSE" />    <dir name="lib">     <dir name="task">      <!-- tasks -->      <file role="data" name="helloWorldTask.class.php" />     </dir>    </dir>   </dir>  </contents>  <dependencies>   <required>    <php>     <min>5.1.0</min>    </php>    <pearinstaller>     <min>1.4.1</min>    </pearinstaller>    <package>     <name>symfony</name>     <channel>pear.symfony-project.com</channel>     <min>1.4.0</min>    </package>   </required>  </dependencies>  <phprelease />  <changelog /> </package>

Now we're ready to wrap everything up into a nice package. Rename your plugin directory to include the version name:

 $ mv plugins/jsHelloWorldPlugin/ jsHelloWorldPlugin-1.0.0

Now compress the plugin folder into a .tgz file:

 $ tar cvzf jsHelloWorldPlugin-1.0.0.tgz jsHelloWorldPlugin-1.0.0/

Installing the Plugin

Now you can install the plugin like this:
$ php symfony plugin:install jsHelloWorldPlugin-1.0.0.tgz

Testing the Plugin

To test your plugin, simply run your helloWorld task like you did before:
$ php symfony helloWorld
Congratulations! You just wrote your first plugin.

No comments: