on Sep 17th, 2008pQuery - Messing with the DOM from PHP
You can download the complete source-code + example here
So, this is a small pet-project I managed to get running with a decent API last night, it’s YAPTE (Yet Another PHP Templating Engine), but bare with me for a few minutes. My huge gripe with using PHP as a template language, embedding it within the html, is that it gets messy - quick. For small examples or limited real world usage it’s fine, but for large projects with complex views? No way.
But, I don’t want to create another template language a´la Smarty that basically just emulates a crappier (none thought that would be possible, huh? ;p) version of PHP. So my two main goals when designing the idea for pQuery in my head were these:
- I want to use PHP to format, and output, my data.
- I don’t want to mix PHP with (X)HTML, at all.
The result is, in lack of good imagination, for now named “pQuery” a homage to jQuery. At the moment the code is about 250 lines and the functionality is fairly limited. Let’s take a quick peek at an example template:
Example on a couple of different ways to push data into the template
<html>
<head>
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title></title>
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var annoy = function(){
alert("Annoying...");
}
//]]>
</script>
</head>
<body>
<ul id="post-list">
<li>
<h2></h2>
<span class="small-text block">
Posted %date by
<a href="mailto:%s"></a>
</span>
<p></p>
<h3>Comments</h3>
<ul>
<li>
<h4></h4>
<span class="small-text block">
<em>Posted date by name</em>
</span>
<p></p>
</li>
</ul>
</li>
</ul>
</body>
</html>
And here’s how you’d fill it with data:
<?php
require 'pquery/parser.php';
$posts = include 'example_posts.php';
$p = new pQuery_Parser;
$html = $p->parse_file("example.html");
$html->head->title = "Demo of pQuery-0.1";
list($keywords, $description) = $html->head->meta;
$keywords["content"] = "php, html, separation";
$desription["content"] = "pQuery is just a pre-alpha release";
foreach($html->body->ul->loop($posts) as $items) {
list($li, $post) = $items;
$li->h2 = $post['title'];
$li->p = $post['body'];
$li->span->a = $post['author']['name'];
$li->span->a->attr_format("href", array($post['author']['email']));
$li->span = array('%date' => $post['date']);
foreach($li->ul->loop($post['comments']) as $items) {
list($li, $comment) = $items;
$li->h4 = $comment['title'];
$li->p = $comment['body'];
$li->span->em = $comment;
}
}
echo $html->render();
This allows you to keep the layout(template), presentation-logic(view), control-logic(controller), business-logic(model) 100% separate, although the view-layer probably should be split into two separate layers also, but that’s a topic for another post.
It would be great with some feedback on this, there are some parts of the syntax I’m not to happy about right now (for example the attr_format() function to printf() data into attributes) so there’s room for a lot of improvement. This is in no way production ready code, it was thought out over a couple of hours and written down in the same time.
For all my Python readers out there I have a working python Prototype built on top of cElementTree, but it’s not 100% functional yet so I decide to hold onto it for now.
Also, the above PHP version has no way to select elements based on css-selectors, a selector-engine prototype engine is in the works, but I need more spare time.
This sounds really interesting! Sorry for not commenting on the code, but I am in a bit of a hurry at the moment. Thought I’d let you know that I’ll have a look at it though.
I like this approach. And I feel, that this thing can be made to work really fast (using some cache-technics)..
How about putting this as a project on github or googlecode?
I know another two projects which basically have the same idea:
http://simplehtmldom.sourceforge.net/
This one is pretty similiar. If you know how to access elements in jQuery, you will be an expert with this. Well, it actually is supposed to be like jQuery (… but since PHP is server-based and JS is not, the implementation of course has to be a little different :P)
http://www.jonasjohn.de/lab/htmlsql.htm
Allows you to access the properties of HTML elements, but as far as I could test/see, it doesn’t allow you to change anything?
I know another two projects which basically have the same idea:
simplehtmldom.sourceforge.net
This one is pretty similiar. If you know how to access elements in jQuery, you will be an expert with this. Well, it actually is supposed to be like jQuery (… but since PHP is server-based and JS is not, the implementation of course has to be a little different :P)
http://www.jonasjohn.de/lab/htmlsql.htm
Allows you to access the properties of HTML elements, but as far as I could test/see, it doesn’t allow you to change anything?
Sorry for the incomplete links above, but you seem to have something funny going on with this commenting system?
I know another two projects which basically have the same idea:
simplehtmldom.sourceforge.net
http://www.jonasjohn.de/lab/htmlsql.htm
Yeah the commentin is fubared, its scheduled for maintance some time… well.. sometime ;P
[…] if you read my last post about pQuery you’d be familiar with me working on a way to enhance the PHP templating […]
[…] Fredrik Holmström recently posted a small template engine, based on DOM-manipulation. While there are certainly a lot of template engines around, I find this approach interesting. The concept is simple enough; The template is parsed into an object model (DOM), and then values can be assigned to these through PHP code. The main difference to traditional template engines (Such as Smarty), is that the template it self doesn’t have any imperatives within. In fact, the template doesn’t even have to be written to the template engine, to be used - Any markup can be used as a source. […]
[…] Fredrik Holmström recently posted a sma…, based on DOM-manipulation. While there are certainly a lot of template engines around, I find this approach interesting. The concept is simple enough; The template is parsed into an object model (DOM), and then values can be assigned to these through PHP code. The main difference to traditional template engines (Such as Smarty), is that the template it self doesn’t have any imperatives within. In fact, the template doesn’t even have to be written to the template engine, to be used - Any markup can be used as a source. […]
Saw the write up in my Planet PHP feed and it sounds very interesting. I personally have been using simplehtmldom, which is mentioned above by Paul Grill.
I’ve been doing a similar thing to the capture and bind thing that was mentioned in the sitepoint write up, except using simplehtmldom’s jquery like syntax for selection.
Keep going, sounds interesting.
The problem is how tightly coupled the template and view appear to be (based on your example). I hope you don’t mind if I elaborate on this in code; maybe we can get to hacking on something at SF or Google Code.
There’s indeed no PHP in the template, however there IS HTML in the PHP code. If the problem is with PHP in templates becoming unwieldly, this is the other way round: the reference to HTML elements will become unwieldly in the PHP code.
What’s more, if you look at the template (eg from a designer perspective) it’s not at all clear anymore what you can change. Rule number one probably is to keep of the classes. But can you delete an element with a certain class? Will you know what you just have deleted that depended upon that class?
I think Koen has hit the nail on the head here. In trying to remove PHP code from your HTML, you’ve gone too far the other way and started putting HTML into your PHP.
If the template changes significantly in the future then you’ll end up doing just as much work as you would if there was no templating system at all.
The code looks quite elegantly done from the brief look I’ve just had and it’s quite compact considering the functionality it seems to have, I just think it’s missing the target somewhat in its current guise.
[…] this new post to the SitePoint PHP Blog there’s a look at using a small templating engine recently released by Fredrik Holmstrom that takes a different tack on working with template files - […]
@ All people that noted on the fact that it “moves html into php”: Yes in this version you’re right, I have two other prototypes at my harddrive (one written in python and one in php) that solves this issue in two different ways:
1) Adds a separate php:id or py:id that lets you access those elements from within python/php
2) Allows you to select elements based on css rules, such as: $s(”#posts li”).each(function($element, $i) { /* do something to each li here */ });
All in all I like 1) better since it disconnects the php/python from the css/html completely, sure you need to add php:id=”title” for say the h2-tag on a post or something, but it also means you dont have to clutter your tags with dom-id’s that are only used in php/python or unnecessary css-classes so you can disconnect the php/python from the html structure.
I think number 1) is good step in the direction I would favor. The question I still have at this point is this: suppose you iterate through a list using list items (ul, li). Would the designer (who is instructed about php:id) be able to change the <li php:id=”posts”> into a similare div structure?
Koen yes, as it is now the “abstraction” of using a php:id or py:id disconnects the all together so that you can change the html structure in any way you want aslong as you keep the php/py:id structure the same.
The current implementation of option 1) is in python and im going to tidy it up and put a post up about it.
Hey there! Nice implementation. As the matter of fact I was searching for those kinds of TE for my framework. But two things always tend to stop me:
1) DOM-manipulating is quite hungry for the resources
2) If you get some templates changed (in a web-designing studiowhere I work I get them alot!) you are forced to change your php-code as well. And that’s really bad.
Chears.
We have put together a PHP DOM Template engine that seperates design from development and works well. It uses three new attributes which are removed at render time.
We have tested is speed against a number of other PHP Template engines and while it is slightly slower than some of the pre-compiled template engines this one fairs well for a direct parsing renderer.
The best thing is if you want to re-template a site and not redo the code it is all quite possible if you have the site planned out well.