Creating a Textile Decorator Class

December 22, 2009

in PHP

I’m lazy when it comes to writing valid HTML. I know it’s the right thing to do, but I’ve developed some bad habits over the years. There are too many times when I forget quotes, alt tags, and ending tags. So I’ve decided to outsource my HTML generation to a machine: Textile.

Textile is a “human web text generator”. I like Textile because I can use simple formatting cues to generate any HTML you want. A simple example would be,

p. This is a paragraph. "A link to a URL":http://someurl

Textile will turn that text into this HTML:

<p>This is a paragraph. <a href="http://someurl">A link to a <spanclass="caps">URL</span></a></p>

In my CCSF courses I’ve developed a small PHP framework that I use as a teaching tool for my advanced PHP course. I call it MojoMVC. MojoMVC generates output of any kind by employing Decorator classes to format the output. The default format is HTML, but Decorators can be of any kind, including XML, PDF, images, and so on. All you have to do is write the class for the format you want. I created a HTMLDecorator class to have Textile ease my HTML woes.

MojoMVC Overview:

  1. MojoMVC is a conventional MVC framework that receives a request for the URL http://you.com/cs130a/syllabus.
  2. Controller classes are mapped to URLs.
  3. Which means, there is a cs130aController class and a syllabus page to be displayed.
  4. Every controller class has a render method defined in the parent class, ApplicationController.
  5. Every render method uses a Decorator class to format output.

The render in ApplicationController looks like this:

 1  class ApplicationController extends Base {
 2      // snip //
 3      function render() {
 4         // Default is HTMLDecorator
 5         $klass = $this->as.'Decorator';
 6         // Decorators all have a render()
 7         $decorator = new $klass;
 8         // Pass the current instance to the decorator for rendering.
 9         $decorator->render($this) ;
10         exit;
11      }
12  } 

By the way, one of PHP’s Good Parts in visible in this method—the easy implementation of polymorphism in lines 5, 7, and 9.

After we define the render method, the next step is to create a Decorator that will take the current instance and render its output using Textile. Here’s how it works.

The MojoMVC HTMLDecorator

 1 class HTMLDecorator
 2 {
 3
 4     function render($klass)
 5     {   // $klass is instance of current controller
 6         $textile = new Textile; // new Textile object
 7         // Check to make sure we have the requested object
 8         if (file_exists(VIEWS.$klass->r->controller.'/'.$klass->r->action.'.html'))
 9         {
10             // If so, run the method requested
11             if (method_exists($klass->r->controller.'Controller', $klass->r->action))
12             {
13                 $action = $klass->r->action;
14                 $klass->$action();
15             }
16             // Buffer output so we can pass it to Textile
17             ob_start();
18             include (VIEWS.$klass->r->controller.'/'.$klass->r->action.'.html');
19             // Textileize the HTML
20             $klass->out = $textile->textileThis(ob_get_clean());
21         } else
22         {
23             include (VIEWS.$klass->r->controller.'/'.$klass->r->error404.'.html');
24         }
25         // Include the layout HTML file that displays the requested page.
26         if (file_exists(LAYOUTS.$klass->r->controller.'.html'))
27         {
28             include LAYOUTS.$klass->r->controller.'.html';
29         } elseif (file_exists(LAYOUTS.'default.html'))
30         {
31             include LAYOUTS.'default.html';
32         } else
33         {
34             print $klass->out;
35         }
36     }
37 }

Most of this code is all about error checking. Textileizing is a matter of saving the output (using ob_start and ob_get_clean), loading Textile, creating an instance, and running the text through the textileThis method.

To learn more about Textile, check out the Textile home page. Textile has been ported to Ruby, where it is known as RedCloth.

For an easy-to-digest introduction to the Decorator design pattern, check out the Head First Design Patterns sample chapter.

Happy hacking…

Share and Bookmark
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Blogplay
  • FriendFeed
  • StumbleUpon
  • Tumblr
  • Twitter
  • Add to favorites
  • LinkedIn
  • Posterous
  • Reddit
  • Suggest to Techmeme via Twitter

Leave a Comment

Previous post:

Next post: