Page 1 of 1

Dynamic forms based on VO/DTO & Type-map

Posted: Wed Jan 10, 2007 11:29 am
by xinnex
I'm currently in the process of redesigning a PHP5 framework which so far has been mimicking things like CakePHP or Symfony (not using Active Record!)

So far we've been using the DAO-pattern and simply passed our VO/DTO-objects directly from the controller to the view.
This lead to extremely fast development since we could do things like:

In the controller:

Code: Select all

$this->posts = $postDAO->findAll();
Int the view:

Code: Select all

foreach($posts as $post)
{
	$this->add(new Headline($post->getTitle));
}
Problems arise though, when the VO/DTO-objects change and the views subsequently has to be updated.
Obviously the views are too dependent on the VO's methods... so what to do?

"A generic model which could be iterated in the view", you say?

But what about the forms?.. We'll.. We probably all know how boring it can be to design forms.
So how about this approach?:

VO/DTO:

Code: Select all

class Customer
{
	private $id;
	private $name;

	public function setId($id)
	{
		$this->id = $id;
	}
	public function getId()
	{
		return $this->id;
	}
	public function setName($name)
	{
		$this->name = $name;
	}
	public function getName()
	{
		return $this->name;
	}
}
Type-map (maps matching getters/setters in the VO/DTO):

Code: Select all

class CustomerControlMap extends BaseControlMap
{
	private $maps;
	public function __construct()
	{
		$this->maps = array();
		$this->maps['name'] = new TextField();
		$this->maps['id'] = new HiddenField();
	}
	public function getMap($fieldName)
	{
		return $this->maps[$fieldName];
	}
}
Converts a customer to a list-object (using "get_class_methods()" in the DynamicListAdapter-class):

Code: Select all

class CustomerList extends DynamicListAdapter
{
	public function __construct(Customer $customer)
	{
		parent::__construct($customer);
	}
	public function getList()
	{
		return parent::getList();
	}
}
Imaginary form-generator call:

Code: Select all

$list = new CustomerList(new Customer());
$form = FormGenerator::generate($list->getList(), new CustomerControlMap());
$form->setAction('action.php');
$form->setMethod('post');
Resulting in a Form-object with a TextField and HiddenField as its children, which could be outputted like:

Code: Select all

<form method="post" action="action.php">
 <input type="hidden" name="id" />
 ...
</form>
This way the view (with the formgenerator-call) is only coupled with the type-map.
So when the VO/DTO changes, you would only have to update the Type-map.

Thoughts, critics (and "HERESY!"-claims) appreciated, and sorry for the long post.

Posted: Wed Jan 10, 2007 5:34 pm
by xinnex
Maybe people are intimidated by the long post, so I'll rephrase it a bit:

How would you deal with dynamic form-generation, preferably in an OO-fashion?

Posted: Wed Jan 10, 2007 7:01 pm
by Ollie Saunders
You'd use my form's library, OsisForms :D

Alpha will be out within a week. Source code is available for viewing now on sourceforge. After that there's a possibly it'll become part of the Zend Framework. Till then there's a form component in the Zebra PHP framework and Cake. I looked at Zebra in some depth. You write form templates and define your own 'error blocks' you then attach validations to widgets.

Dedicated libraries are patForms (quite powerful, design ok, complex) and QuickForm (moderate power, not well designed, good community backing). None of the above are robust enough for web application level form requirements but if you have less rigorous requirements they might be enough.

My library is different in that it is a flexibly, powerful, oo api that can be easily extended. The fundamentals of the library aren't even tied to HTML / HTTP POST as you can write your own renderers and retrievers. Validation system is extendible and loosely coupled from the rest of the library. I could go on.

Posted: Wed Jan 10, 2007 7:13 pm
by xinnex
ole wrote: My library is different in that it is a flexibly, powerful, oo api that can be easily extended. The fundamentals of the library aren't even tied to HTML / HTTP POST as you can write your own renderers and retrievers. Validation system is extendible and loosely coupled from the rest of the library. I could go on.
Looks very interesting. Could you point me to a "getting started"- or a "crash course"-like resource for it?
I browsed through the documentation in svn, but it was somewhat.. erh.. not-there-like? Pretty UML though :wink:

Posted: Wed Jan 10, 2007 7:25 pm
by Ollie Saunders
Umm yeah... :oops:

I wrote a whole load of docs for it and then I changed so much that it no longer applied so you're gonna have to wait I'm afraid.

Posted: Wed Jan 10, 2007 8:04 pm
by xinnex
A quick example would probably be sufficient... (maybe something you've posted around here?.. I'll look around)

Posted: Wed Jan 10, 2007 8:06 pm
by Christopher
I think the next step from you scheme is to build an actual form controller. The your control maps can be on a field by field by field basis and you can attach as many fields as needed and define them as you do it. So you might end up with somthing like:

Code: Select all

$customerform->addMap('name', new TextField());
$customerform->addMap('id', new HiddenField());

Posted: Wed Jan 10, 2007 8:06 pm
by Ollie Saunders
Sadly no. I don't have a factory class yet either so I can't show you anything. Sorry, you will have to wait that full week.

Posted: Wed Jan 10, 2007 8:29 pm
by xinnex
arborint wrote:I think the next step from you scheme is to build an actual form controller. The your control maps can be on a field by field by field basis and you can attach as many fields as needed and define them as you do it. So you might end up with somthing like:

Code: Select all

$customerform->addMap('name', new TextField());
$customerform->addMap('id', new HiddenField());
Any resources on such a formcontroller, or just a quick mockup? Much appreciated input..

EDIT: I'm trying to come up with an approach that requires a minimum of effort to maintain/update.