Skip to content
This repository

[RFC] Template and theme DSL #491

Closed
drak opened this Issue September 12, 2012 · 24 comments

8 participants

Drak Axel Guckelsberger Robert Gasch Thanasis Fotis Dominik Mayer phaidon Albert Pérez Monfort Mateo Tibaquirá Palacios
Drak
Owner

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 $.

Tags can also form blocks e.g.

{% for item in navigation %}
    <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor %}

Within the {{ ... }} syntax, one can use functions, variable and modifiers. For example {{ date('+2days', 'Europe/Paris') }}

Take a quick look at the Twig documentationto see more about the syntax.

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.

Here are some ideas

{# pagevars as an object #}
{{ pagevars->set('title', 'page title') }}
{{ pagevars->set('meta.description', 'Page description') }}

Keep pagevars as is and make tags

{% pagevarsadd key=key value=value %}

Keep pagevars as is and make a function

{{ pagevarsadd(key, value) }} 

It's all a matter of style.

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?

Axel Guckelsberger
Collaborator

Some thoughts:

  • 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.
Drak
Owner

@Guite - you can embed controllers much more easily with {% render "FooModule:Article:recentArticles" with {'max': 3} %} for example.

Robert Gasch
Collaborator

+1 for using tags for things like pagevars

Drak
Owner

@Guite - the tags would be more writing

{% pagevarset name='title' value='Some title here' %}

vs

{{ pagevars->set('title', 'Some title here' }}

But there are also wider questions about how we communicate between the module and theme.

Axel Guckelsberger
Collaborator

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

Drak
Owner
Thanasis Fotis
Owner

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).

Axel Guckelsberger
Collaborator

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?

Drak
Owner

@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.

Drak
Owner

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.

Thanasis Fotis
Owner

@drak if these are key to value, then it's ok. I didn't how we could set/get those that's why i mentioned that example.

Axel Guckelsberger
Collaborator

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.

Dominik Mayer
Collaborator

I also think that a module controller should not define a themes width, this would be horrible for responsive theming.

Drak
Owner
Dominik Mayer
Collaborator
phaidon
Collaborator

I like the tag style more. It is more clear and more similar to the old style.

{% pagevarset name='title' value='Some title here' %}

Albert Pérez Monfort
Collaborator

+1 for the tags style

{% pagevarset name='title' value='Some title here' %}

Finally I was able to memorize it :-). I think that we should do things as similar as possible to old methods.

phaidon
Collaborator

Maybe this off topic but it seems that some symfonie2 calls are very bad memorizable. E.g.

$this->request->query->get();
$this->request->request->get();

for get and post calls. This are very fundamental calls.

Drak
Owner
phaidon
Collaborator

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.

Mateo Tibaquirá Palacios
Collaborator

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.

Drak
Owner

Is there any particular reason to have this separate. Can you please document what vars you are using with themeset/get and what they control.

Mateo Tibaquirá Palacios
Collaborator
Drak drak closed this November 01, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.