Application Lego: Build a Wiki with Symfony in 20 Minutes

This tutorial shows how fast you can develop with symfony. It showcases symfony's admin generator capabilities, and makes great use of a couple of symfony plugins.

Installation

Start with an empty symfony sandbox. Then use the symfony command line to install two plugins from the symfony plugins repository. Open a terminal, go to the sf_sandbox repository and type:

> php symfony plugin-install http://plugins.symfony-project.com/sfPropelVersionableBehaviorPlugin
> php symfony plugin-install http://plugins.symfony-project.com/sfAdvancedAdminGeneratorPlugin

The first plugin requires one change in the default symfony configuration, since it is a behavior. A behavior is a model modification bringing additional capabilities to the model classes for which it is enabled. To activate behaviors in your symfony project, you need to change the last line of the config/propel.ini to:

propel.builder.addBehaviors = true

Model initialization

A wiki is basically a tool to manage articles and to keep every modification of these articles. This means that you need at least an article table to store the information of the articles. So define the following structure in the config/schema.yml file:

propel:
  article:
    id:         ~
    title:      varchar(255)
    body:       longvarchar
    version:    integer
    updated_at: ~

From this description, symfony can both initialize a database and an object model to map the table to an object-oriented API. You just need to type in the command line:

> php symfony propel-build-all

The Article model should be versionable, so that every modification to it creates a new version. Thanks to the plugin you just installed, this is as easy as adding this line at the end of the lib/model/Article.php model file:

sfPropelBehavior::add('Article', array('versionable'));

One last thing: clear the cache. Don't forget to do this every time you add a class

> php symfony clear-cache

Check that nothing is broken by browsing to the application's default page:

http://localhost/sf_sandbox/web/frontend_dev.php

Article edition interface

Use the command line to create a wiki module based on the Article model with the admin generator:

> php symfony propel-init-admin frontend wiki Article

Play with the apps/frontend/modules/wiki/config/generator.yml file until you get something satisfactory, or paste the following configuration:

 generator:
   class:              sfAdvancedAdminGenerator
   param:
     model_class:      Article
     theme:            default

     list:
       title:        List of Articles
       sort:         title
       click_action: show
       display:      [=title, updated_at]
       filters:      [title, updated_at]
       object_actions:
         _show:      { name: View Article }
         _edit:      { name: Edit Article }
     show:
       actions:
         _list:      { name: Back to the list }
         _edit:      { name: Edit Article }
     edit:
       fields:
         updated_at: { type: plain }
         version:    { type: plain }
         body:       { params: size=80x15 }
       actions:
         _save:      { name: Save modifications }
         _show:      { name: View Article }
         _list:      { name: Back to the list }
         _delete:    { name: Delete Article }

The results should be visible at the following URL. Go on, play with the interface, enter a few articles, try to edit one a few times - you will see that the version number automatically increases in the show view. That's one of the benefits offered by the sfPropelVersionableBehaviorPlugin.

http://localhost/sf_sandbox/web/frontend_dev.php/wiki

Note that the above file uses an extension for the symfony Admin Generator called sfAdvancedAdminGenerator - that's the purpose of the second plugin you installed. It offers a "show" view and separates the "create" view from the "edit" one. Apart from that, the syntax is a simple illustration of the Admin Generator capabilities - refer to the 'Admin Generator' Chapter in the symfony book for more information.

History of modifications on an article

A wiki keeps every revision of an article, and offers a list of past revisions. So you will add a history action to the wiki module. Edit the apps/frontend/modules/wiki/actions/actions.class.php class and add the following method:

public function executeHistory()
{
  $this->article = $this->getArticleOrCreate();
}


This method just reuses an existing method created by the Admin Generator. This getArticleOrCreate returns an Article object based on the id request parameter. If you are curious about how this method works, you will find the generated actions class in cache/frontend/dev/modules/autoWiki/actions/actions.class.php.

Now, to the history template. Create a apps/frontend/modules/wiki/templates/historySuccess.php file with the following content:

<?php use_stylesheet('/sf/sf_admin/css/main') ?>

<div id="sf_admin_container">
  <h1><?php echo sprintf('History of "%s" modifications', $article->getTitle()) ?></h1>
  <div id="sf_admin_content">

    <?php foreach ($article->getAllResourceVersions('desc') as $resourceVersion): ?>
    <div class="form-row">
      <?php echo sprintf("'%s', Version %d, updated on %s (%s)\n",
        link_to($resourceVersion->getTitle(), 'wiki/show?id='.$article->getId().'&version='.$resourceVersion->getNumber()),
        $resourceVersion->getNumber(),
        $resourceVersion->getCreatedAt(),
        $resourceVersion->getComment()
      ) ?>
    </div>
    <?php endforeach; ?>

    <ul class="sf_admin_actions">
      <li><?php echo button_to('Show Article', 'wiki/show?id='.$article->getId(), 'class=sf_admin_action_show') ?></li>
      <li><?php echo button_to('Edit Article', 'wiki/edit?id='.$article->getId(), 'class=sf_admin_action_edit') ?></li>
    </ul>
  </div>
</div>


The getAllResourceVersions() method is a model extension provided by the sfPropelVersionableBehaviorPlugin, which returns an array of ResourceVersion objects, each giving details about a particular revision.

To check the resulting HTML for the new action and template, just browse to:

http://localhost/sf_sandbox/web/frontend_dev.php/wiki/history/id/1

You should see the history of modifications of the article of id 1. Each revisions provides a link to the show view. For this link to display the correct version, you need to override one method of the actions class. Basically, if a version parameter is present in the request, this method forces the article to this version.

protected function getArticleOrCreate($id = 'id')
{
  $article = parent::getArticleOrCreate($id);
  if($this->getRequest()->hasParameter('version'))
  {
    $article->toVersion($this->getRequest()->getParameter('version'));
  }

  return $article;
}


That's about all. Oh, yes, you can plug the history page into your other generator's pages by modifying the generator.yml. For both the show and the edit view, add the following entry under the actions: key:

_history:   { name: History }

Conclusion

In about 50 lines and 20 minutes, you have a working wiki, with search, sorting and pagination capabilities. You can review (and reuse) any older revision of an article. Of course, this is not enough to publish your new app as a shiny open-source project - you should at least add user authentication through sfGuardPlugin and article formatting through markdown. Maybe you will need to write an additional 20 lines of code for that.

But that illustrates how to build up an application with symfony. The framework and the plugins provide the features, you just assemble them and glue them together according to your needs. Just like you used to assemble Legos to create a fire station. Since there are very few lines of code, the application is easy to review, maintain, and run.

6 Comments so far

  1. Hugo on April 7th, 2008

    Nice tutorial François. Thanks a lot ;)

  2. forkmantis on April 7th, 2008

    Excellent. I’ve been meaning to install the sfPropelVersionableBehaviorPlugin on one of my production sites. I’ll go through this tutorial first and give it a test drive.

  3. Cristy on April 7th, 2008

    Built the wiki in less than 20 minutes using Symfony 1.0 and mysql. Any hints on getting the wiki working with Symfony 1.1? For example, what is the URL to download sfPropelVersionableBehaviorPlugin for Symfony 1.1?

  4. manuel de vicente on April 9th, 2008

    me ha encantado el tutorial

  5. raúl on April 9th, 2008

    Oh, That’s fine. Thank you for this practical tutorial.

  6. catchamonkey on April 30th, 2008

    Good to see another tutorial based around something a little different. :D

Leave a reply