Paul M. Jones

Don't listen to the crowd, they say "jump."

Shared Hosts with Subversion?

I want to use Subversion for the Solar project, not CVS, but I can't find a shared host that has it. I use pair.com for absolutely everything, but they won't let me run svnserve on a shared host (which is reasonable) and the Apache2 track is not an option for me.

Anybody know of a reliable web host that has Subversion installed for remote use?

(UPDATE 2005-02-17) I ended up going with TextDrive.


The Hive is dead. Long live Solar!

Inspiration struck this morning. I wanted to get across the idea that this library is essentially a collection of simple, straightforward objects that are all related to each other and share common development principles; in addition, it would come with common application pieces pre-built. An ant hive seemed a good metaphor to use in that case. But as we have learned, the name Hive is already taken, so that's out.

However, I think I have a good replacement name: the Simple Object Library and Application Repository for PHP, or Solar. It is short, highly descriptive, lends itself to a logo and a catchphrase, and is sufficiently specific that you know what it is without being so generic that it has no meaning by itself. And nobody else is using it. :-)

So the domains are registered, all that remains is to rename the class structures and re-commit to CVS.

UPDATE (2005-02-21): You can visit http://solarphp.com/ for more information; and, of course, check back on this blog periodically.


More Than One Hive

Robert Janeczek notes that his project, also called Hive, won an award in the Zend PHP5 coding contest last year. It's obvious he has first dibs on the name; it's also obvious that I didn't search hard enough for other PHP5 projects using that name.

So what to do now, seeing as I already went and bought the domain name "phphive.com"? :-(


Introducing: the Hive

The world may not feel the need for yet another class library, but after two years with PEAR, I sure do. My attempt to unify PEAR packages with a wrapper package (which I attempted with Yawp) is essentially a dead-end. While I like the mode of operation I have developed with Yawp and DB_Table and Savant, I do not think the PEAR project is open to incorporating such a mode.

With that in mind, I am introducing a new class library for PHP5: the Hive. You can download a PEAR package of it. While this is a 0.0.1 development release, I think you will find the work well fleshed out, with a current PhpDocumentor-generated API reference. End-user documentation will be forthcoming in the next few weeks.

A Bit About My Pear Background

What is it that developers love about PEAR? Look no further than this page, which was the result of a call-for-replies on the PEAR-DEV mailing list last year. Let me add to that list my own reasons why I started using PEAR classes.

In the beginning, there was only one thing that mattered to me: unified error handling. That was it, really. If a foreign object reported an error, I knew exactly how to check for it and what format it would be in; if I needed to report an error, I knew exactly how to format it. Thus, for all its flaws, PEAR_Error was the main reason I started using PEAR classes. Add to that the PEAR DB abstraction package, which was a great labor-saver. Finally, and I have come to love this more than anything else, the PEAR installer has turned into a work of genius under the stewardship of Greg Beaver.

But I have come to believe that PEAR is too much a mishmash; even with coding style standards, the class packages operate according to widely varying styles. In addition, it is far too difficult to add a new package that I find useful but is similar in purpose to an existing package (even if the principles of their operation are widely different). For example, see the acceptance of DB_Table in the face of serious opposition and only after patient months of lobbying, as well the rejection of Savant after a knock-down drag-out (to which rejection I contributed my own fair share).

In short, I find it much too hard to do anything new or different within PEAR that is not already part of PEAR doctrine; while this brings stability, it also brings a certain morbidity. (This is not to say I'm leaving PEAR; I'm not. I am just going to concentrate my new development efforts outside PEAR, not inside it.)

Foundational Principles Of The Hive

There is one essential principle behind the Hive: comprehensibility. Developers exploring the Hive should be able to comprehend the code quickly and easily, so they can see exactly what's going on and why. In short, I am tired of slogging through uncommented, undocumented, complex, obtuse code and packages, whether mine or someone else's.

The principle of comprehensibility gives rise to two corollaries:

  • Simplicity of code
  • Obsessive dedication to comments and documentation

These in turn mean that it should be easy to extend and customize code in the Hive, but that has yet to be borne out.

Some Technical Notes

The Hive adheres to PEAR coding style standards and its directory structure is similar to PEAR's.

Hive can exist with any other library set, including standalone libraries, PEAR, Horde, and so on; using the Hive does not mean you are limited to the Hive.

Hive comes with a shared-object aggregator and convenience method central class and some basic functional classes:

  • Hive_Cache for caching; both file and memcached are currently supported
  • Hive_Error for unified error handling
  • Hive_Sql for identical-operation database abstraction (will migrate to a PDO backend as PDO comes on-line)
  • Hive_Sql_Entity for representing data-type abstracted tables with automated validation and form-hints generation
  • Hive_User for user authentication and roles/groups (preferences and permissions will arrive later)
  • Hive_Valid for data validation

One major goal of the Hive is to provide shared application component backends that are not tied to any particular display mechanism. This is accomplished through Hive_Sql_Entity (the successor to DB_Table) and the Hive.conf.php configuration mechanism, along with the shared object instantiator Hive::shared (which is a successor to the Yawp::getObject technique). The initial set of application component objects will include a comment/trackback tool, a wiki page storage interface, and a blog entry storage interface.

Cliffhanger

(Not a conclusion. ;-) I'll be writing more about the Hive in weeks to come; with any luck, this will be in the form of documentation, as well as blogging about feedback, issues, ideas, and to-do items.

As always, I'm happy to hear feedback and see trackbacks.

Update (2005-03-08)

Somebody else is using the name "Hive" for a PHP5 project. I have adopted a new name for the project: Solar. You can search this blog for other Solar entries to learn more, or visit the Solar home page.


Text_Wiki 0.24.0 beta

I released a new version of Text_Wiki today composed of some bugfixes and functionality enhancements (all based on user requests, thanks everyone!).

The big deal is that Text_Wiki is "beta" now. Even though it doesn't have all the renderers I would like, the API has proven stable and extensible. The full change notes are:

* fixed Bug:2670 (incorrect css_new case in "wikilink" xhtml renderer)

* fixed Bug:2916 (parser for "code" does not set all attributes)

* implemented Request:2947 (more flexible way to handle wikilinks) -- the wikilink renderer now lets you specify a callback to determine if a page exists or not

* implemented Request:2917 (allow dot in interwiki regex parser)

* implemented Request:3162 (allow for additional punctuation in interwiki regex parser)

Text_Wiki is a PEAR package designed to parse wiki text into an intermediate format, and then render the parsed text into any supported output format (XHTML by default, but plain text and Latex are also supported, and RTF as well as other formats are expected in the future).


First Free Elections Ever in Iraq

Today, Iraqis get to vote. They were beaten, murdered, gassed, starved, raped, looted, and tyrannized by a dictator for fifty years, and by kings and tyrants before that for all time in memory. But today they get to vote.

Regardless of your short-term petty political bickering about Bush, he's the one who got this ball rolling. Today a people gets to choose its government, because America looked to its own interests, and found those interests to be the same as the Iraqi people: freedom.

A small minority wants to blow them up for voting; those in that minority has only violence and blood, not freedom, on their minds. That's not going to stop the vast majority who want freedom; they will vote, not in spite of, but because of the danger that minority represents.

It's a good day. Break out the cigars, and hail: "Democracy! Whiskey! Sexy!"


Savant 2.3.3 released

Savant version 2.3.3 is ready for download. The change notes are:

* the form plugin now defaults to null for "clear" and "float" on blocks; previous default settings would break surrounding CSS layout

* the form plugin now has added 'layout' setting; when false, no automatic layout is produced; default is true

* the form plugin now unquotes based on GPC -or- runtime magic quotes (becuase values may be coming directly from database)

* basic compiler now uses regular expressions to parse templates

* basic compiler has 'strict' flag to restrict the PHP used in a compiled template, but it's not yet fully operational (chokes on some valid variable code, waiting for fixes in PHPCodeAnalyzer)


Complication Is A Sign Of Muddled Thought

From gapingvoid:

"Having digested shedloads of advertising lingo over the last decade, I'm suddenly finding that the answers that really resonate with me are getting simpler and simpler. Complication is a sign of weakness. Complication is a sign of muddled thought."


Savant3-3.0.0dev1

The first development release of Savant version 3 is ready for download. (Savant is a template system for PHP that uses PHP itself as the template markup language; it supports plugins and output filters, as well as optional compilers.) The following is a link to the PEAR package tarball.

http://phpsavant.com/Savant3-3.0.0dev1.tgz

The release rate for Savant has been very high (three major versions in 18 months). This is because had the bad luck (or poor foresight) to start Savant2 on the cusp of the PHP5 release, so it had to handle both PHP4 and PHP5. With any luck, Savant3 should be the last major version number until PHP6.

Some change notes follow, but they are not a replacement for examining the source code. As development progresses, I'll write up real documentation.

CHANGE NOTES:

Savant2 code was 31793 bytes with comments; Savant3 is 23728 bytes with comments. This is not due to reduced comments. ;-)

PHP5 only, uses public/protected (no private because we want to allow extension) and runs clean under E_ALL|E_STRICT error reporting.

Real unit tests using the .phpt framework. The 'form' plugin test fails becuase the test is not complete yet, but all others pass.

Reduced number of default plugins, mostly from the form element suite. The plugin 'modify' has been renamed to 'safe' but I'm not sure that will remain the case.

In Savant2, you were not supposed to assign a variable with a name starting in "_". In Savant3, there no more restrictions on what you can name an assigned variable; any allowed PHP name is OK.

In Savant2, configuration properties were prefixed with underscore. In Savant3, config properties are stored as a static array inside the conf() method. This has the benefit of keeping all configs away from the assigned variable space (i.e., the object properties). Access only through public getters and setters (which are nominally dumb, but in this case are necessary).

The assign() and assignRef() methods work just like always, but return true/false instead of error objects.

Variable extraction is still allowed. Initially I disliked the idea, but the new configuration scheme allows a very simple and elegant extraction using extract() and get_object_vars($this).

Restricted directories are always on (i.e., Savant2::setRestrict(true) is always the case).

Filters are now simply callbacks; you can specify a function, static class method, or object instance method. The callback should take one parameter, the buffered template output.

Filters are now applied through the native PHP ob_start() callback system, so you can do more complex stuff like ob_gzhandler. However, it makes filters harder to debug, as they occur within the ob_start() process.

Compilers are now simply callbacks; you can specify a function, static class method, or object instance method. The callback should take two parameters, the path to the source template and a reference to the calling Savant object.

No more methods like clear() or getVars(); you can access all assigned variables as public properties of the template object.

No more loading or unloading of plugins or filters; all happens automatically. Once a plugin is instantiated, you cannot un-instantiate it.

Plugins always get a reference to the calling Savant object, just like in Savant1.

Plugin classes must use the method name as their "main" method instead of plugin(). E.g., the 'form' plugin uses form() instead of plugin() as the main method. This is because E_STRICT forces you to have the exact same number of parameters when extending a class.

Plugins are activated via the magic method __call(); thus, no more plugin() method per se. Plugin instance are stored in a static array inside __call(); they are not available to the rest of the object.

All plugins return instead of echo; to display plugin output, use "echo $this->pluginName()". This is because of magic method __toString() requirements. Thus, no more splugin() method.

You can call display() and fetch() the way you did in Savant2, but you can also "echo $Savant;" as the equivalent of display().

The following old methods are rougly congruent to these new method names (this is only a partial list).

    Savant2::loadTemplate() ~= Savant3::template()
    Savant2::setError()     ~= Savant3::setErrorType()
    Savant2::loadPlugin()   ~= Savant3::setPluginConf()
    Savant2::loadFilter()   ~= Savant3::addFilters()
    Savant2::plugin('xxxx') ~= Savant3::xxxx()

Savant: Why Plugins?

A good question from the Savant-Talk list today. The quote is from the questioner, and the remainder is my response (almost verbatim from the list).

But could You PLS explain me shortly the main idea of plugins? I mean I can not understand that there is a need to create for example any html form fields by php... I still see the idea of templates as separation of business logic from display logic. From my point of view such example form fields shoud be still in template but not generated by php. So maybe such ones should be provided quite so as a templates or something like that. Only the values should come to them.

Well my wonders goes farther - why to use ANY php or savant function INSIDE template...(?)

First off, use of plugins is not required, of course, so if you don't like them you don't need to use them. This is kind of a weak argument, I know, because the code for plugin support is there whether you like it or not -- in Savant3 this will end up being about 30 lines (with comments it's about 50 lines), which I think is very small for the power you can get from them.

But second, and more importantly, they are convenient time-savers. I completely agree with you when you say you "see the idea of templates as separation of business logic from display logic." To that, I say: a plugin is just an encapsulated, reusable portion of display logic. It gets tiresome to write forms by hand all the time. Instead of *having* to write a select box by looping through options passed in as an assigned variable, and mixing the PHP echo code with the literal HTML, you can use one line in the template to call the 'form' plugin and generate a select box with correct items pre-selected for you.

One argument against plugins is that they are not a necessary component of a template engine; if you want convenience methods, you can instantiate your own output objects and assign them to the template, or write them as global functions, or call them as static class methods. This is a perfectly valid argument. However, to my mind, that kind of thing is a "pattern" of development, and will end up looking nearly the same across all implementations. All that Savant does is take the common aspects of that pattern and codify them for common use so that different developers can collaborate easily and effectively using the same higher-level tool set.

This is not a comprehensive defense of plugins, but I hope this brief essay begins to show why plugins can be useful and worthwhile in a template system.