Features & Approach
Demo & Implementations
Native PHP Templating Engine
We have studied a lot of different templating engines. Our choice is clear for now. We won't be explaining all pro's and contra's of this choice. Curious reader can get main points at this article or this one. And this simple benchmark too.
Definitely PHP syntax is fine enough for templating work. But it has one big disadvantage. Actually any other common purpose templating mechanism does have it too. Here we tell you how we solved this problem.
Main Problem of Native PHP Templates (Smarty Either)
All templates look pretty in basic functionality such as variable placing, loops, conditional blocks. But there are some tasks where most of templates look ugly (if able to work out at all). Let us illustrate it in rather rare but figurative sample -- building a tree structure. This sample may be considered as a kind Acid test for templates.
Suppose your template need to draw a tree out of given array. There is given data:
The data should come out in the following format:
Smarty and many other templates simply can't produce such output using only their standard syntax. Smarty has to employ PHP code to do so what is very ugly from the first point. You may say "you have picked native PHP anywhay, what else do you need?". Well it's true that with native PHP templating engine we can ommit any third party. Yet we are not satisfied.
One of the main point of template is that it consists of almost pure HTML code with very modest and clean foreign embeddings. To produce tree output we have to write quite a chunck of recursive code. After that our template will be even not close to clean look. What we expecting from such template is something like ("curly" speaking):
That is what we call "clean and intuitive template". Seems there is no one common application engine exists which can work out such recursive template. There are few templates which are able to work with blocks recursively. But for some reasons their templates are not intuitive. For instance in one we found BRANCH block need to be oddly placed outside of TREE block.
To make things shorter we are proud to announce that we managed to emplemented "rather clean" way for such "Acid" test template with native PHP. Tree building template sample will look as follows:
This solution made in conjuction with another task explaned below.
Shameful Secret of MVC (Everybody Was Afriad to Point Out)
Whole idea of MVC paradigm is clear in theory. Problem begins when it come to practice. Assume programmer has retrieved data from the database, filtered, sorted out and threw it to the web designer to lay it out. It will be fine if the set of data is very simple. What happens if designer need actually write bunch of code to output that data properly. Didn't you forget that it was designer and he not suppose to know recursies and other complex coding stuff.
The one sample we have touched in the chapter above. Tree output may look very abstract and academical to encounter in real life. Here is another sample based on absolutely real case:
This is simplified rate sheet of one of the hotels in a travel company. As you see there is no any recursive structures. But whole template code to create such layout will be much longer and more complex than in that abstract tree sample above. It doesn't really matter will we use native PHP template or a "curly" one. It will be just big mess of control structures and HTML codes.
We can ask programmer to format data in more "output friendly" way. Embed there bits of HTML codes to make designer easy to build layout. Hey, stop! Are we talking about "model" doing "view" things?. Are we still under MVC paradigm in this case?
We came to paradox -- there are certain tasks which are not belong to "model" and hardly can be part of "view". Where is the place for them?
That why we see solution in emplementing additional sub-layer for MVC. We call it "Helper" layer and MVC becomes MHVC or M[H]VC. Entire task of Helper layer is to take unnecessary load out from View. Helper may be abstract and serve any project (as in the tree sample). Helper also may be task specific to serve only particular project.
If Model provides complex data in normalized format, Helper re-format data in simplier structures aware of the way it will be output. Hence it still leaves decoration issues to the View layer. For instance in our hotel sample Model provides data in abstract tree like format: Wing→Room-type→Room-occupancy→Rate→Period. Helper will be aware of HTML table structure and reformat it in flat array row by row, providing additional information how many cells or rows to span, etc. This will allow to use only one loop block insead of several nested ones.
Helper allowed to generate full or parts of HTML tags which doesn't influence decoration look but only logical part of output. For instance we consider COLSPAN as the logical property of the cell while STYLE is graphical. If we take as sample HTML form then Helper could be useful here too. Such properties as NAME, VALUE, CHECKED of the INPUT tag are considered logical and may be taken off from the View layer. Otherwise INPUT tag will be overloaded with heavy routine logic.
All in all Helper layer allows to create elegant, easy readable and manageble templates in speedy manner. There will be no thoughts and doubts where to put "questionable" code which merely doesn't belong to Veiw neither Model.
In Phella we have Modules (PHP programs) which reperesents "model" and Templates (HTML layouts) -- "view". Helpers are overlapping area of these two sets. They are technically Modules (programs) but logically belong to "view".
Why Designers Hate Forms?
There is another problem of templates exists -- forms. Forms are not so friendly with templates. Let us imagine First Scenario:
What kind of mood you expect from designer when he need to layout this kind of form? All those "name", "value", "checked", etc. attributes are important but not for him. And exactly those attributes and technical loops (or block) make form a big mess. Technical codes makes tags so long. But initially we agreed that remplates ("view") is the designer's department. What all those codes do there?
To answer this question there is Second Scenario:
That is mu-u-uch better! Don't you agree? There are still some issues with <LABEL> tags but not a big loss. But wait a moment, where designer put his bells, whistles and styles? May be this way:
Well, it will work but... We here have two important rules - don't wear dirty clothing and don't put HTML code in between quotes. Sorry, this scenario wont work for us.
There is another scenario which we don't want to discuss at all - large form generators with many things like data validators, etc. Our holy cow MVC is against such cancer-like things.
You bet that we already have got our own solution for this problem. Gotcha! Here it is:
Inspite that it looks like "abstract" sample it is real working one. We do extend all "tecnical" attributes and tags in the back-end. Even <LABEL> attributes if this tag take place. And we still do not pre-parse whole document for that like we do not pre-parse anything in Phella. Just on PHP pass. Can somebody point us any other form templating engine which satisfy all these conditions:
Here some more flavours of our form templating mechanism:
Suppose we have this array set up somewhere earlier:
<SELECT> with initial <OPTION>
<SELECT> with <OPTION> as a specimen to extend
Group of <RADIO>'s with fixed elements
Group of <RADIO>'s with dynamic elements (note that <LABEL> is also automaticly extended)
Group of <SELECT>'s to work with dates (note that list of years generated automaticly too)
Error higliting mechanism
Markup vs Markdown
We chose Markdown as the preffered text formating language for Phella CMS. Why so? There is one grand reason dominating any other. You can't give to a copywriter unlimited control over layout. The problem is not in the security, injections, ets. We even don't consider this issue. Copywriter is always a trusted person and there is no reason to apply security measures against him. What we need to protect is the structure of the copy and ability to apply new design when necessary.
It means that you have to define as many styles as you need. Let copywriter to feel free within this predefined set of styles. When it is shortage of a different styles then define another one. But never ever allow such things like [color=red]...[/color].
Applying this major importance point we cleary see that Markdown is the best choice. Good thing that it is much more simple and "clean" comparing to HTML or BBcode especially in often used mark ups such as heading and emphasizing.
Well for the people who ready to stand all the oddities and mis-stylings we do have WYSIWYG editor ready to go. Sorry but we didn't reserve BBcode module. Fans of this strange thing may add their own modules when needed.
Additionally we extended Markdown syntax sligtly in order to get it more handy. Basically there are two additions. Firstly there may be not enough of all different kinds of blocks and spans to produce layout you wish. We have added "class" property as the modificator to switch different design for the same tag. For instance you need more than one style of BLOCKQUOTE's then you can define additional with explicitly named style. This sample shows some ways to apply alterantive styles to the most used mark up.
##.[class] Heading ## Heading =======.[class] .[class]Paragraph text here with **.[class]strong** text. .[class] Another paragraph text here with [.[class]link](url) text and special horisontal rule below. -------------.[special] >.[classname] > Quote > block > here
Second modification concerns link tags in order to apply notation used in internal links across whole Phella project. It means that copywriter don't need to write hard coded URL addresses but shorter internal references. Those references later will be resolved to proper URL's depending on configuration of the project (think mod_rewrite for instance).
Depending on configuration may be resolved to:
Unfortunately still there is none good and universal internationalisation solution for whatever programming language. More or less standard approach with gettext works only partially when we need to translate interface, that is just set of short phrases (prompts or error messages). In fact multilanguage goes beyond that. What if we need to present and synchronyze big chunks of text (say articles) in several languages? Standard gettext way won't work for that at all.
In order to solve the problem we could come out with nothing else but two independent solutions. One is full analogue to gettext but without going that deep into the system level. Usage of gettext demands access to some system resources which may be difficult to obtain for different reasons. We offer basically the same thing but in custom PHP level. Whenever you change translation tables you don't have to restart Apache or such.
The translation table can be one for each langauge for the whole project. But as soon as you notice that loading whole table (while bigger part of it is not necessary for certain request) brings project to overhead you may set Phella to automatic splitting of the table. When certain request recieved Phella may automatically collect only necessary entries from the main table and compile them to a separate sub-table. Since that this smaller sub-table will be loaded to serve translation. Obviuosly it takes more storage space on the disk, but these days storage is much less critical than response speed.
Whenever you need to update translations you work only with the main table and delete those sub-tables which need to be touched. If you doubt which ones just delete all of them.
Along with that Phella offers another approach for bigger pieces of text. In fact it can be used not only for multilanguage but for any kind of varying of the contents, even multidimentionally. Say you have request named "home". In standard situation it should pick up block named "home". But if you set up language modifier such as "home-<lang>" then request "home" will employ block "home-en" or "home-de", etc. depends on current language environment. All defaults and missings are properly handled.
There may be several modifiers at once such as "home-<country>-<lang>". All modifiers can be changed independently from each other.
These two multilingual solutions ("short" and "long") can be combined in one project and even in one request.