Iterators for HTML_QuickForm2_Group

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

 
using_iterators.txt · Last modified: 2008/06/03 19:42 (external edit)