[PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Ryan Panning
I have discovered that when I foreach over a RecursiveDirectoryIterator 
(see example below) the $item actually turns into a SplFileInfo object. 
I would expect it to be a RecursiveDirectoryIterator. How do I do a 
hasChildren() on SplFileInfo?


However, if I change it to a non-recursive, DirectoryIterator, $item is 
what I would expect, DirectoryIterator. I've tested this with 5.2.8 and 
5.3b1. I'm guessing this is an issue with my setup as I'm sure I've 
gotten this to work before...



$dir = new RecursiveDirectoryIterator('/path/to/dir');
foreach ($dir as $item) {
print get_class($item) . \r\n;
}

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Philip Graham
Here's a RecursiveDirectoryIterator class I've written and find quite useful:

?php
/**
 * This class encapsulates an iterator that iterates over all the files in a
 * directory recursively.  Only files that don't begin with a '.' are included
 * in this iteration.  This class essentially wraps an SPL DirectoryIterator
 * object and returns each file in the iteration as an SplFileInfo.
 *
 * @author a href=mailto:phi...@lightbox.org;Philip Graham/a
 */
class Util_RecursiveFileIterator implements Iterator {
CONST SHOW_DOT_FILES = true;

private $_basePath;
private $_curDirIter;
private $_dirStack;
private $_showDots;

/**
 * Constructor.  By default the iteration will skip any files that begin
 * with a '.' character but this can be changed by passing the class
 * constant SHOW_DOT_FILES as the second parameter.
 *
 * @param string $basePath - The base path of the directory to iterate 
over
 * @param boolean $showDots - Whether or not to include files that begin
 * with a '.' character in the iteration.
 */
public function __construct($basePath, $showDots = false) {
// PREPARE ... THE ... HUMANOID
if(!is_dir($basePath)) {
$basePath = dirname($basePath);
}
if(!$basePath) {
$basePath = '.';
}
// If the given path is relative this function will transform it
// into an equivalent path.  This call assumes that the relative path
// is relative to the file that created this iterator.
$this-_basePath = Util_File::getAbsolutePath($basePath, 2);

$this-_showDots = $showDots;

}

/**
 * Returns the current value of the iteration
 *
 * @return FileInfoInfo
 */
public function current() {
return $this-_curDirIter-current();
}

/**
 * Returns the index of the current entry.
 *
 * @return string
 */
public function key() {
$curPath = $this-_curDirIter-getPathname();
$relativeToBase = substr($curPath, strlen($this-_basePath));
return $relativeToBase;
}

/**
 * Moves the directory iterator to the next element of the iteration.
 */
public function next() {
$this-_curDirIter-next();
$good = false;
while(!$good) {
if(!$this-_curDirIter-valid()) {
if(count($this-_dirStack) == 0) {
$good = true;
} else {
$this-_curDirIter = array_pop($this-_dirStack);
}
} else if($this-_curDirIter-isDot()) {
if(!$this-_showDots) {
$this-_curDirIter-next();
} else {
$good = true;
}
} else if(!$this-_showDots 
  substr($this-_curDirIter-getFileName(), 0, 1) == '.') {
$this-_curDirIter-next();
} else if($this-_curDirIter-isDir()) {
// Create a new iterator for the sub-dir
$newIter = new DirectoryIterator(
$this-_curDirIter-getPathname());

// Make sure the current iterator is ready to go when it
// gets popped off the stack
$this-_curDirIter-next();

// Push it... push it real good
array_push($this-_dirStack, $this-_curDirIter);

// Set the new iterator
$this-_curDirIter = $newIter;
} else {
$good = true;
}
}
}

/**
 * Resets the iterator to first file in the object's base path.
 */
public function rewind() {
$this-_curDirIter = new DirectoryIterator($this-_basePath);
$this-_dirStack = array();
if(!$this-_showDots  $this-_curDirIter-isDot()) {
$this-next();
}
}

/**
 * Returns a boolean indicating wether or not there are anymore elements 
left
 * in the iteration.
 */
public function valid() {
return $this-_curDirIter-valid();
}
}

Usage:

$dirIter = new Util_RecursiveFileIterator('/path/to/directory');
foreach($dirIter AS $fileName = $fileInfo) {
  // $fileName is the basename of the file and $fileInfo is a SplFileInfo
  // for the file
}

Hope this helps!


On February 23, 2009 11:31:04 Ryan Panning wrote:
 I have discovered that when I foreach over a RecursiveDirectoryIterator
 (see example below) the $item actually turns into a SplFileInfo object.
 I would expect it to be a RecursiveDirectoryIterator. How do I do a
 hasChildren() on SplFileInfo?

 However, if I change it to a non-recursive, DirectoryIterator, $item is
 what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
 5.3b1. I'm guessing this is an issue with my setup as I'm sure I've
 gotten this to work before...


 $dir = new RecursiveDirectoryIterator('/path/to/dir');
 foreach ($dir as $item) {
  print 

Re: [PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Nathan Nobbe
On Mon, Feb 23, 2009 at 9:31 AM, Ryan Panning rpann...@gmail.com wrote:

 I have discovered that when I foreach over a RecursiveDirectoryIterator
 (see example below) the $item actually turns into a SplFileInfo object. I
 would expect it to be a RecursiveDirectoryIterator. How do I do a
 hasChildren() on SplFileInfo?

 However, if I change it to a non-recursive, DirectoryIterator, $item is
 what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
 5.3b1. I'm guessing this is an issue with my setup as I'm sure I've gotten
 this to work before...


 $dir = new RecursiveDirectoryIterator('/path/to/dir');
 foreach ($dir as $item) {
print get_class($item) . \r\n;
 }


if youre trying to do recursive iteration whereby you 'flatten' the tree
structure, drop the RecursiveDirectoryIterator into a
RecursiveIteratorIterator (its for iterating over RecursiveIterators), then
you dont have to bother w/ calling hasChildren() at all.  you probly also
want to look at the constructor args, since by default, it only returns leaf
nodes.

$dir = new RecursiveDirectoryIterator('/path/to/dir');

$itt = new RecursiveIteratorIterator($dir,
RecursiveIteratorIterator::CHILD_FIRST);

 foreach ($itt as $item) {
print get_class($item) . \r\n;
 }


-nathan


Re: [PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Ryan Panning

Nathan Nobbe wrote:

if youre trying to do recursive iteration whereby you 'flatten' the tree
structure, drop the RecursiveDirectoryIterator into a
RecursiveIteratorIterator (its for iterating over RecursiveIterators), then
you dont have to bother w/ calling hasChildren() at all.  you probly also
want to look at the constructor args, since by default, it only returns leaf
nodes.

$dir = new RecursiveDirectoryIterator('/path/to/dir');

$itt = new RecursiveIteratorIterator($dir,
RecursiveIteratorIterator::CHILD_FIRST);


foreach ($itt as $item) {
   print get_class($item) . \r\n;
}



-nathan



Hi, thanks for the idea. In my case I do not want to flatten the tree. 
When there is a sub-directory I make a repeat call to the 
function/method, there-by calling it for each directory. I'd give you 
more details but I don't think it'd help with this specific issue.


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Ryan Panning

Philip Graham wrote:

Here's a RecursiveDirectoryIterator class I've written and find quite useful:

?php
/**
 * This class encapsulates an iterator that iterates over all the files in a
 * directory recursively.  Only files that don't begin with a '.' are included
 * in this iteration.  This class essentially wraps an SPL DirectoryIterator
 * object and returns each file in the iteration as an SplFileInfo.
 *
 * @author a href=mailto:phi...@lightbox.org;Philip Graham/a
 */
class Util_RecursiveFileIterator implements Iterator {
CONST SHOW_DOT_FILES = true;

private $_basePath;
private $_curDirIter;
private $_dirStack;
private $_showDots;

/**
 * Constructor.  By default the iteration will skip any files that begin
 * with a '.' character but this can be changed by passing the class
 * constant SHOW_DOT_FILES as the second parameter.
 *
 * @param string $basePath - The base path of the directory to iterate 
over

 * @param boolean $showDots - Whether or not to include files that begin
 * with a '.' character in the iteration.
 */
public function __construct($basePath, $showDots = false) {
// PREPARE ... THE ... HUMANOID
if(!is_dir($basePath)) {
$basePath = dirname($basePath);
}
if(!$basePath) {
$basePath = '.';
}
// If the given path is relative this function will transform it
// into an equivalent path.  This call assumes that the relative path
// is relative to the file that created this iterator.
$this-_basePath = Util_File::getAbsolutePath($basePath, 2);

$this-_showDots = $showDots;

}

/**
 * Returns the current value of the iteration
 *
 * @return FileInfoInfo
 */
public function current() {
return $this-_curDirIter-current();
}

/**
 * Returns the index of the current entry.
 *
 * @return string
 */
public function key() {
$curPath = $this-_curDirIter-getPathname();
$relativeToBase = substr($curPath, strlen($this-_basePath));
return $relativeToBase;
}

/**
 * Moves the directory iterator to the next element of the iteration.
 */
public function next() {
$this-_curDirIter-next();
$good = false;
while(!$good) {
if(!$this-_curDirIter-valid()) {
if(count($this-_dirStack) == 0) {
$good = true;
} else {
$this-_curDirIter = array_pop($this-_dirStack);
}
} else if($this-_curDirIter-isDot()) {
if(!$this-_showDots) {
$this-_curDirIter-next();
} else {
$good = true;
}
} else if(!$this-_showDots 
  substr($this-_curDirIter-getFileName(), 0, 1) == '.') {
$this-_curDirIter-next();
} else if($this-_curDirIter-isDir()) {
// Create a new iterator for the sub-dir
$newIter = new DirectoryIterator(
$this-_curDirIter-getPathname());

// Make sure the current iterator is ready to go when it
// gets popped off the stack
$this-_curDirIter-next();

// Push it... push it real good
array_push($this-_dirStack, $this-_curDirIter);

// Set the new iterator
$this-_curDirIter = $newIter;
} else {
$good = true;
}
}
}

/**
 * Resets the iterator to first file in the object's base path.
 */
public function rewind() {
$this-_curDirIter = new DirectoryIterator($this-_basePath);
$this-_dirStack = array();
if(!$this-_showDots  $this-_curDirIter-isDot()) {
$this-next();
}
}

/**
 * Returns a boolean indicating wether or not there are anymore elements 
left

 * in the iteration.
 */
public function valid() {
return $this-_curDirIter-valid();
}
}

Usage:

$dirIter = new Util_RecursiveFileIterator('/path/to/directory');
foreach($dirIter AS $fileName = $fileInfo) {
  // $fileName is the basename of the file and $fileInfo is a SplFileInfo
  // for the file
}

Hope this helps!


Hi, although I don't think this will work in my situation, there is an 
interesting piece of code that you have.


array_push($this-_dirStack, $this-_curDirIter);

Are you able to inject the iterator with more items? I would like to 
do this with the RecursiveDirectoryIterator where-by I inject fake 
files into the iterator. Is this what you're doing here?


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Philip Graham
On February 23, 2009 12:32:26 Ryan Panning wrote:
 Hi, although I don't think this will work in my situation, there is an
 interesting piece of code that you have.

 array_push($this-_dirStack, $this-_curDirIter);

 Are you able to inject the iterator with more items? I would like to
 do this with the RecursiveDirectoryIterator where-by I inject fake
 files into the iterator. Is this what you're doing here?

Yes, in essence that is what this is doing but I am not manipulating the 
DirectoryIterator objects.  I am instead using my own structure and logic to 
do this.

Basically I'm using normal (i.e flat) DirectoryIterator objects but when I 
encounter a sub directory, I instantiate another DirectoryIterator for the 
sub-directory to continue the iteration.  In order to remember where I was 
once I've finished iterating over the sub-directory the current iterator is 
pushed onto a stack.  Then once the iteration of the sub-directory is finished 
the iterator for the parent directory is popped off the stack and the 
iteration over that directory continues from where it was interrupted.

Does this explanation satisfy your question?


-- 
Philip Graham
Lightbox Technologies
Suite 312 240 Catherine St.
Ottawa, ON, K2P 2G8
613-686-1661 ext. 102

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP] RecursiveDirectoryIterator and foreach

2009-02-23 Thread Nathan Nobbe
On Mon, Feb 23, 2009 at 10:27 AM, Ryan Panning rpann...@gmail.com wrote:

 Nathan Nobbe wrote:

 if youre trying to do recursive iteration whereby you 'flatten' the tree
 structure, drop the RecursiveDirectoryIterator into a
 RecursiveIteratorIterator (its for iterating over RecursiveIterators),
 then
 you dont have to bother w/ calling hasChildren() at all.  you probly also
 want to look at the constructor args, since by default, it only returns
 leaf
 nodes.

 $dir = new RecursiveDirectoryIterator('/path/to/dir');

 $itt = new RecursiveIteratorIterator($dir,
 RecursiveIteratorIterator::CHILD_FIRST);

  foreach ($itt as $item) {
   print get_class($item) . \r\n;
 }



 -nathan


im not sure i fully understand the problem, but from the sound of it, as a
work-around, why not something like this,

$dirIt = new RecursiveDirectoryIterator($path);
foreach($dirIt as $item) {
  if($item-isDir()) {
$subdir = new RecursiveDirectoryIterator($item);
// now you have the RecursiveDirectoryIterator you wanted ??
  }
}

-nathan