Browse Source

refactored FileHelper.

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
040db44fbd
  1. 118
      framework/yii/helpers/base/FileHelper.php
  2. 8
      tests/unit/framework/helpers/FileHelperTest.php

118
framework/yii/helpers/base/FileHelper.php

@ -134,12 +134,21 @@ class FileHelper
*
* - dirMode: integer, the permission to be set for newly copied directories. Defaults to 0777.
* - fileMode: integer, the permission to be set for newly copied files. Defaults to the current environment setting.
* - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
* If the callback returns false, the copy operation for the sub-directory or file will be cancelled.
* - filter: callback, a PHP callback that is called for each sub-directory or file.
* If the callback returns false, the the sub-directory or file will not be copied.
* The signature of the callback should be: `function ($path)`, where `$path` refers the full path to be copied.
* - fileTypes: array, list of file name suffix (without dot). Only files with these suffixes will be copied.
* - only: array, list of patterns that the files or directories should match if they want to be copied.
* A path matches a pattern if it contains the pattern string at its end. For example,
* '/a/b' will match all files and directories ending with '/a/b'; and the '.svn' will match all files and
* directories whose name ends with '.svn'. Note, the '/' characters in a pattern matches both '/' and '\'.
* If a file/directory matches both a name in "only" and "except", it will NOT be copied.
* - except: array, list of patterns that the files or directories should NOT match if they want to be copied.
* For more details on how to specify the patterns, please refer to the "only" option.
* - recursive: boolean, whether the files under the subdirectories should also be copied. Defaults to true.
* - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied.
* The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
* file to be copied from, while `$to` is the copy target.
* - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied.
* The signature of the callback is similar to that of `beforeCopy`.
* file copied from, while `$to` is the copy target.
*/
public static function copyDirectory($src, $dst, $options = array())
{
@ -154,7 +163,7 @@ class FileHelper
}
$from = $src . DIRECTORY_SEPARATOR . $file;
$to = $dst . DIRECTORY_SEPARATOR . $file;
if (!isset($options['beforeCopy']) || call_user_func($options['beforeCopy'], $from, $to)) {
if (static::filterPath($from, $options)) {
if (is_file($from)) {
copy($from, $to);
if (isset($options['fileMode'])) {
@ -177,22 +186,23 @@ class FileHelper
*/
public static function removeDirectory($dir)
{
$items = glob($dir . DIRECTORY_SEPARATOR . '{,.}*', GLOB_MARK | GLOB_BRACE);
foreach ($items as $item) {
$itemBaseName = basename($item);
if ($itemBaseName === '.' || $itemBaseName === '..') {
if (!is_dir($dir) || !($handle = opendir($dir))) {
return;
}
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
if (StringHelper::substr($item, -1, 1) == DIRECTORY_SEPARATOR) {
static::removeDirectory($item);
$path = $dir . DIRECTORY_SEPARATOR . $file;
if (is_file($path)) {
unlink($path);
} else {
unlink($item);
static::removeDirectory($path);
}
}
if (is_dir($dir)) {
closedir($handle);
rmdir($dir);
}
}
/**
* Returns the files found under the specified directory and subdirectories.
@ -200,18 +210,17 @@ class FileHelper
* @param array $options options for file searching. Valid options are:
*
* - filter: callback, a PHP callback that is called for each sub-directory or file.
* If the callback returns false, the the sub-directory or file will not be placed to the result set.
* The signature of the callback should be: `function ($base, $name, $isFile)`, where `$base` is the name of directory,
* which contains file or sub-directory, `$name` file or sub-directory name, `$isFile` indicates if object is a file or a directory.
* If the callback returns false, the the sub-directory or file will be excluded from the returning result.
* The signature of the callback should be: `function ($path)`, where `$path` refers the full path to be filtered.
* - fileTypes: array, list of file name suffix (without dot). Only files with these suffixes will be returned.
* - only: array, list of path names that the files or directories should match if they want to be put in the result set.
* The matching is done in a partial manner. For example, the '.svn' will match all files and directories whose name ends with '.svn'.
* And the name '/a/b' will match all files and directories ending with '/a/b'.
* Note, that '/' should be used as separator regardless of the value of the DIRECTORY_SEPARATOR constant.
* If a file/directory matches both a name in "only" and "except", it will NOT be put in the result set.
* - except: array, list of path names that the files or directories should NOT match if they want to be put in the result set.
* - recursive: boolean, whether the files should be looked recursively under all subdirectories.
* Defaults to true.
* - only: array, list of patterns that the files or directories should match if they want to be returned.
* A path matches a pattern if it contains the pattern string at its end. For example,
* '/a/b' will match all files and directories ending with '/a/b'; and the '.svn' will match all files and
* directories whose name ends with '.svn'. Note, the '/' characters in a pattern matches both '/' and '\'.
* If a file/directory matches both a name in "only" and "except", it will NOT be returned.
* - except: array, list of patterns that the files or directories should NOT match if they want to be returned.
* For more details on how to specify the patterns, please refer to the "only" option.
* - recursive: boolean, whether the files under the subdirectories should also be lookied for. Defaults to true.
* @return array files found under the directory. The file list is sorted.
*/
public static function findFiles($dir, $options = array())
@ -223,7 +232,7 @@ class FileHelper
continue;
}
$path = $dir . DIRECTORY_SEPARATOR . $file;
if (static::validatePath($path, $options)) {
if (static::filterPath($path, $options)) {
if (is_file($path)) {
$list[] = $path;
} elseif (!isset($options['recursive']) || $options['recursive']) {
@ -236,62 +245,61 @@ class FileHelper
}
/**
* Validates a file or directory, checking if it match given conditions.
* @param string $path the path of the file or directory to be validated
* @param array $options options for file searching.
* @return boolean whether the file or directory is valid
* Checks if the given file path satisfies the filtering options.
* @param string $path the path of the file or directory to be checked
* @param array $options the filtering options. See [[findFiles()]] for explanations of
* the supported options.
* @return boolean whether the file or directory satisfies the filtering options.
*/
protected static function validatePath($path, $options)
protected static function filterPath($path, $options)
{
if (isset($options['filter']) && !call_user_func($options['filter'], $path)) {
return false;
}
$path = str_replace('\\', '/', $path);
$n = strlen($path);
$n = StringHelper::strlen($path);
if (!empty($options['except'])) {
foreach ($options['except'] as $name) {
if (strrpos($path, $name) === $n - strlen($name)) {
if (StringHelper::substr($path, -StringHelper::strlen($name), $n) === $name) {
return false;
}
}
}
if (!empty($options['only'])) {
foreach ($options['only'] as $name) {
if (strrpos($path, $name) !== $n - strlen($name)) {
if (StringHelper::substr($path, -StringHelper::strlen($name), $n) !== $name) {
return false;
}
}
}
if (!empty($options['fileTypes'])) {
if (!is_file($path)) {
return true;
}
if (($type = pathinfo($path, PATHINFO_EXTENSION)) !== '') {
return in_array($type, $options['fileTypes']);
if (!empty($options['fileTypes']) && is_file($path)) {
return in_array(pathinfo($path, PATHINFO_EXTENSION), $options['fileTypes']);
} else {
return false;
}
}
return true;
}
}
/**
* Shared environment safe version of mkdir. Supports recursive creation.
* For avoidance of umask side-effects chmod is used.
* Makes directory.
*
* This method is similar to the PHP `mkdir()` function except that
* it uses `chmod()` to set the permission of the created directory
* in order to avoid the impact of the `umask` setting.
*
* @param string $path path to be created.
* @param integer $mode the permission to be set for created directory. If not set 0777 will be used.
* @param boolean $recursive whether to create directory structure recursive if parent dirs do not exist.
* @return boolean result of mkdir.
* @see mkdir
* @param integer $mode the permission to be set for created directory.
* @param boolean $recursive whether to create parent directories if they do not exist.
* @return boolean whether the directory is created successfully
*/
public static function mkdir($path, $mode = null, $recursive = false)
public static function mkdir($path, $mode = 0777, $recursive = true)
{
$prevDir = dirname($path);
if ($recursive && !is_dir($path) && !is_dir($prevDir)) {
static::mkdir(dirname($path), $mode, true);
if (is_dir($path)) {
return true;
}
$parentDir = dirname($path);
if ($recursive && !is_dir($parentDir)) {
static::mkdir($parentDir, $mode, true);
}
$mode = isset($mode) ? $mode : 0777;
$result = mkdir($path, $mode);
chmod($path, $mode);
return $result;

8
tests/unit/framework/helpers/FileHelperTest.php

@ -45,7 +45,7 @@ class FileHelperTest extends TestCase
*/
protected function removeDir($dirName)
{
if (!empty($dirName) && file_exists($dirName)) {
if (!empty($dirName) && is_dir($dirName)) {
if ($handle = opendir($dirName)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != '.' && $entry != '..') {
@ -235,8 +235,8 @@ class FileHelperTest extends TestCase
$dirName = $basePath . DIRECTORY_SEPARATOR . $dirName;
$options = array(
'filter' => function($base, $name, $isFile) use ($passedFileName) {
return ($passedFileName == $name);
'filter' => function($path) use ($passedFileName) {
return $passedFileName == basename($path);
}
);
$foundFiles = FileHelper::findFiles($dirName, $options);
@ -261,7 +261,7 @@ class FileHelperTest extends TestCase
$dirName = $basePath . DIRECTORY_SEPARATOR . $dirName;
$options = array(
'exclude' => array($excludeFileName),
'except' => array($excludeFileName),
);
$foundFiles = FileHelper::findFiles($dirName, $options);
$this->assertEquals(array($dirName . DIRECTORY_SEPARATOR . $fileName), $foundFiles);

Loading…
Cancel
Save