I spent some time looking at SPL and iterators, especially the RecursiveIterator part and I am puzzled on how to implement this for QF2_Group. It could be nice to extend ArrayObject which add array features to collection objects like Group, but Group will already extend HTML_Common2 and since there is no multiple inheritance or mixins in PHP, I don't know what to do.
Do you have any idea about this ? Do we need to use SPL at all ?
Here is the class declaration I thought about:
class HTML_QuickForm2_Group extends HTML_Common2 implements IteratorAggregate protected $elements = array(); public function getIterator() { return new GroupIterator($this); } public function getElements() { return $this->elements; } public function toHtml() { return $this->__toString(); } public function __toString() { return 'group: '.$this->name."\n"; } } class GroupIterator extends RecursiveArrayIterator implements RecursiveIterator { public function __construct(HTML_QuickForm2_Group $group) { parent::__construct($group->getElements()); } public function hasChildren() { return $this->current() instanceof HTML_QuickForm2_Group; } public function getChildren() { return new GroupIterator($this->current()); } } class HTML_QuickForm2_Element { protected $name = ''; public function __construct($name) { $this->name = $name; } public function __toString() { return 'element: '.$this->name."\n"; } } $g1 = new HTML_QuickForm2_Group('g1'); $g1->append(new HTML_QuickForm2_Element('el1')); $g1->append(new HTML_QuickForm2_Element('el2')); $g2 = new HTML_QuickForm2_Group('g2'); $g2->append(new HTML_QuickForm2_Element('el1_2')); $g2->append(new HTML_QuickForm2_Element('el2_2')); $g1->append($g2); $g1->append(new HTML_QuickForm2_Element('el3'));
By the way, there is no need IMO to extend HTML_QF2_Element. Like in a tree, you have nodes (the elements) and containers (the groups), I think it makes it easier to differenciate both.
Then, since we implement IteratorAggregate, we can provide a getIterator() method the returns a RecursiveArrayIterator extension.
If we want to use a recursive foreach() loop on a Group, we can then use a RecursiveIteratorIterator like this:
$it = new RecursiveIteratorIterator($g1, RecursiveIteratorIterator::SELF_FIRST); foreach ($it as $el) { echo $el; }
This means we have to write a GroupIterator class.
Do you have a better idea ?
— Bertrand Mansion 2006-06-29 13:14
As you may have already noticed, I'm not a huge fan of adding the array access features to QuickForm classes (except maybe for HTML_QuickForm2_Datasource). They add quite a bit of ambiguity (do we access attributes or children? do we access children by name or by id?). Having iterators and a DOM-like API is IMO a bit cleaner.
You are right about the need to have a RecursiveIterator since we can nest Containers (the most obvious thing is that the Form itself is a container), I completely missed this when I did the mockup of HTML_QuickForm2_Container. Will try to wrap my head around this Recursive stuff…
Unfortunately we'll need methods defined in Element for most of the Containers: getName()/setName(), accept(), etc.
— Alexey Borzov, 2006-06-29 20:33 MSD