Symfony Plug-In of the week: sfPJS

In the pursuit for the most cryptic plug-in name, we recently released a plug-in called sfPJSPlugin. PJS stands for 'PHP JavaScript', and the plug-in offers a new way to include dynamically-generated JavaScript files. For those familiar with the RJS templates in RoR, this is kind of similar, except the code necessary to deal with it is really minimal.

Including a dynamic JavaScript file is great to create unobtrusive behaviours. The main template code contains no JavaScript, all the behaviours are added dynamically in the included file. The same way as you separate content from style with CSS, you separate content from behaviours with JS. The news is, with sfPJS, if the JavaScript behaviours are database or session-dependent, you can include them in a similar way as usial JavaScript files - in one line.

For instance, let's imagine a page displaying "hello, world!" where you would like the text to become a link to an alert box showing the current server time, but only for users with JavaScript support. With sfPJS, this is how you would do it:

<span id="hello">Hello, World!</span>

<?php use_helper('PJS') ?>
<?php use_pjs('foo/bar') ?>

The use_pjs() helper will call a foo/bar action and render it by using a foo/templates/barSuccess.pjs template. Note the .pjs suffix instead of the usual .php. The .php templates are traditionally used to render HTML code, the .pjs templates are used to render JavaScript code.

So the foo/bar action is a regular symfony action and can access the request, response and other objects in the same way the others action do:

// In modules/foo/actions/actions.class.php
class fooActions extends sfActions
  public function executeBar()
    // Do smart things, like for instance
    $this->time = time();

And the barSuccess.pjs is seen by the client as JavaScript file, except it is executed by the server and has access to all the symfony helpers and the variables defined in the action.

// In modules/foo/templates/barSuccess.pjs
<?php use_helper('Javascript') ?>
document.getElementById('hello').innerHTML = "<?php echo link_to_function('Hello, World!', 'alert(\''.$time.'\')') ?>";

You could say that there is nothing revolutionary in this, but the use_ujs() helper does more than just disabling the layout decoration for the template and setting the response mime-type to application/x-javascript. By internally forwarding to a special action, the helper allows for fine caching and is much easier to use than the usual use_javascript() helper.

You can read more about this plug-in in its wiki page.

We will try to speak regularly about interesting plug-ins, so make sure you come back to discover the wonderful add-ons that can make your symfony projects easier to code and funnier to develop.


What are the main differences between this plugin and this one:

Also, from the intro it seems like javascript is not mix with HTML, does that means that the tag use_pjs is converted into a &lt;script src=""&gt;&lt;/script&gt; and in the &lt;head&gt; section?

sfUJSPlugin uses sfPJSPlugin (the one described in this post) to generate dynamic JavaScript files. But it does more than that, and offers a handy way to define behaviours with helpers from directly within the main template, avoiding constant switching between the main page and the behaviours page.

Or, to put it in a different way, it allows for really unobtrusive scripting with an obtrusive (yet very practical) approach.

And yes, the use_pjs() call inserts a &lt;script&gt; tag directly in the page header, bearing a reference to a symfony action.

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.