Separation of Design and Business Logic – How thumbnailing usually is contradicting
Yesterday I announced the first stable release of sfImageTransformExtraPlugin. I mentioned it could help you separating design from logic.
Today I want to explain my reasoning and why I think it is important especially for long living projects.
Most of you will use symfony or another MVC pattern framework so I assume you all know about the idea behind the MVC pattern.
“The pattern isolates “domain logic” (the application logic for the user) from input and presentation (GUI), permitting independent development, testing and maintenance of each.” (source wikipedia)
For websites the presentation side of things has almost certainly have to do with templates in which you find a lot of HTML and some little PHP that mainly outputs dynamic contents or performs some sort of presentation specific logic.
Images could be considered content thus belonging to the model part of the pattern. But the presentation of an image is different. Only in some cases the image as uploaded is shown to the user, unmodified, un-resized. Most of the time those images show up in different formats such as icons, images on an article teaser, images on the top of an article, images in a gallery, images in a gallery detail view, etc..
You see all these different formats (refered to as thumbnails) are the presentation part of an image.
Implementing an MVC pattern promises a clean separation of Design, Logic and Content. One of the benefits being that the Design part can be changed or replaced without affecting the Logic or the Content.
But where does the creation of thumbnails happen? Where do you define the presentation of your images?
In most cases you will have produced some code that uses an API for image manipulation such as GD or ImageMagick or higher level abstractions like sfThumbnailsPlugin or sfImageTransformPlugin. And this code you will probably have implemented in your business logic.
You did this because of two reasons:
- You needed an event that triggers the thumbnail creation
- You need access to the content, the original image
Eventually you will find that the part of your business logic where the just uploaded image suits both of these requirements. So you add the image manipulation at that point.
The problem is just that you probably forgot about a third requirement.
- You need to know about the format to be generated
Effectively you bundled a concern of your presentation to your controller!
Moreover you are no longer able to change the presentation layer without changing the business logic as well. Imagine that you want to change the layout of you website and some if not all of the image formats used have slightly changed. You would have to go to every point in your code where images are manipulated to change it accordingly. Not at all what the MVC promised.
Now looking at the requirements again we can recognise something familiar.
- You needed an event that triggers the thumbnail creation, read: some code to execute the generation
- You need access to the content, the original image, read: you need the content to generate from
- You need to know about the format to be generated, read: you need a presentation to generate to
So these requirements seem to deserve their own MVC pattern it seems, right?
Yes it does. So why not use the one we already know: our framework?
We could wrap the implementation of all the above requirements to its own request where the response is a presentation of the original image a.k.a. a thumbnail.
Now we know that it is easy to set up a route to a symfony controller that generates an image. The first requirement is easily done.
But we still need the original image and some information what exactly to do with it (generate an icon, a fullscreen format, a teaser image, ..?). In a dedicated request though we have no information about when the request was triggered and in what context.
So we need to pass some information with the request that helps us to identify the original image source as well as the desired format.
sfImageTransformExtraPlugin does just that.
It uses a (fully configurable) URL to get a format identifier – which is a descriptive name such as icon, article_top, gallery_thumb, whatever, .. – and reads the format settings of it from the configuration. You can configure the most complex manipulation but identify it only by a short, descriptive, even SEO meaningful name that you include in the thumbnails URL.
The plugin does also offer several source implementation that all read the information they need to access the image source from the thumbnail URL. This is sometimes an ID, sometimes a filename. You can even extend the plugin by writing custom image source classes that read all the parameters you need to provide the appropriate source image.
In your templates then you only have to create the right
// for example for an image stored on a doctrine model 'icon', 'sf_subject' => $object, 'slug' => 'my-seo-friendly-image-name')), array(..)); ?> // possible result: // -> http://yourhost.com/thumbnails/icon/my-seo-friendly-image-name-123.jpg
Now if you want to change your websites design again you will have to change the templates (of course) and the format configuration as necessary and then you’re done. No change of code at all!