Using Generators in Agile Toolkit

#1

PHP5.5 have some nice new features including Generators. When combined with Iterators they can be used for some really awesome stuff in Agile Toolkit.

Suppose you want to display contents of a folder in grid. Currently you would need to get folder structure (as an array) and then pass it into Grid as setSource(). But Grids and Lister also support iterators, and here how you can use them:

$g = $this->add('Grid');
$g->addColumn('name');
$g->addColumn('size');

$g->setSource(call_user_func(function(){
        yield ['name'=>'Hello', 'size'=>123];
        yield ['name'=>'World', 'size'=>321];
}));

So what happens? When PHP executes a method and finds “yield” keyword it automatically returns a generator. Generator is like a sequence which you can foreach() through (see http://php.net/manual/en/language.generators.syntax.php)

You can actually combine that with Iterators to do something useful:

$g = $this->add('Grid');
$g->addColumn('name');
$g->addColumn('size');
$g->setSource(call_user_func(function()use($path){
    foreach(
        new \CallbackFilterIterator(
            new \DirectoryIterator($path),
            function($f){
                return !$f->isDot() && $f->getExtension()=='php';
            }
       ) as $k=>$i){
        yield $k=>['name'=>(string)$i, 'size'=>$i->getSize()];
    }
}));

This code will read files from folder, skip dots and only display files with php extension, then use Generator to format output as an array, which Grid can recognise.

I am thinking about adding few more usage patterns into ATK:

  1. Ability to pass Closures to setSource(). The closure will be lazily executed during render and it’s return will be used instead.
  2. Ability to specify Closures as grid formatters.

Those will make it even easier to use generators:

$g = $this->add('Grid');
$g->addColumn('name');
$g->addColumn('size');
$g->setSource(function(){
        yield ['name'=>'Hello', 'size'=>123];
        yield ['name'=>'World', 'size'=>321];
});

and

$g = $this->add('Grid');
$g->setSource(new \CallbackFilterIterator(new \DirectoryIterator($path),
     function($f){ return !$f->isDot() && $f->getExtension()=='php'; }));
$g->addColumn(function($row){ return (string)$row; }, 'name');
$g->addColumn(function($row){ return $row->getSize(); }, 'size');

This syntax should be possible in ATK 4.3.1 (or master) if you are using PHP5.5.

1 Like
#2

Great Idea, But I would love to have this 5.5+ feature in a 4.3.1 (seperate branch) as master is currently compatible with php 5.3.

5.3, I think should be maintained a bit longer.

#3

You can use 5.5 constructs with Agile Toolkit while it remains 5.3 compatible. The documentation uses up-to-date PHP semantics however the framework itself is 5.3 friendly.