Making a symfony plug-in for visual theme and custom errors

I manage a growing number of symfony-based Intranet apps that share a common look-and-feel. I use the same stylesheet and images on them all, and it I am nervous every time I make Yet Another Copy of the same files, knowing that I’m duplicating them and causing trouble for myself.

Also, as I wrote in my post about custom error pages, I have error pages set up for each, and I hate copying them. So I have invested some time into building a plugin containing the visual assets and the customized error pages, so that it’s easier to keep them uniform across all the apps I work on, and so that it will be that much quicker to build new projects.

I don’t think anyone outside my company will want my plug-in, but these instructions will hopefully be useful for anyone who wants to do the same thing.

These instructions are for symfony 1.1 but they should apply equally to 1.0 and 1.2.

Plugin organization

Here are the files and directories in my plugin:

plugins/myThemePlugin/
  config/
    view.yml
  modules/
    default/
      config/
        view.yml
      templates/
        disabledSuccess.php
        error404Success.php
  README
  web/
    css/
      mystyles.css
      myerrors.css
      mymain.css
    errors/
      error500.php
      unavailable.php
    images/
      my_swoop.jpg
      bg_sfTAlert.jpg
      bg_sfTLock.jpg
      bg_sfTMessage.jpg
      indicator.gif
      tall_gradient.jpg

Using svn:externals to install the plugin in each symfony project

I only want one copy of this thing, with version control, so I use svn:externals (for my other plugins too ).

$ svn propget svn:externals plugins
myThemePlugin/        https://mysvnserver.com/svn/web/myThemePlugin
sfGuardPlugin/        http://svn.symfony-project.com/plugins/sfGuardPlugin/branches/1.1/
$ svn up

Publishing the assets

The chapter on plugins in the The Definitive Guide to symfony explains:

Web assets (images, scripts, style sheets, etc.) are made available to the server. When you install a plug-in via the command line, symfony creates a symlink to the project web/ directory if the system allows it, or copies the content of the module web/ directory into the project one. If the plug-in is installed from an archive or a version control repository, you have to copy the plug-in web/ directory by hand (as the README bundled with the plug-in should mention).

As I showed above, I prefer to use svn:externals for my plugins, so this is a bit of a problem for me. Also, I develop on Windows (with XAMPP and Cygwin), so the more elegant symlink solution is not an option. Symfony 1.2 has a task called plugin:publish_assets that makes the copies, but that messes up my version control strategy. SO: I am going to use svn:externals to get the web assets from my plugin too.

$ svn propset svn:externals "myThemePlugin  https://my_svn_server/svn/web/myThemePlugin/web/" web
$ svn propget svn:externals web
    myThemePlugin  https://my_svn_server/svn/web/myThemePlugin/web/
$ svn up

This lets me keep the plugin in its own repository. You could get a similar effect by just checking out the files, but it would clutter up the SVN for your main project.

The end result: I have one copy of the web assets in the SVN repository, but they’re checked out twice into each project (once under plugins/myThemePlugin/web and once under web/myThemePlugin).

view.yml files

Now the overall view.yml file in plugins/myThemePlugin/config/ sets stylesheets for my whole project:

default:
  stylesheets:    
    - /myThemePlugin/css/main: { position: last }
    - /myThemePlugin/css/bannerhealth: {position: last}
    - %SF_ADMIN_WEB_DIR%/css/main
    - %SF_CALENDAR_WEB_DIR%/skins/aqua/theme

And I have another one to apply some additional stylesheets to my error pages:

error404Success:
  metas:
    title:        404 Not Found
  stylesheets: 
    - /sf/sf_default/css/screen.css
    - /sf/sf_default/css/ie.css
    - /myThemePlugin/css/errors: {position: last}
 
disabledSuccess:
  metas:
    title:        Temporarily Unavailable
  stylesheets: 
    - /sf/sf_default/css/screen.css
    - /sf/sf_default/css/ie.css
    - /myThemePlugin/css/errors: {position: last}

relative image paths in stylesheets and error pages

I use relative paths in my stylesheets (served out of myprojecturl/myThemePlugin/css/) so they can find the images (myprojecturl/myThemePlugin/images/):

background-image: url(../images/tall_gradient.jpg);

I’d do the same if my error templates (like plugins/myThemePlugin/modules/default/templates/error404Success.php) used images, but they don’t.

The pages in plugins/myThemePlugin/web/errors (which are installed via svn:externals now in web/myThemePlugin/errors) are used when things are so broken symfony can’t build template pages, so they have full HTML structure, including full stylesheet tags:

<?php $path = '..'; ?>
 
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $path ?>/../sf/sf_default/css/screen.css" />
<!--[if lt IE 7.]>
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $path ?>/../sf/sf_default/css/ie.css" />
<![endif]-->
 
 
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $path ?>/css/main.css" />
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $path ?>/css/bannerhealth.css" />
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $path ?>/css/errors.css" />

Apache error page configuration

Finally, I tell Apache to use my customized error pages for errors in this project.

  <Directory "/path/to/myproject/web">
        ErrorDocument 404 /myproject/default/error404
	ErrorDocument 500 /myproject/bhThemePlugin/errors/error500.php
  </Directory>

There we go! Now I have a lot less to do each time I make a new app; all the pretty stuff is in my plugin, and there aren’t any surprisingly brown symfony pages to throw off any users.

What do you think? Any errors or ommissions or problems?