[RFC] Template and theme DSL
#491

Assignees

Labels

Projects

Milestone

7 participants

Overview

This RFC is to discuss the details of how the templating language we use should look. The decision has already been made to use Twig but there a number of implementation details we need to consider.

Who should care

This ticket directly affects module and theme developers, as well as core developers. Once we have a clear roadmap of what to do, we can make a lot of progress with a script to do a lot of the refactoring work in the template.

Syntax

For brevity, Twig has two syntax forms tags, e.g. {% set name=foo %} and variable/functions e.g. {{ title }}. Variables, unlike smarty do not begin with $.

New DSL

Twig is much more powerful than smarty and even supports the creation of macros, which are like smarty tags created on the fly, inside the template. For this reason we can probably scale down a lot of the smarty templating tags we've been using.

One nice improvement with Twig is the ability to use assigned PHP objects and arrays in a template (smarty was very limited in what it allows).

Template / theme communication

Module controllers return some rendered text. This is assigned to a variable and then assigned to maincontent in a theme template. As such, the theme, and the module rendered content are two quite distinct silos.

One of the main concerns is how to communicate between the module and the theme. For example, to set meta tags, or page title in the main theme and to communicate which javascript and css files to include. In 1.x we already use page-variables and some globals. I am wondering if we can do better here. We need to cover

Javascript

CSS

Meta tags

Title (which is not a meta tag)

?

What is missing from this list? Is it generic enough if we are considering non-HTML themes? Do we prefer separate array objects or just one for global variable and use naming conventions with one pagevar object/array e.g.meta.description, title. I think there is a strong case to separate out javascript and CSS into their own thing and not be part of the pagevars per se.

Globals

This follows on the previous topic. What should be made globally available to all templates. For example, in the theme, there are smarty variables like themename, modulename, func etc. What should be made available and can we made work to simplify this (possibly with an API, or encaps in an array/object of meta data for the theme/template).

In 2.0 we'll have the Request object available so that will encapsulate all the request data including the controller (mod,func,type in old zikula). This should definitely be made available to all themes/templates.

Magic function method

It is possible to register all PHP functions as Twig functions using callbacks but there are probably some disadvantages here.

Symfony

There are a number of things we also get with the Symfony2 framework, for free. For example, we can generate URLs using the routing information, e.g. <a href="{{ path('_welcome') }}">Home</a>.

We also can address other controllers simple with {% render "FooModule:Article:recentArticles" with {'max': 3} %}

Other points

What has been missed. What things are lacking in the way we currently do things in Zikula 1.3? What could be made simpler?

I like the tag notation for things like pagevars. The object based notation seems too much writing.

The request object is certainly useful.

Not that important maybe, but potentially interesting is rethinking the module controller and api access. Something like a factory could be convenient. So instead of {mod(api)func modname='MyMod' type='admin' func='doSomething'} we could have something like {foo = modApi('MyMod', 'admin'}{foo->doSomething();}...{foo->somethingElse();}.

Not directly related to the inside-template-view, but handling of cache ids is very tedious in Smarty. Don't know whether there is some kind of auto magic possible in this area. Maybe a convenient facade would be possible which retrieves some arguments like permission information and list of used parameters.

But the tag notation is more explicite and declarative which might be advantageous for (non-technical) template writers.

Beside the meta tags and page variables there is not that much left for the communication between module and theme. One point is certainly that a theme should provide some meta data which is required for things like #447

regarding pagevars, I actually prefer the object notation way better than the tags. it seems more intuitive using get/set.
One question though, how are we going to define the meta.property tag?
this needs an extra parameter eg og:type, og:url. just take a look of the page source of the current page to see what i am talking about.
use {{ pagevars->set('meta.property.og:type', bla bla') }} ?

@drak what are the benefits of separating the javascript and css objects with the rest of the pagevars. apart from the fact that it makes more sense :), is there any other technical benefit?

regarding what is made available to the views, i think we should keep it to the absolute minimum
eg request object, module info, module settings.
I think in 1.3 Zikula_View is quite bloated.
There must be an api however, so that controllers can add other stuff to the object if needed (eg add settings for another module).

Module templates are processed before the theme is processed. But for things like #447 modules will have to be able to fetch information about the theme like which doctype will the final output rendering be? or maybe do we have more than 500px width available for this page?

@Guite - has it ever been, or would there ever a need for a module controller to influence which theme? It would be possible via listeners anyway.

What I would like to do is make _theme available in the request object along with _controller which is already there.

@tfotis - in 1.3 all we are doing is passing object references to templates so it's no bloated per se, from a real memory perspective. However, we could leave some of those things out and let the module developer pass them if he so wanted. However, pagevars for example need to be twig globals. I don't like pagevars very much (as currently implemented) - that's why 1.3 has metatags separated out. But for 2.0 I want to improve the entire concept, if possible so there is a clear "themplate/theme API'. What I specifically dislike about pagevars is that some elements are arrays ad some are key/value pairs. It's ugly and confusing. Then some parts (like js/css) are not even communicated to the theme, but intercepted elsewhere. It seems ugly to me.

@tfotis can you explain a bit more about why you suggest what you do with the meta open graph tags? Theses are just key to value and you could just have some logic in the theme to decide what tags to output. e.g. {% if pagevar['meta.og.type']|default('') %}<meta tag here>{% endif %}

Separating out js/css is just a lot cleaner. Assetic already provides {% javascript %} and {% css %}` tag/blocks although we may need to roll our own or override these to work in some of our script resolution features.

Just FYI: object notation also has another possibility in twig {{ pagevar.set('foo', 'bar') }}
Remember we can use functions in twig too which are notated like {{ strtolower(...) }} so for example, we'll do gettext like this

{{ __('translate this') }}

Making translation notation the same as in PHP code will be easier for developers.

In theory a module controller could define some kind of theme requirement (like a minimum width). But I think in practice most use cases work in the other direction: a module controller being required to use information from the theme.

I'm not saying a module controller should do this or that, but, what
options we want available to developers. Certainly the use of listeners
will enable all manner of things to be modified in the system (as is
currently possible).

I'm not saying a module controller should do this or that, but, what
options we want available to developers. Certainly the use of listeners
will enable all manner of things to be modified in the system (as is
currently possible).
—
Reply to this email directly or view it on GitHub.

you should be using ad IDE, then you dont need to memorise anything
as you have autocomplete.

I use an IDE (phpstrom). But with a call with four elements (this,request,request,get) you need to memorize it. In addition query = get and request = post is not very intuitive at least for me.

With the formutil the code was much easier read for someone new. I dont want to say that a util soultion is the best solution. But a good code should be understandable in a short time with nearly no comments.

The other communication method between module and theme templates are the themeset/getvar plugins, which assigns/retrieves variables directly to/from the Theme instance. I've been using them to customize some theme stuff according the category/screen being rendered at module level.

I guess that the Theme info is barely needed itself by a module, except by
the Client specifications that would be used differently like Axel pointed,
but I use themeset/getvar for completely custom vars, like cliptid,clipcat, etc.