DB_Table: Pre-Defined Per-Query Fetchmodes

Ian Eure just provided a patch to DB_Table that is genius in its simplicity. While I have not tested it, the patch looks like it will cause no trouble. In short, in your predefined SQL queries, you can specify that the query should return in DB_FETCHMODE_ASSOC, DB_FETCHMODE_ORDERED, or any other fetchmode. For example:

// predefined query for a list of all rows
$this->sql['list'] = array(
    'select'    => '*',
    'from'      => $this->table,
    'order'     => 'some_column DESC',
    'get'       => 'all',
    'fetchmode' => DB_FETCHMODE_ASSOC

// predefined query for a single row
$this->sql['item'] = array(
    'select'    => '*',
    'from'      => $this->table,
    'get'       => 'row',
    'fetchmode' => DB_FETCHMODE_OBJECT,
    'fetchmode_object_class' => 'myDataObjectClass'

With that, you can call $dbTable->select('list') and get an array of rows, or call $dbTable->select('item', "id = '9'") and get an object of type myDataObjectClass.

This is only in CVS right now, as I’m trying to add various Oracle restrictions to DB_Table, but it was just too neat to not add in right away. Thanks, Ian Eure.

DB_Table is a PHP class to automatically create RDBMS tables and XHTML forms. It includes a “poor man’s” data type abstraction wherein the database is forced to store date and time data in ISO formats, which means you do not need to do date/time magic on your queries before executing them (and you don’t need to do magic on the return results, either).

YaWiki 0.18 alpha released

YaWiki 0.18 alpha is ready for download. The change notes are:

* updated to take advantage of Text_Wiki 0.22 and later

* configuration change: Text_Wiki parsing and rendering is much more configurable via [Text_Wiki_*] groups in Yawp.conf.php (instead of via the [yawiki] group)

* now supports RSS feeds for all pages in all areas, all pages in one area, or one page in one area

* yawiki::getPage() now takes optional $area, $page, and $dt arguments

* clicking on the “Revert” button when no date-time is selected now reverts to the most-current saved version

* cannot delete Main (or other default) area in area_list.php

* other areas in the wiki are automatically set up as interwiki sites

* acl.php area name list now shows a ‘*’ wildcard

* there is now a “settings” link on area_list.php (clicking on the area name will take you to the page list)

One big deal is that you can configure Text_Wiki directly now, with all the new CSS options that Text_Wiki 0.23.1 has. Another is that public RSS feeds are available for the entire wiki, one area (all pages), or one page in an area. No RSS feeds for comments yet, because that’s part of a separate project (Yet Another Comment System, or Yacs, which has until now been embedded in YaWiki in pre-alpha form).

With this release, I am willing to call YaWiki feature-complete for a 1.0 release. Keep the bug reports coming (there have been remarkably few, hope it stays that way) and I’ll start commenting and documenting in earnest. With luck it can go beta over the next couple of months, then a stable release early next year.

YaWiki is a wiki-like CMS (or a CMS-like wiki, if you prefer) designed for collaborative documentation efforts. It is built from PEAR and PEAR-compliant components such as Savant, DB_Table, Text_Wiki, and uses the Yawp foundation for rapid application development.

Savant and The Right Reverend Jim

RevJim has a great critique on one of my many posts about Savant vs. Smarty. His analysis is accurate, fair, and open. You really should read the whole thing. In the mean time, here are some highlights of what I want to respond to:

As of a few verisons ago, PHPSavant has a compiled templates option. In the event that your security needs would keep you from allowing template authors direct access to PHP, you can author a PHPSavant template compilation class that will, when activated, convert template markup of your own design into proper PHPSavant template code.

Smarty has the advantage over PHPSavant because the template compiler and, therefore, the language of the template is already written. This means, first and foremost, that I don’t have to write a full-featured, flexible template compiler like I would with PHPSavant. This also means, though this is less important, that users of differnet Smarty based applications can join forces to teach one another and lead by example when it comes to what Smarty is capable of. With PHPSavant, those authoring templates in PHP would be able to help one another. But the users of applications that employed PHPSavant with a template compiler would find themselves in less company.

He concludes, “if PHPSavant were to implement a template compiler that was as featureful as the Smarty template language and provide a means in which to request template compilation only if a template had been changed, Smarty would, unless there are any major speed differences, have no reason to exist whatsoever as PHPSavant would cover the needs of both the ‘pure PHP template junkies’ and the ‘template tag sugar addicts’.”

Jim, please tell me you didn’t try to set me up for this one. 🙂

Such a compiler already exists in basic form as part of the standard Savant2 distribution. It converts a limited markup, and only compiles when the template source has been modified. While not 100% locked down, part of the plan is to add a feature suggested by Joshua Eichorn to have the PHP tokenizer extension pass through the script to make sure only “whitelisted” PHP has been generated.

The markup is as follows:

Markup Action
{$this->var} Prints an assigned variable
{$var} Prints a local variable
{if (…): } Starts an if block
{elseif (…): } Starts an elseif block
{else (…): } Starts an else block
{endif} Ends an if/else/elseif block
{for (…): } Starts a for loop
{endfor} Ends a for loop
{foreach (…): } Starts a foreach loop
{endforeach} Ends a foreach loop
{while (…): } Starts a while loop
{endwhile} Ends a while loop
{[‘pluginName’, $this->arg0, $arg1, ‘arg2’, …]} Activates the plugin named ‘pluginName’ with an argument list
{* … *} comments
{tpl ‘template.tpl.php’} Includes a template

The markup is converted directly to PHP and matches very closely the PHP an author himself would write; the compiled PHP code is very clean and easy to debug.

While this basic example compiler is not as full-featured as the Smarty compiler, any basic functions that are missing can easily be added, if for no other reason than the codebase is much prettier (it adheres to the PEAR standard) and nicely object-oriented. Savant is also a lot lighter than Smarty, so there’s less code to slog through.

Does this mean there’s no reason for Smarty to exist? Certainly not; while I have no use for Smarty, that does not mean there is no use for it period. But the existence of this basic compiler, I think, goes a long way toward satisyfing some of RevJim’s desires regarding a non-Smarty template system.

On a related note, Jim is dead-on about collaborative effort between users of different markups; because Savant does not dictate what compiler you must use, anybody can come up with any kind of markup they want. It would be easy for this to lead to chaos on the compiler front.

However, I see this as a strength, not a weakness. Because the compiler is separated from the core templating system, the “best” or “most useful” compilers can evolve separately from the core template functions. Different communities can write compilers to suit their particular needs, all while using the same core functions and plugin sets. Thus, you get the best of both worlds; a relatively static core package (top-down) that provides an easy, dynamic, and well-defined way to extend and enhance the functions of that package (bottom-up).

UPDATE: See the Savant2_Compiler_basic documentation for more information.

UPDATE: Jim responds! It’s bloggy ping-pong! 🙂

New Text_Wiki Mailing List

If you use the Text_Wiki package you can now subscribe to its dedicated mailing list at [email protected].

One of the inconveniences of PEAR is that is has no package-specific mailing lists. Thus, if you want to talk about a specific package and no other, you have to get all the traffic whether or not it is related to the package in which you are truly interested. As I said, it’s an inconvenience, but having it would be a nice touch. Thank goodness for Tigris. 🙂

Text_Wiki is an object-oriented PHP library to parse wiki text and then render it into any of a number of formats. Each parsing and rendering rule is its own class, so you can add/change/delete parsing rules quite easily. Aaron Wormus gives it a favorable review (thanks Aaron! 🙂 and provides some example code on how to write your own rules at the end of PHP Barnstormer #15.

Savant version 2.3.1 released

I bungled the Savant 2.3.0 release (c.f. how overload() and __call() bit me in ass on PHP 4), but with the kind forbearance of its users, Savant 2.3.1 will make up for that fouled release. Here are the change notes:

* PHP5 Only: Supports __call overloading as an alias to plugin(). No support for overloading in PHP 4; sorry.

* The form plugin no longer generates layout for hidden elements (thanks Alain Petignat)

* Fixed two errors in the Exception error handler (thanks Jeff Surgeson)

* Fixed trimwhitespace filter to handle preformatted blocks with attributes in the tag (thanks Alain Petignat)

Savant is a template system for PHP that uses PHP itself as the template markup language. Savant has plugins, output filters, customized error handling, and allows you to hook in a compiler object to deal with customized non-PHP template markup. I call it the simple, elegant, and powerful alternative to Smarty.

Speaking of which, John Coggeshall used to think that something like Smarty would be a bad idea (see his comments from 2000, on a PHP3 list, here.

The differences between how I work now and how you propose work be done in the future is staggering — you are asking me to let a designer that I don’t trust to write basic HTML to write advanced control loops and logic blocks using a top-end system which converts this pseudo-language into PHP and THEN processes the PHP Code… FINALLY outputting the page to the user… assuming that designer wrote his code right AND the top-level parsing engine actually parsed it correctly.

(As a side-note, I strongly suggest reading the whole thread, which is about whether or not to embed a template system within PHP, and what the markup should be like. There are arguments for and against PHP-based markup — the “two languages” and “mini-language” points come up multiple times. There are predictions that the new template language would quickly overlap with PHP and make it necessary for developers to know two languages, the real PHP code and the pseudo-PHP template markup code, for no reason other than to call one of them a “template.” Zeev Suraski in particular appears to be clairvoyant on these points.)

This was 2000, of course, and at the height of the dot-com bubble, where anyone who could spell “HTML” was counted as an expert. PHP did not then enjoy the widespread acceptance it does now, so it is easy to understand why Coggeshall was unwilling to let a designer have anything to do with “real code.”

Coggeshall recently followed up on that post with new comments here, in which he says he needs to eat his own words, although he doesn’t really say why (John, if you’re reading, I’d be very happy to hear the specifics :-).

Man, considering I’ve given Numerous Talks on Smarty, am the author of IntSmarty, and this very web site is completely Smarty-powered, this posting is clearly a case of me shoving my foot deep down my throat. In my defense, it was written 4 years ago…. and I do still agree that there are circumstances when Smarty doesn’t make any sense… but still — well, needless to say its quite funny to read that posting now. Since it’s out there, I figure I’d bring it to light myself and laugh before someone else beat me to the punch

So I’ll say it, everyone mark it down in your calendars — I was dead nuts wrong.

Coggeshall’s contributions to the PHP world notwithstanding, I would say his conclusion was right in 2000, if for different reasons in 2004. In contrast to John, I believe there is only one reason to even think about using Smarty (or a similar system) and that reason is not exactly all-encompassing. More on that in a moment.

First, here is my foundational question: Why would you have one interpreted language act as the interpreter/compiler for another language just to convert it into the first language? Regardless of whether or not you cache the compiled result (*) like Smarty does, using PHP to “compile” a template into PHP makes no sense to me; if it’s going to be converted to PHP anyway, you might as well just use PHP as the markup language to begin with instead of some other markup. Using PHP itself means less to learn, less to debug, more powerful functions, cleaner code, forwards compatibility, and so on. This is how Savant works: you get all the power of model-view separation by using the Savant object to interface with a template script, but the template script itself is in PHP, and that template script can use the Savant plugins for custom tasks (such as generating a form).

For me, there is one reason, and one reason only, to “compile” templates: if the template author is a security risk. I don’t mean, “the on-staff template designer can’t be trusted to use PHP properly” — if you are in that position, you have a management and training issue, maybe a personnel issue, and not a template system issue. Frankly, if a designer can learn the complex Smarty loop and section markup, that designer can learn minimalist PHP.

No, I mean if the author is an actual security risk; say, if your application allows its users to edit templates via a web form. Then, and only then, is compiling or converting a limited markup to full PHP a reasonable option. Fortunately, Savant allows for this as well; you can hook in a compiler object to convert markup to PHP. Savant comes with an simple compiler as an example implementation.

None of the above commentary applies to XML/XSLT templating because I know exactly squat about that methodology. Having said that, I am happy to be the malcontent noodge in the PHP templating world, and look forward to hearing you tell me why I am wrong, be it in your own blog (remember to trackback!) or in the comments below. Happy templating, all. 🙂

(*) Yes, I know that the Smarty folks don’t call it a “cache” — but the fact remains that they store the compiled template on disk for faster future access. That sure sounds like a cache to me. They refer to it as distinct from their “output cache” but that’s another issue — why use a template-system cache that is separate from the rest of your application? Again, makes no sense to me; caching seems more like an application-level task, not a template-system task.

DB_Table and Oracle Support

I want to make DB_Table work with everything, everywhere, all the time, the same way, so that you don’t have to use extra function t0 massage your SQL queries and the data you use in them; that way, you can make your DB_Table-based application completely portable without having to think about it too much. This is necessarily a lowest-common-denominator approach, and so far it seems to have worked passably well. The biggest problem, until yesterday, was that PostgreSQL won’t allow you to have a table with indentical field names and index names (easy solution: append index names with “_index” automatically).

However, Alex Höbart informs me (among other things) that Oracle has a strict limit on the length of table, field, index, and sequence names: 30 characters, maximum. This is a problem, becuase many other databases seem to allow at least twice that length (e.g.: MySQL allows 64 chars, Microsoft SQL allows 128, and SQLite has no limitation).

If it turns out that at least one other RDBMS has a similar limitation, then I can in good conscience make that limitation universal in DB_Table. If not, I will be faced with the hard choice of either dropping Oracle support (awful!) or at least adding a “strict check” flag so that DB_Table classes will know to use the 30-character limit (not as awful, but still bad, and not really what I want to do).

Anybody out there know if the Frontbase and PostgreSQL have 30-character (or similar) length limits for names of tables, indexes, fields, and sequences?

Update (11:01): It appears PostgreSQL has a default limit of 31 chars.

A cousin, of sorts, to DB_Table?

It seems I am not alone in thinking it is wise to embed database table column information in the PHP class that will interface with that table. Harry Fuecks, in his blog entry titled A Development Infrastructure for PHP, points to work by Tony Marston.

Check out Tony’s notes about his business class field properties and compare with the DB_Table schema setup documentation. They are obviously very similar, at least in example and documentation. The both do automated validation as well, and have “hints” for form-building embedded in the class.

Nice to know someone is on the same path as me (although Tony is obviously **much** further ahead :-).