Object oriented Web-UI in PHP

28 Feb 2009

Are you familiar with one of these fancy rich-client GUI toolkits? GTK+, Qt, SWT, you name it. They provide nice bridge between what user and programmer see. One would notice that HTML is itself UI platform with all this links, form controls, and JavaScript events. I can't disagree on that, but there's definitely more that could be done to push it more toward high level API rather than low level mark-up to make writing applications easier.

The idea I'm going to present is founded on the elegance and object orientation of SWT I've had chance to work with ages ago. The main goal is to create convenient API to avoid manual HTML/JavaScript coding.

Start holistic

Instead of specing out list of requirements, I'll just write piece of code I'd love to work with – my idealistic way of doing things. This is somewhat holistic approach that may be more appropriate for religion rather than software engineering, but down the line we will get to details.

$login = new Input();
$login->setValue(@$_POST['login']);
$passwd = new PasswordInput();
$button = new SubmitButton();

$form = new Form();
$form->template = 'login-form.tpl';
$form->target = ...some-url...;
$form->add($login)->add($passwd)->add($button);

print($form);
Very basic Web-UI API example

So far so good. We have fairly understandable object oriented API, now it is time to define events. In SWT each listener requires action adapter. Such adapter is most often defined as anonymous subclassed object. Since in web environment most actions is basically described by URL, we don't need action adapter. At least not just yet.

$forgot = new Button();
$forgot->text = 'Forgot my password';
$forgot->addListener(new ClickListener(...some-url...));
$form->add($forgot);
Listener demo

Now, our fancy OO API supports handling events. onclick in this case, but virtually any other is possible. Now what about reading form fields? After user had typed in her name and clicked Forgot button the application should read that name and pass it in URL. Obviously you can't do it on server side, or can you?

$forgot->addListener(
	new ClickListener(
		...some-url... . '?login=' . $login->valueReader()
	)
);
Value reader can be used to read form fields on client-side.

Now what the heck is valueReader()? Think of it as of proxy object for querying form fields on client side. In reality it's not an object (although it could be one implementing __toString() method) it's just a piece of inline JavaScript that gets DOM element by id and returns value property. Since ClickListener generates onclick string it plays nicely with value reader.

So yeah, get by id. But what is the id? I don't know. It should be automatically generated, shouldn't it? Yes, that would help, however I'd rather generate it automaticaly only when not passed to view constructor. This way you can specify id by hand if you need to. But this id thing is a minor problem.

Now consider signup form with more events, listeners, and actions madness. Do you know this nice feature that as you type your login name it checks on the fly if it's available? Surely, we c4n haz t4ht too!

$login = new Input();
$login->addListener(
	new StopTypingListener(
		...some-url... . '?login=' . $login->valueReader()
	)
);

StopTypingListener is (allegedly) listener that triggers action only when user has stopped typing for certain amount of time. In this example it fires event for checking whether username is free or taken. But wait a minute, you can't just reload whole page when user is half way through the form! Obviously, this needs to be Ajax call and here's where you actually do need action adapter.

$login->addListener(
	new StopTypingListener(
		new Action(
			...some-url... . '?login=' . $login->valueReader(),
			...callback-name...
		)
	)
);
Ajax action adapter example

Tada. Done Ajax way. Now, it's very likely you have your head full of question marks. How is this all implemented?

And now something for reductionists

It is important to state that in above examples I rely heavily on PHP's ability to cast objects to strings. Doing so with __toString() method frees your code from litter otherwise caused by manual casting. Let's just track which object returns what when cast to string.

Fear, Uncertainty, and Doubt

Developers, mostly those of little exposure to real life in its whole brutality, tend to raise alarm that having such heavywight API is, uhm, heavy. I have only one answer to that: Like I care! Iron is cheap, programmers' time is not (sorry guys, this reads in Polish). So go and get more memory for your box, or don't and waste more time tinkering with low lever/lightweight API you like more.

So where can I get this from?

Recent activity on Stackoverflow.com brought back my faith in Tigermouse framework I started years ago. Just play with it for a while, see examples, download, have fun, delete or take over further development of the framework as I have no time to do it any more. Oh, please use SVN version of it, as the last official release is terribly outdated.

Digg del.icio.us StumbleUpon Wykop Reddit Folksr

permalink | trackback | rss

 
 
Wasacz

'onclick' is not a listener, to be strict.

stronger

Wasacz, sure it is not, but don't really know where do I imply it is. Can you advise?

Wasacz

Maybe that 'Listeners' mentioned time after time were just a part of my imaginations.

Your turn:

nick:
and?:
www (if any):
Wpisz kod:code
Object oriented Web-UI in PHP php oop gui web-ui tigermouse