I found a couple of questions (this one and this question) related to the SPL iterators, but I'm not sure if they're helpful in my case, as I'm using a rather high level extension of the RecursiveIteratorIterator
; the DirectoryTreeIterator
.
Could somebody perhaps show me how to alter the DirectoryTreeIterator
or how to sort the returned array per directory after it has been outputted by the iterator?
A method of sorting the files correctly directly on the Apache server is also an option for me, if it's possible using .htaccess
for example.
This is the code of DirectoryTreeIterator
from the SPL:
/** @file directorytreeiterator.inc
* @ingroup Examples
* @brief class DirectoryTreeIterator
* @author Marcus Boerger
* @date 2003 - 2005
*
* SPL - Standard PHP Library
*/
/** @ingroup Examples
* @brief DirectoryIterator to generate ASCII graphic directory trees
* @author Marcus Boerger
* @version 1.1
*/
class DirectoryTreeIterator extends RecursiveIteratorIterator
{
/** Construct from a path.
* @param $path directory to iterate
*/
function __construct($path) {
parent::__construct(
new RecursiveCachingIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME
),
CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD
),
parent::SELF_FIRST
);
}
/** @return the current element prefixed with ASCII graphics
*/
function current() {
$tree = '';
for ($l=0; $l < $this->getDepth(); $l++) {
$tree .= $this->getSubIterator($l)->hasNext() ? ' ' : ' ';
}
return $tree . ($this->getSubIterator($l)->hasNext() ? ' ' : ' ')
. $this->getSubIterator($l)->__toString();
}
/** Aggregates the inner iterator
*/
function __call($func, $params) {
return call_user_func_array(array($this->getSubIterator(), $func), $params);;
}
}
To clarify why I'm using the code above is because it fits my needs exactly. I want to generate a recursive directory tree prefixed by whitespaces - the original code example by Marcus Boerger adds some ASCI elements. The problem is I don't have control over the sorting of files and directories, so I would like the directory tree to appear like this:
dir001
subdir001
subdir002
subfile001.jpg
file001.png
fi开发者_Python百科le002.png
file003.png
dir002
apple.txt
bear.txt
contact.txt
dir003
[...]
Instead, the listings returned by the iterator isn't sorted at all and it shows me something like this:
dir002
bear.txt
apple.txt
contact.txt
dir001
subdir001
subdir002
subfile001.jpg
file002.png
file001.png
file003.png
dir003
[...]
So I guess the solution I'm looking for is some way to call a sort method every time a subdirectory is indexed and added to the directory tree.
I hope I've made it somewhat clearer, as a nonnative speaker it's sometimes hard to put thoughts into coherent sentences (or even words for that matter).
Well, I'm not sure where you got that class from, but it's doing some pretty messed up things (including a few bugs to say the least). And while it uses SPL, it's not an SPL class.
Now, I'm not 100% sure what you mean by "sort", but assuming you're talking about a natural sort, why not just flatten an array, and then sort it?
$it = new RecursiveTreeIterator(
new RecrusiveDirectoryIterator($dir),
RecursiveTreeIterator::BYPASS_KEY,
CachingIterator::CALL_TOSTRING
);
$files = iterator_to_array($it);
natsort($files);
echo implode("\n", $files);
or
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::SELF_FIRST
);
$files = iterator_to_array($it);
$files = array_map(function($file) { return (string) $file; }, $files);
natsort($files);
echo implode("\n", $files);
Edit: Based on your edit, here's how I would solve it:
function BuildTree($it, $separator = ' ', $level = '') {
$results = array();
foreach ($it as $file) {
if (in_array($file->getBasename(), array('.', '..'))) {
continue;
}
$tmp = $level . $file->getBaseName();
if ($it->hasChildren()) {
$newLevel = $level . $separator;
$tmp .= "\n" . BuildTree($it->getChildren(), $separator, $newLevel);
}
$results[] = $tmp;
}
natsort($results);
return implode("\n", $results);
};
$it = new RecursiveDirectoryIterator($dir);
$tree = BuildTree($it);
It's a pretty simple recursive parser, and does the natural sort on each level.
Don't know about SPL iterators, but for your iterator you should put the items in an array, then sort them and add them to $tree. I modified the function current but didn't test it:
function current()
{
$tree = '';
$treeitems = array();
for ($l=0; $l < $this->getDepth(); $l++) {
//NOTE: On this line I think you have an error in your original code:
// This ? ' ' : ' ' is strange
$treeitems[] = $this->getSubIterator($l)->hasNext() ? ' ' : ' ';
}
$treeitems.sort();
for each ($treeitems as $treeitem)
$tree .= $treeitem;
return $tree . ($this->getSubIterator($l)->hasNext() ? ' ' : ' ')
. $this->getSubIterator($l)->__toString();
}
精彩评论