From 528be1ee796d25fa50c2f736fd57302d24945893 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 30 Mar 2016 15:26:24 +0200 Subject: [PATCH] doc: Iterate files alphabetically and directories last --- library/Icinga/Util/DirectoryIterator.php | 100 +++++++++++++++------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/library/Icinga/Util/DirectoryIterator.php b/library/Icinga/Util/DirectoryIterator.php index 3addbd2bb..472899b2f 100644 --- a/library/Icinga/Util/DirectoryIterator.php +++ b/library/Icinga/Util/DirectoryIterator.php @@ -3,14 +3,22 @@ namespace Icinga\Util; +use ArrayIterator; use InvalidArgumentException; -use Iterator; +use RecursiveIterator; /** * Iterator for traversing a directory */ -class DirectoryIterator implements Iterator +class DirectoryIterator implements RecursiveIterator { + /** + * Iterate files first + * + * @var int + */ + const FILES_FIRST = 1; + /** * Current directory item * @@ -26,11 +34,18 @@ class DirectoryIterator implements Iterator protected $extension; /** - * Directory handle + * Scanned files * - * @var resource + * @var ArrayIterator */ - private $handle; + private $files; + + /** + * Iterator flags + * + * @var int + */ + protected $flags; /** * Current key @@ -46,6 +61,13 @@ class DirectoryIterator implements Iterator */ protected $path; + /** + * Directory queue if FILES_FIRST flag is set + * + * @var array + */ + private $queue; + /** * Whether to skip empty files * @@ -72,8 +94,9 @@ class DirectoryIterator implements Iterator * * @param string $path The path of the directory to traverse * @param string $extension The file extension to filter for. A leading dot is optional + * @param int $flags Iterator flags */ - public function __construct($path, $extension = null) + public function __construct($path, $extension = null, $flags = null) { if (empty($path)) { throw new InvalidArgumentException('The path can\'t be empty'); @@ -82,6 +105,9 @@ class DirectoryIterator implements Iterator if (! empty($extension)) { $this->extension = '.' . ltrim($extension, '.'); } + if ($flags !== null) { + $this->flags = $flags; + } } /** @@ -96,6 +122,23 @@ class DirectoryIterator implements Iterator return is_dir($path) && is_readable($path); } + /** + * {@inheritdoc} + */ + public function hasChildren() + { + return static::isReadable($this->current); + } + + /** + * {@inheritdoc} + */ + public function getChildren() + { + return new static($this->current, $this->extension, $this->flags); + } + + /** * {@inheritdoc} */ @@ -110,12 +153,14 @@ class DirectoryIterator implements Iterator public function next() { do { - $file = readdir($this->handle); - if ($file === false) { - $key = false; + $this->files->next(); + $skip = false; + if (! $this->files->valid()) { + $file = false; + $path = false; break; } else { - $skip = false; + $file = $this->files->current(); do { if ($this->skipHidden && $file[0] === '.') { $skip = true; @@ -125,7 +170,10 @@ class DirectoryIterator implements Iterator $path = $this->path . '/' . $file; if (is_dir($path)) { - $skip = true; + if ($this->flags & static::FILES_FIRST === static::FILES_FIRST) { + $this->queue[] = array($path, $file); + $skip = true; + } break; } @@ -138,16 +186,18 @@ class DirectoryIterator implements Iterator $skip = true; break; } - - $key = $file; - $file = $path; } while (0); } } while ($skip); - $this->current = $file; /** @noinspection PhpUndefinedVariableInspection */ - $this->key = $key; + + if ($path === false && ! empty($this->queue)) { + list($path, $file) = array_shift($this->queue); + } + + $this->current = $path; + $this->key = $file; } /** @@ -171,21 +221,11 @@ class DirectoryIterator implements Iterator */ public function rewind() { - if ($this->handle === null) { - $this->handle = opendir($this->path); - } else { - rewinddir($this->handle); + if ($this->files === null) { + $this->files = new ArrayIterator(scandir($this->path)); } + $this->files->rewind(); + $this->queue = array(); $this->next(); } - - /** - * Close directory handle if created - */ - public function __destruct() - { - if ($this->handle !== null) { - closedir($this->handle); - } - } }