PHP
Article

Transphporm – a Different Kind of Template Engine

By Zack Wallace

If there is one thing the world needs, it’s definitely another PHP template engine! But wait, this one is different!

Many PHP template engines (Smarty, Blade, Twig…) are little more than abstracted PHP code, making it easier to write loops, if/then/else blocks, and display variables with less verbosity than vanilla PHP. These traditional template engines require the designer to have an understanding of special syntax. The template engine must also be in place and operational in order to parse data and thus completely render the final design. Nothing wrong with this.

Magazine, flyer, brochure, cover layout design print template

Transphporm follows a different approach that is generally known as “template animation”. What this means is that the web designer creates the entire HTML/CSS/JS page including placeholder content such as “Lorem Ipsum”, then the template engine comes along and replaces parts of the DOM with new data before the final render.

The benefit of template animation is that the designer does not have to know the backend code, template language, or any particular special syntax. They can use whatever tools they want to create 100% functional HTML pages.

The server-side software does not even need to function while the designer works. This means the designer doesn’t have to wait for the backend to deliver data for them to work with.

Basically, the designer can work with this:

<h1>A Good Title Here</h1>
<p>A subtitle</p>

<p>Some awesome text for clients to see.</p>

Instead of this:

<h1>{$futuretitle|upper}</h1>
<p>{$futuresubtitle|capitalize:true|default:'Default Text'}</p>

<p>{$futureawesometext}</p>

The placeholder content in the first example will be replaced by Transphporm. In the second example, the template engine must be functional and parsing the templates in order to see the final design as the designer envisions it.

Notice how the separation of concerns reaches nearly 100%. There is no special syntax or code that the designer needs to know. On the server-side, Transphporm does not need to have any HTML tags hard-coded. You don’t have logic and code on the front end, and you don’t have presentation and nodes being hard-coded in the backend.

Note: The backend may still produce reasonable HTML tags such as what is created through a WYSIWYG editor. i.e img, a, p, strong, em, etc., but never block level when done right.

Let’s see how this works. If you’d like to follow along, please prepare a new environment.

Installing Transphporm

In the public folder of our project, we’ll install the package via Composer.

composer require level-2/transphporm:dev-master

Then, we create a new index.php file with the content:

<?php

require 'vendor/autoload.php';

Note: Frequently run composer update as Transphporm is an active project. It updated a few times during the writing of this article.

Create Your Pages

Transphporm requires no front-end syntax or special code at the design level. We will use a CSS-like selection language to find and replace content before rendering output to the browser.

By the nature of template animation I can theoretically grab any ready-to-go template off the web so long as it is XHTML valid. This means <meta charset='utf-8' /> and not <meta charset='utf-8'> as is with current HTML5. Modern practice is to not use self-closing tags, but to be XML-valid, we must. Note that your final render can be HTML5, but the templates you create for Transphporm must be XHTML. This is just the nature of using PHP’s XML methods.

A Transphporm object requires two values. One is valid XHTML markup which represents the designer’s template. It could be an entire page, or just snippets of XHTML to be used in the greater theme. The other is TSS (Transphporm Style Sheet) directives which contain the replacement logic.

Reference the github page for full documentation as I can be only so verbose within the length of this article.

Add this to the index.php file:

$page = 'home.xml';

$tss = 'home.tss';

$template = new \Transphporm\Builder($page, $tss);

echo $template->output()->body;

Now create the home.xml file with this basic XHTML template:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        
        <title>HTML5 TEMPLATE</title>

        <style>
            body { padding: 20px; font-size:1em; }
            header nav { background-color:#ACEAD0; padding:15px 10px; }
            header nav ul { padding:0; }
            header nav li { display:inline; list-style:none; margin-right:15px; }
            header nav a { text-decoration:none; }
            article header h1 { margin-bottom:4px; color:#34769E; font-size:2em; }
            article header h2 { margin:0; font-size: .8em; color:#555; }
            article p { font-family:Arial, sans; color:#444; line-height:1.4em; }
            footer { background-color: #444; padding:10px; }
            footer p { color:#E2E2E2; }
        </style>

    </head>
  
    <body>
        <header>
            <nav>
                <ul>
                    <li><a href="#">Home</a></li>
                    <li><a href="#">The Goods</a></li>
                    <li><a href="#">Favorites</a></li>
                    <li><a href="#">Media</a></li>
                    <li><a href="#">Contact</a></li>
                </ul>
            </nav>
        </header>
        
        <main>
            <article>
                <header>
                    <h1>Page Title</h1>
                    <h2>By Jehoshaphat on Jan 1, 2015</h2>
                </header>
                
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut voluptas deserunt in quam itaque consequatur at recusandae, veritatis placeat porro cum magni eos iure vero, obcaecati est molestiae quos enim.</p>

                <p data-p="yes">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi sed asperiores cum explicabo praesentium, mollitia possimus nam. Aperiam autem doloribus hic. Ex quae quia fugiat, fugit eaque quam adipisci nemo.</p>
                
                <ul>
                  <li>A list item 1</li>
                </ul>
            </article>
        </main>
            
        <footer>
            <p>footer stuff</p>
        </footer>

    </body>
</html>

Now create a home.tss file with this:

article h1 {content: "My New Page Title"}

The TSS directive is “selecting” the h1 using CSS-like syntax. “Find an h1 that is a child of an article tag”. Note that specificity matters. If you had many article tags or many h1 tags, they would all be selected and changed!

This is especially true for repeating nodes like the <li>. If there were more than one in our template, each individual list item would be replaced by the entire repeating dataset!

If your index.php, home.xml, and home.tss files have been created correctly, you should be able to open the website and see the template. The template has <h1>Page Title</h1> but you should actually see “My New Page Title” when rendered in the browser.

Transphporm supports common CSS syntax including:

  • .classname
  • tagname.classname
  • direct > descendant
  • #id
  • element[attribute="value"] OR simply element[attribute]

Methods not supported include ~ and +.

Beyond these selectors, Transphporm supports pseudo elements including:

  • element:before
  • element:after
  • element:nth-child(n)
  • element:even
  • element:odd

You can chain selectors together just like in CSS.

article header > p {content: "First paragraph after the article header section"}

This is the easy stuff and is hopefully straightforward.

At this point, you’re surely thinking “but I don’t want to hard code text in the TSS directive!”

Well, that’s where the fun begins.

Handling Data

Let’s pretend this project is a bit more complicated. You are not likely to have the new <h1> content hard-coded in a TSS file! And you’ll likely have more than one piece of content to update.

I’m going to create an object called $data and assign some values to it.

Update index.php to this:

require 'vendor/autoload.php';

// Some fancy routing to setup the page.
$page = 'home.xml';
$tss  = 'home.tss';

// Some fancy controller/model action to get data.
$data = new stdClass;

$data->pagetitle = "Awesome Page";
$data->title     = "Article Title";
$data->subtitle  = "By Zack";

$template = new \Transphporm\Builder($page, $tss);

echo $template->output($data)->body;

Now we have $data as an object. We also added $data to the output() method.

The home.tss file can now be updated to this:

title {content: data(pagetitle)}
article h1 {content: data(title)}
article h1 > h2 {content: data(subtitle)}

The attribute we use called content accepts a value called data(). This is similar to how in CSS you might supply rgba() as a value for color.

At this point we can replace any content by utilizing the CSS syntax. Notice how we even replaced content within the <head> section.

DOM Concerns

At this point, you may be thinking that the designer and programmer don’t have to talk to each other; but on some level they do. The designer must use proper XHTML or the engine will crash (error handling may be improved over time).

You might be wondering what happens if the designer changes the DOM and thus breaks a TSS selection. This can happen, especially if you rely more on the DOM tree than on well-thought-out IDs and classes. I would rather use id="posttitle" than rely on main article header > h1 which may not always be set in stone.

Multiple Partials

We can also utilize more than one XML file to assemble the final template.

Here is an example TSS file:

@import 'another.tss';

aside {content: template("sidebar.xml")}

We can use @import to include other TSS files. We can also use template() to assign partial xml to the selected node as seen above. Any TSS directives that come after this line can affect the included xml file.

This way, you can carefully craft the importing of xml partials and TSS directives to assemble the final page. Just like CSS, everything compiles top-down.

Not only this, but you can replace content with partial content of the included template. In the above example, I’m including the entire sidebar.xml file. But what if I only want the <aside> within that file? Just do this:

aside {content: template("sidebar.xml", "#extra aside")}

This will only pull the <aside> out from under the element with ID “extra”. The benefit of this is that the designer can still work with complete templates if they want to, even though you may only extract certain elements. It also means that, just as you can combine images together into a single file and use CSS to display them as needed, you can combine template elements in a single file and just extract the parts you need.

Advanced Directives

One concern you might have is that if the designer breaks up the design into many partials, doesn’t that defeat the purpose of template animation because now you need Transphporm to put it back together? Kind of.

This is because the “master” template still contains the designer’s complete mockup. Nothing changes there. The “real” final markup will be within the partials. This makes the designer’s job only slightly more complex as they will have to edit the main design visually, then copy and change things within the partials for production. If they update the primary page, they may have to update partials too.

If you refer back to our basic HTML template, partials could easily be used for the header, the menu, the primary content area, the footer, etc. But placing these in partials doesn’t affect the designer being able to leave the primary base template fully intact and visually complete. The partials will simply replace the placeholder markup later.

And as we just saw, the partials themselves can be part of a larger complex or complete page.

Repeating Data

Transphporm can handle repeat data through the use of a repeat() attribute.

Our template has an unordered list. We can fill it by using $data to pass an array of objects. Let’s add an array of fruit objects to index.php.

$fruits = []; // Master array of all fruits

$fruit = new stdClass;
$fruit->name = 'Apple';

$fruits[] = $fruit;

$fruit = new stdClass;
$fruit->name = 'Pear';

$fruits[] = $fruit;

$data->fruits = $fruits;

Now in the TSS file:

article ul li {repeat: data(fruits); content: iteration(name)}

If you’ve added the data to index.php and updated the TSS file, the unordered list should now have two <li> nodes listing “Apple” and “Pear”.

Before:

<ul>
    <li>A list item 1</li>
</ul>

After:

<ul>
    <li>Apple</li>
    <li>Pear</li>
</ul>

Notice how we used two attributes “repeat” and “content” separated by a semicolon. Just like setting height, width, color and border in CSS on a single node, you can apply multiple transforms using a single selection with Transphporm.

We passed data(fruits) to the repeat function. This will repeat the selected node (the <li>) including its closing tag. Then, we use iteration() to tell it what data within each fruit object to display.

Note: beside data() and iteration(), there are other transforms available including format which accepts the values “uppercase”, “lowercase”, “titlecase”, “date”, and can deal with numbers as well.

Attributes

Transphporm can do some fun stuff with attributes.

Let’s say we wanted to hide the <li> if it equals “Apple”. To do this, we can inspect the current iteration and select based on that.

article ul li:iteration[name='Apple'] {display: none;}

Notice how it works like a psuedo element by using a colon after the <li> and in square brackets matching a name=value pair. Notice also that Transphporm can just as easily hide elements with the familiar CSS directive display:none (though with Transphporm, the elements are fully removed from the DOM, not just hidden).

In our template, the second paragraph has data-p="yes". Let’s hide it based on that value.

article p[data-p="yes"] {display:none}

Notice how there is no colon after p here like before when using iteration, which is a Transphporm function. We are selecting with normal CSS attribute syntax which doesn’t use a colon.

You can also set the content of the attributes themselves. The example from the docs uses a “mailto” link like so:

a:attr(href) {content: "mailto:", iteration(email)}

Again, attr is a Transphporm function so the colon is used. Also notice “(href)” is a direct selection of the attribute itself, no value is used.

Something cool happens here – content is set to “mailto:” but then we use a comma and the iteration’s value. Transphporm will concatenate multiple values when using a comma, e.g.:

p {content: "This ", "is ", "really ", "long"}

So with the previous “mailto” example, a proper attribute href="mailto:someemail@example.com" will be assembled.

Headers

Transphporm does not send headers. You will have to use normal PHP functions for that.

The output() method returns an object with two attributes. One is body which contains the rendered HTML, the other is headers which is an array of headers.

The way to set a header is to select the <html> element and use the built-in pseudo element :header to set it.

html:header[location] {content: "/another-url"}

To make use of headers set this way, you’ll have to read the array returned by Transphporm, take those values and set them with PHP’s header() function. Instructions for how to do this are in the docs.

Conditional Changes

It is possible to change elements based on logic in other parts of the application. Let’s say your program has a function like this one:

class Security {
  public function LoggedIn() {
    // Some logic
    return false;
  }
}

$data = new Security; // Be sure to pass $data to the output() method as usual

Now you can read this value and determine the appropriate action:

#welcome:data[LoggedIn=""] {display:none}

This could be quite handy!

It should be noted that, with template animation, we usually start with a complete template with all features, then strip away parts that don’t belong. We would build the template with “logged in” features, then remove them from the DOM if not needed.

This is described as a “top down” approach, as opposed to “bottom up” where only minimal markup is present, and we add stuff as needed.

Both approaches work with Transphporm.

Benefits of Decoupled Display and Logic

An advantage of separating display logic from markup is that they become decoupled entirely. This means that any given XML doesn’t have to belong to any given TSS. In fact, some XML could be used with different TSS and some TSS could be used with any other XML.

One example of this is using TSS to repopulate forms. A single TSS could be used to repopulate any given form template. It would look like this:

form textarea {content: data(attr(name))}
form input[type="text"]:attr(value) {content: data(attr(name))}

The function attr(name) reads the “name” attribute of the selected element. If the “name” attribute of the textarea element were “comments”, then it compiles to:

form textarea {content: data(comments)}

data(comments) here is referencing the passed-in $data object we’ve already used before, but it would work just as well if $_POST itself were passed instead.

The second line in the above TSS is selecting all form input elements with a type of “text”. It is then specifically selecting the value attribute itself which is where you would put content when populating a form. The data is, again, coming from data(xyz) where “xyz” is the name attribute of the selected element. In turn, the name attribute will match the data coming in from $_POST or a $data object.

The end result is that anywhere you need to repopulate a form, you could simply include one TSS file like so:

import 'form-populate.tss';

As an example of passing $_POST you might do this in your PHP:

$data->title = "Article Title";
$data->formData = $_POST;

Once $_POST has been passed in through $data, a binding feature can specifically link formData to all the TSS used under that form element.

form {bind: data(formData)}
/* Now that formData is bound to form, it can be accessed directly */
form input:attr(value) {content: data(attr(name))}

Binding just means I can call data(key) rather than data(formData[key]) because the context of data() was changed to reference formData directly.

Language Independence

It should be noted that decoupling means any language can be used to process the TSS files without any change to the templates. The author has built a sister compiler in Javascript that is 100% compatible as far as TSS and XML templates go. Find it on Github at Transjsform.

Challenges

Using template animation takes care of both the designer and the coder. The designer can create their templates and partials without any real concern for the backend or template engine. Only valid XHTML is needed. The programmer, on the other hand, only needs the ability to easily find the DOM elements which need their content replaced.

The programmer and designer will, however, need a planned-out file structure for where to place major and minor templates, partials and so forth.

The person who is not quite taken care of yet is the editor/writer.

It’s fine to have XHTML templates. It’s fine to have TSS logic somewhere. The data can come from a controller and be assembled into a single $data object. But where do the writers write?

Obviously, some form of editorial interface is going to be required to connect a writer to a particular piece of content/TSS to update it. There is nothing contained in the template itself to inform the backend which nodes require content editing and which do not.

Some form of meta-data will be required to say “this paragraph needs custom data, but this one does not”. The programmer also needs to know which sections will be replaced by a partial. There may even be multiple versions of a partial depending on some other application logic.

Because of this, we can’t really claim that there is a 100% separation between designers and coders, as they still need some level of congruity regarding the overall structure of things.

Make the Editor Learn TSS?

One of the reasons for template animation is to prevent a designer from having to learn a template language or syntax. This is a pointless goal if you are just making a writer learn TSS syntax instead! It would likely be much easier for a designer to learn a template syntax than to teach a writer CSS syntax.

If the designer is also the content editor, then they have to learn TSS anyway, so why not just learn an existing mature template language? If the editor doesn’t know CSS syntax, nothing will be intuitive for them.

Parts of TSS are for assembling the page, other parts for assigning copy. Editors further only need access to some of these transforms. Some transforms may be structural in nature while others content oriented.

A true separation of concerns here must include the editors as well as the programmer and designer. No existing CMS is going to be able to adopt Transphporm as-is. A complicated template could potentially contain hundreds of transformations with lots of various logic paths. The content editors need a WYSIWYG.

All together, this presents an interesting challenge for making Transphporm usable for everyone.

It should be noted that the author is currently working on a parser where an editor could submit Markdown as the content and Transphporm would parse it into HTML for the output. This feature should be added very soon and takes us a step closer to an editing interface.

Caching

Basic caching is being implemented as written about here. Without a cache, PHP currently has to traverse the XHTML and parse TSS for every page load. In its current iteration, this could create a performance issue when using Transphporm.

Conclusion

Using CSS-like syntax to select DOM elements is a very fun concept. Designers may find relief from having to learn a new syntax, and they can mock up 100% complete designs with no worry about the backend. This also means one should be able to download any XHTML, ready-made templates and get started relatively quickly with minimal DOM changes.

It’ll be interesting to see how this project matures. The first CMS interface to be created to manage TSS transforms and content editing will be particularly interesting.

If you don’t like the way regular template engines work, maybe Transphporm is more up your alley? Take a look and let us know!

  • sarfraznawaz2005

    I first thought “Oh my God, yet another thing to learn” but I think this has great potential and would be really useful and improve over time. Really nice idea, thanks for sharing !

  • gggeek

    This is not a novel idea (there are some js template engines doing this afair), and although it might be implemented better than previous incarnations, the fact that none of those gained traction in real life leaves me a bit skeptical…

    The idea by itself seems great in theory, but it turns out that in real life it has many shortcomings. The article does a good job of describing some cases; here are some more which I can think of:

    1. the “login-form/hello-mr-x” combo: does the designer really produce a single html page with both boxes included and a css toggle to enable/disable them, or does he usually produce two html files in real life?

    2. for more complex logic than either-display-this-block-or-that-block, things can get messy quickly, eg how do you communicate clearly in an html template the fact that an item in a menu can have multiple states (bold, linked, bold-and-linked)?

    3. slicing the templates in parts which are reused across the site: I doubt very much that the designer has the same idea of the slicing needs that the developer has

    4. not being able to produce non-html output can also make developers wary of learning a tool with limited application usage, and the fact that it breaks on non-well-formed html is a major problem

    • http://www.zacksdomain.com/ Zack Wallace

      For 1) It’s not that there is a CSS toggle, it’s that only one of the two alternate nodes are ever included in the first place (if it were grabbed as an external partial). Or if both are in the original design, one of them is excluded from the final render. Not hidden with CSS, but not included at all. The this/that nodes could be extremely simple (username/pass) to very complex (user name, id, messages, notifications, meta-data, etc etc). So the designer could have very different layouts for each condition.

      2) aren’t these usually handled by JS anyway? Or standard CSS? Or the logic of the application itself? Your application is assembling the menu. TSS would just be populating with whatever data the application is returning.

      4) Not sure what you mean here. Outputting bad HTML is a good thing? Designers should be able to create malformed templates? Or are you talking about outputting alternate MIME types, like it should be able to work with JSON or XML or something?

      It’s a work in progress. I think it will make more sense when people can see it in use within the larger context of a CMS or interface of some sort.

      • gggeek

        about 1 and 2 and 3: my point is: how natural is it for the designer to work with 2 or more partials which represent the alternative representations of some “block of information” on the page?
        I am not a designer, so I might be completely wrong, but my idea is that the for anything but trivial cases, the designer would have a hard time delivering the same partials that the developer can use, and viceversa.

        For the menu case, let’s say that we have 3 css classes to be applied , which do not all appear at the same time on a menu (allowed cases are: all items have links, all items have links except one which is bold, or all have links except one bold+linked). I would say that the easier way for the designer to communicate this is to create 3 partials, each of which has the complete menu in it. Now, how would the developer use TSS to populate them?

        about 4: broken html is not something to advocate, but when your pages are built from multiple bits, it sometimes happens that e.g. a div open in partial A get not closed when partial C is inserted.
        Yes, other mimetypes would typically include json and xml (I think that using dom/css based selectors would work fine with xml?)

      • gggeek

        about 1 and 2 and 3: my point is: how natural is it for the designer to work with 2 or more partials which represent the alternative representations of some “block of information” on the page?
        I am not a designer, so I might be completely wrong, but my idea is that the for anything but trivial cases, the designer would have a hard time delivering the same partials that the developer can use, and viceversa.

        For the menu case, let’s say that we have 3 css classes to be applied , which do not all appear at the same time on a menu (allowed cases are: all items have links, all items have links except one which is bold, or all have links except one bold+linked). I would say that the easier way for the designer to communicate this is to create 3 partials, each of which has the complete menu in it. Now, how would the developer use TSS to populate them?

        about 4: broken html is not something to advocate, but when your pages are built from multiple bits, it sometimes happens that e.g. a div open in partial A get not closed when partial C is inserted.
        Yes, other mimetypes would typically include json and xml (I think that using dom/css based selectors would work fine with xml?)

        • http://r.je Tom Butler

          Full disclosure: I’m the author of the library

          >about 1 and 2 and 3: my point is: how natural is it for the designer to work with 2 or more partials which represent the alternative representations of some “block of information” on the page?

          The designer can work with whatever they like. If they like they can use complete .html files that show the entire layout. The developer can then create a partial form *any* element in the file as is shown in the article with:

          aside {content: template(“sidebar.xml”, “#extra aside”)}

          Which opens sidebar.xml and includes the aside element inside the element with the id #extra

          >For the menu case, let’s say that we have 3 css classes to be applied , which do not all appear at the same time on a menu (allowed cases are: all items have links, all items have links except one which is bold, or all have links except one bold+linked). I would say that the easier way for the designer to communicate this is to create 3 partials, each of which has the complete menu in it. Now, how would the developer use TSS to populate them?

          Again, the developer can use the TSS to extract any element at all as a partial so the designer can build a partial with all three states and the developer can extract whichever one they like e.g.

          nav li:iteration[needsbold=true] {content: template(‘nav.xml’, ‘.needsbold’}

          nav li:iteration[needsitalic=true] {content: template(‘nav.xml’, ‘.needsitalic’}

          //Then set the content of the containing link

          nav li a:attr(href) {content: iteration(url); }

          nav li a {content: iteration(text); }

          >, it sometimes happens that e.g. a div open in partial A get not closed when partial C is inserted.

          Which is a symptom of a poorly structured architecture in itself. If you’ve ever worked with a templating system that allows opening and closing tags in different files (e.g. wordpress) it becomes incredibly difficult to maintain. It’s very difficult to see which opening tag matches which closing tag. It’s a lot better in any template engine to keep the opening/closing tags in their own files purely for readability and ease of maintenance .

          > Yes, other mimetypes would typically include json and xml (I think that using dom/css based selectors would work fine with xml?)

          Considering you shouldn’t be using string manipulation to create JSON anyway, this is a non-issue. json_encode() is always a better solution for this task and Trasnsphporm works with any XML based format (e.g. RSS or SOAP)

          • gggeek

            Thanks for chiming in!

            The creation of partials from bits of design files did escape my shoddy reading of the post, and indeed seems like a good step forward in the march for the holy grail of round-trip integration (allowing the designers to make changes after the templates have been integrated by the developers).

            I have a strong dislike for the declarative nature ox XSLT, and find that most programmers are better at understanding/writing imperative logic for medium to complex cases, so it would be interesting to see how transphorm templates compares to twig for a more real-life (ie complex) example.

            Also, having been through the pains of maintaining large bases of behat/selenium tests which identify page elements by a random combination of ids, css classes and dom structure, I am keenly aware of how brittle that coupling tends to be, with the html structure being often in greater flux than the php codebase (and this despite the promises of css ages ago!). This will also be a critical point for the adoption of transphorm imho…

            Flinging over the link to the dev team to see what their feedback is!

          • http://www.zacksdomain.com/ Zack Wallace

            Something I didn’t touch on in the article is how a broken DOM connection can be detected and fixed.
            Once there exists some kind of interface/editor for managing the content, I can imagine there would be a method of detecting when a TSS link fails. When the searched-for element is not found.

            If something breaks with normal template engines, you will get an output of nothing, or some default string, or even error messages, but no real way to detect that something is wrong in the backend.
            With TSS, I can foresee that somehow, in the backend (not the front) that there could be a warning that something is wrong and provide that to the editors. The frontend would see no errors or blank content, but would rather see the default content contained in the template design itself.

            I summary, TSS could potentially provide better management in the backend for content editors and coders when there is a broken connection between DOM and data.
            I could be wrong about that assessment but it’s something I considered.

  • Badumpsss

    Check phptal

    • http://r.je Tom Butler

      phptal isn’t quite the same, it still includes the logic in the template, it just expresses it as xml attributes. Transphporm allows the designer to work with 100% HTML and zero logic (or extra tags/attributes) as the display logic is stored in a separate file

    • http://r.je Tom Butler

      phptal isn’t quite the same, it still includes the logic in the template, it just expresses it as xml attributes. Transphporm allows the designer to work with 100% HTML and zero logic (or extra tags/attributes) as the display logic is stored in a separate file

  • Taylor Ren

    Probably I will never give it a try.

    It has a similar approach like XML/XSLT stuff. Putting data extraction work in CSS is something in fact couples the data AND the presentation.

    “`article h1 {content: “My New Page Title”}“`

    What if I want to see “`h1“` becomes an “`h2“`? I need to change the html template AND the CSS rule as well. Whereas in a template engine, I will only change the template engine.

    • http://www.zacksdomain.com/ Zack Wallace

      If the template designer decides later to change up how the structure works, without breaking TSS, then this is why I suggested it’s better to stick with IDs and classes and not purely DOM structure.
      Secondly, when this project matures and has some type of automated connection between the temnplate and backend interface, “orphaned” TSS could be identified and reconnected to the proper location in the template.
      This is also why I can’t declare it as 100% separation of concerns. The designer and the developer do need to be in line as far as keeping templates relatively immutable.

      • Taylor Ren

        IDs can also be dynamically assigned as we see in a typical forum / post / comment page. The comment ID can be “post-comment-sequence” style. Later maybe changed to a different naming convention.

  • http://www.dev-metal.com/ Chris

    Sorry, and with most respect to the creator: This is an interesting idea, but totally unattractive for backend and frontend developers, in non-theory also nearly unusable. I’ve sent this to several developers in my team (to get more objective feedback) and only received very negative opinions. Personally, I cannot see any advantage in this, also the idea of creating frontend logic/tags/etc in the backend, especially inside PHP, is far from clean code, hard to use in daily workflow (do you want your frontend to work inside your controllers ?), and it bloat the backend massivly, for absolutely no reason.

    Why make things much more complicated and impractical if you could do it in a very clean, simple, obvious, human-readable and fast approach like Twig does ? There’s nothing wrong with foreach-loops or simple if/else constructs in the View, as interating through lists and visual switches are not really logic.

    • http://r.je Tom Butler

      Full disclosure: I’m the author of the library

      > as interating through lists and visual switches are not really logic.

      If loops and if statements aren’t really logic what are they?

      > do you want your frontend to work inside your controllers ?

      I’m not sure what this means, the TSS declarations go inside their own files, nobody would touch the controller other than the back end developer.

      > and it bloat the backend massivly, for absolutely no reason.

      This is a much smaller library than either Twig or Smarty…

      As for the advantages, How often do you need this:

      {% if admin == true %}

      ….

      {% endif %}

      Quite a few times across a site!

      In Transphporm you’d target an element e.g. a class name:

      and apply .admin:data[admin=false] {display: none;}

      The designer can then designate the parts only admin can see with a simple class name.

      Or how about the example of re-populating form fields? That logic is required repeatedly if you’re using twig (without an extra form library). Write the logic once, use it throughout the site. It’s the same difference between style=”font-weight: bold; position: relative” and an external stylesheet.

      • http://www.dev-metal.com/ Chris

        Hi, thanks for the feedback. The question how much logic can / should be done in the View has been discussed for 20 years by 10.000s of devs and the consequence are the established standards that totally do the job and nobody really dislikes.

        As views should only have logic that handles layout switches template engines like Twig/Smarty/PHP are totally fine and the job perfectly.

        And in the end, it’s how people really want to work every day. Twig is nearly perfect, and has been built by analyzing thousands of project workflows, with years of work behind!

        Regarding size/bloating: This has notihng to do with the lib size, it’s about additional, unneeded code in the controller. Adding 5-10 lines of code in every controller (even in the most simple case) works against all clean code standards.

        However, good luck with the project, maybe I’m overseeing use-cases here.

        • http://www.zacksdomain.com/ Zack Wallace

          What do you mean by adding 5-10 lines of code in every controller?
          Your router picks the page/template that’s needed, the controller gathers up some data, then the correct TSS is given the data and shows the template.
          I don’t see any extra code being added to controllers at all.

          I doesn’t matter what template engine/style one uses, there will be some logic going on somewhere. Arguing where the logic takes place is chasing tails. TSS doesn’t require “more” logic, it just moves it around.

          Really it only depends on the job, what tool is best for everybody involved.

          Nobody is saying Transphporm is some kind of killer of Twig. They are quite different in methodology. Like comparing boats to planes or something.

          For example, with traditional template engines, depending on which are chosen, the designer may have more control over logical decisions and what is shown than may be desired. If there are requirements for high security or something, management may not want designers having any control at all over presentation of data or even knowledge of what that data is.
          With the TSS system, some other department can be in charge of deciding what data goes where and the designer has no clue, not even insight into variable names or anything.

          That may be contrived but the point is that template animation has near 100% separation of concerns, the designer can potentially be completely hands-off of the data that may be exported. It might even be that the designer is contracted and can’t be allowed to see the final renderings. They are contracted for an interface, but the final renders have OPSEC concerns. Who knows!

    • http://www.zacksdomain.com/ Zack Wallace

      I’m wondering how it would be unattractive for frontend developers? Considering one of the biggest benefits of template animation is that the frontend devs have little need to know anything about how the backend works. They just need appropriate IDs and classes and they can work with fully complete designs with actual data.
      That would seem more attractive to me, not less attractive.

  • http://www.dev-metal.com/ Chris

    Sorry, and with most respect to the creator: This is an interesting idea, but totally unattractive for backend and frontend developers, in non-theory also nearly unusable. I’ve sent this to several developers in my team (to get more objective feedback) and only received very negative opinions. Personally, I cannot see any advantage in this, also the idea of creating frontend logic/tags/etc in the backend, especially inside PHP, is far from clean code, hard to use in daily workflow (do you want your frontend to work inside your controllers ?), and it bloat the backend massivly, for absolutely no reason.

    Why make things much more complicated and impractical if you could do it in a very clean, simple, obvious, human-readable and fast approach like Twig does ? There’s nothing wrong with foreach-loops or simple if/else constructs in the View, as interating through lists and visual switches are not really logic.

  • Mitch Amiano

    Zack, interesting work. Suppose we wanted to map a navigation data structure (a flat list of menu items in the simplest case, with names and url paths) to a list of anchors. How would that be done using the selector/repeat/content: iteration() idiom, or is there some other construction ?

    A naive approach using the example outlined for a list in the article above would either destroy the anchor tag, or concatenate the anchors within the first list item. A more general purpose transformation language would (by coupling partials inside the transform) allow matching against the list item, but then manipulate its children, so that the anchor gets the content rather than the list item.

    • Mitch Amiano

      Ah, actually, I think I found the answer already. repeat and iterate need not be on the same nodes, and it allows nested nodes.

  • Anru Chen

    Is this re-invent xml/xlst approach?

    • http://r.je Tom Butler

      In XSLT you still provide the logic inside the template rather than in its own (reusable) file, for example:

      “`

      “`

  • Tùng Red

    I am too stupid to understand this template engine :( Twig is more powerful and production-ready. I love Twig!

    • http://r.je Tom Butler

      I disagree, Transphporm is more powerful in several ways:

      1. Anything can be a partial. You can select any element from any file an use it as a partial. In Twig you have to decide up front what is going to be a partial

      2. In Transphporm you can write content to any element. Using twig, again, you have to decide up front which elements might contain variables (and how those variables are going to be formatted). If you want to add more content to the page, or move which element a variable is placed in you have to alter the template.

      3. You can write display logic once (e.g. populating a form) and reuse it in any XML file.

      None of these are possible using Twig, or a traditional template engine that effectively is a fancy wrapper for str_replace

  • http://www.zacksdomain.com/ Zack Wallace

    Yes a big benefit is the frontend guy doesn’t have to have broken code waiting for backend to catch up. They can complete their designs with dummy content that is ready to show to clients or whatever and not have to worry about database or which template engine is used.

  • frostymarvelous

    I don’t why people still bother. I don’t use laravel, but blade just makes sense.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in PHP, once a week, for free.