Вход Регистрация
Файл: framework/filesystem/FileFinder.php
Строк: 267
<?php
/**
 * A utility class that finds any files matching a set of rules that are
 * present within a directory tree.
 *
 * Each file finder instance can have several options set on it:
 *   - name_regex (string): A regular expression that file basenames must match.
 *   - accept_callback (callback): A callback that is called to accept a file.
 *     If it returns false the item will be skipped. The callback is passed the
 *     basename, pathname and depth.
 *   - accept_dir_callback (callback): The same as accept_callback, but only
 *     called for directories.
 *   - accept_file_callback (callback): The same as accept_callback, but only
 *     called for files.
 *   - file_callback (callback): A callback that is called when a file i
 *     succesfully matched. It is passed the basename, pathname and depth.
 *   - dir_callback (callback): The same as file_callback, but called for
 *     directories.
 *   - ignore_files (array): An array of file names to skip.
 *   - ignore_dirs (array): An array of directory names to skip.
 *   - ignore_vcs (bool): Skip over commonly used VCS dirs (svn, git, hg, bzr).
 *     This is enabled by default. The names of VCS directories to skip over
 *     are defined in {@link SS_FileFInder::$vcs_dirs}.
 *   - max_depth (int): The maxmium depth to traverse down the folder tree,
 *     default to unlimited.
 *
 * @package framework
 * @subpackage filesystem
 */
class SS_FileFinder {

    
/**
     * @var array
     */
    
protected static $vcs_dirs = array(
        
'.git''.svn''.hg''.bzr'
    
);

    
/**
     * The default options that are set on a new finder instance. Options not
     * present in this array cannot be set.
     *
     * Any default_option statics defined on child classes are also taken into
     * account.
     *
     * @var array
     */
    
protected static $default_options = array(
        
'name_regex'           => null,
        
'accept_callback'      => null,
        
'accept_dir_callback'  => null,
        
'accept_file_callback' => null,
        
'file_callback'        => null,
        
'dir_callback'         => null,
        
'ignore_files'         => null,
        
'ignore_dirs'          => null,
        
'ignore_vcs'           => true,
        
'min_depth'            => null,
        
'max_depth'            => null
    
);

    
/**
     * @var array
     */
    
protected $options;

    public function 
__construct() {
        
$this->options = array();
        
$class get_class($this);

        
// We build our options array ourselves, because possibly no class or config manifest exists at this point
        
do {
            
$this->options array_merge(Object::static_lookup($class'default_options'), $this->options);
        }
        while (
$class get_parent_class($class));
    }

    
/**
     * Returns an option value set on this instance.
     *
     * @param  string $name
     * @return mixed
     */
    
public function getOption($name) {
        if (!
array_key_exists($name$this->options)) {
            throw new 
InvalidArgumentException("The option $name doesn't exist.");
        }

        return 
$this->options[$name];
    }

    
/**
     * Set an option on this finder instance. See {@link SS_FileFinder} for the
     * list of options available.
     *
     * @param string $name
     * @param mixed $value
     */
    
public function setOption($name$value) {
        if (!
array_key_exists($name$this->options)) {
            throw new 
InvalidArgumentException("The option $name doesn't exist.");
        }

        
$this->options[$name] = $value;
    }

    
/**
     * Sets several options at once.
     *
     * @param array $options
     */
    
public function setOptions(array $options) {
        foreach (
$options as $k => $v$this->setOption($k$v);
    }

    
/**
     * Finds all files matching the options within a directory. The search is
     * performed depth first.
     *
     * @param  string $base
     * @return array
     */
    
public function find($base) {
        
$paths = array(array(rtrim($base'/'), 0));
        
$found = array();

        
$fileCallback $this->getOption('file_callback');
        
$dirCallback  $this->getOption('dir_callback');

        while (
$path array_shift($paths)) {
            list(
$path$depth) = $path;

            foreach (
scandir($path) as $basename) {
                if (
$basename == '.' || $basename == '..') {
                    continue;
                }

                if (
is_dir("$path/$basename")) {
                    if (!
$this->acceptDir($basename"$path/$basename"$depth 1)) {
                        continue;
                    }

                    if (
$dirCallback) {
                        
call_user_func(
                            
$dirCallback$basename"$path/$basename"$depth 1
                        
);
                    }

                    
$paths[] = array("$path/$basename"$depth 1);
                } else {
                    if (!
$this->acceptFile($basename"$path/$basename"$depth)) {
                        continue;
                    }

                    if (
$fileCallback) {
                        
call_user_func(
                            
$fileCallback$basename"$path/$basename"$depth
                        
);
                    }

                    
$found[] = "$path/$basename";
                }
            }
        }

        return 
$found;
    }

    
/**
     * Returns TRUE if the directory should be traversed. This can be overloaded
     * to customise functionality, or extended with callbacks.
     *
     * @return bool
     */
    
protected function acceptDir($basename$pathname$depth) {
        if (
$this->getOption('ignore_vcs') && in_array($basenameself::$vcs_dirs)) {
            return 
false;
        }

        if (
$ignore $this->getOption('ignore_dirs')) {
            if (
in_array($basename$ignore)) return false;
        }

        if (
$max $this->getOption('max_depth')) {
            if (
$depth $max) return false;
        }

        if (
$callback $this->getOption('accept_callback')) {
            if (!
call_user_func($callback$basename$pathname$depth)) return false;
        }

        if (
$callback $this->getOption('accept_dir_callback')) {
            if (!
call_user_func($callback$basename$pathname$depth)) return false;
        }

        return 
true;
    }

    
/**
     * Returns TRUE if the file should be included in the results. This can be
     * overloaded to customise functionality, or extended via callbacks.
     *
     * @return bool
     */
    
protected function acceptFile($basename$pathname$depth) {
        if (
$regex $this->getOption('name_regex')) {
            if (!
preg_match($regex$basename)) return false;
        }

        if (
$ignore $this->getOption('ignore_files')) {
            if (
in_array($basename$ignore)) return false;
        }

        if (
$minDepth $this->getOption('min_depth')) {
            if (
$depth $minDepth) return false;
        }

        if (
$callback $this->getOption('accept_callback')) {
            if (!
call_user_func($callback$basename$pathname$depth)) return false;
        }

        if (
$callback $this->getOption('accept_file_callback')) {
            if (!
call_user_func($callback$basename$pathname$depth)) return false;
        }

        return 
true;
    }

}
Онлайн: 0
Реклама