基于 SPL 迭代器 过滤掉目录中不需要的文件实现
1、在一个模板目录中,由于存在一些需要忽略的文件,也被写入至表中,因此,需要过滤掉。参考:在 Laravle 6、TOGoS/PHPGitIgnore 中,用于解析和应用 .gitignore 类规则的实现
2、现阶段的代码实现
private \RecursiveIteratorIterator $iterator;
private $themeLocation;
public function __construct($themeLocation)
{
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($themeLocation, \FilesystemIterator::SKIP_DOTS)
);
$this->iterator = $iterator;
$this->themeLocation = $themeLocation;
}
3、导致的结果就是例如:node_modules 开头的文件被写入至数据库中。如图1
4、期望通过 The RecursiveFilterIterator class 实现,避免将忽略文件写入至数据库中。这个抽象迭代器为 RecursiveIterator 过滤掉不需要的值。应扩展此类以实现自定义过滤器。 RecursiveFilterIterator::accept() 必须在子类中实现。参考:https://www.php.net/manual/zh/class.recursivefilteriterator.php 。Recursive directory/file listing, filteres “.svn”。
5、新建 ThemeViewIgnoreFinder.php,以获取忽略文件数组。includeDirectories 设置为 true,以包含目录。
<?php
namespace Modules\ThemeStoreDB\Installer;
use TOGoS_GitIgnore_FileFinder;
use TOGoS_GitIgnore_Ruleset;
class ThemeViewIgnoreFinder
{
const THEMEIGNORE = '.themeignore'; // 主题忽略配置文件
public $ignoreResults;
private $themeLocation;
public function __construct($themeLocation)
{
$this->themeLocation = $themeLocation;
$this->ignoreResults = [];
}
/**
* 添加忽略文件
* @param $f
* @param $result
* @return void
*/
public function addIgnoreResult($f, $result) {
$this->ignoreResults[$f] = $result;
}
/**
* 查找忽略文件
* @return array
*/
public function findIgnoreFiles() {
$rulesContent = file_get_contents($this->themeLocation . DIRECTORY_SEPARATOR . self::THEMEIGNORE);
$finder = new TOGoS_GitIgnore_FileFinder([
'ruleset' => TOGoS_GitIgnore_Ruleset::loadFromString($rulesContent),
'invertRulesetResult' => false,
'defaultResult' => false,
'includeDirectories' => true,
'callback' => [$this, 'addIgnoreResult']
]);
$finder->findFiles($this->themeLocation);
return $this->ignoreResults;
}
}
6、新建 ThemeViewRecursiveFilterIterator.php,以实现自定义过滤器
<?php
namespace Modules\ThemeStoreDB\Installer;
class ThemeViewRecursiveFilterIterator extends \RecursiveFilterIterator
{
protected $filters;
public function __construct(\RecursiveIterator $iterator, $ignoreResults) {
$this->filters = $ignoreResults;
parent::__construct($iterator);
}
public function accept() {
$accept = true;
if (isset($this->filters[$this->current()->getFilename()])) {
$accept = !$this->filters[$this->current()->getFilename()];
}
return $accept;
}
}
7、编辑 SPL 迭代器 代码实现
private \RecursiveIteratorIterator $iterator;
private $themeLocation;
public function __construct($themeLocation)
{
$dirIterator = new \RecursiveDirectoryIterator($themeLocation, \FilesystemIterator::SKIP_DOTS);
$themeViewIgnoreFinder = new ThemeViewIgnoreFinder($themeLocation);
$filterIterator = new ThemeViewRecursiveFilterIterator($dirIterator, $themeViewIgnoreFinder->findIgnoreFiles());
$iterator = new \RecursiveIteratorIterator($filterIterator);
$this->iterator = $iterator;
$this->themeLocation = $themeLocation;
}
8、运行时报错。如图2
PS E:\wwwroot\object> php artisan theme-store:theme:install E:\wwwroot\object\resources\views\theme 12345 blade
安装主题到数据仓库
Symfony\Component\Debug\Exception\FatalThrowableError : Too few arguments to function Modules\ThemeStoreDB\Installer\ThemeViewRecursiveFilterIterator::__construct(), 1 passed and exactly 2 expected
at E:\wwwroot\object\Modules\ThemeStoreDB\Installer\ThemeViewRecursiveFilterIterator.php:9
5| class ThemeViewRecursiveFilterIterator extends \RecursiveFilterIterator
6| {
7| protected $filters;
8|
> 9| public function __construct(\RecursiveIterator $rit, $ignoreResults) {
10|
11| $this->filters = $ignoreResults;
12| parent::__construct($rit);
13| }
Exception trace:
1 Modules\ThemeStoreDB\Installer\ThemeViewRecursiveFilterIterator::__construct(Object(RecursiveDirectoryIterator))
[internal]:0
2 RecursiveFilterIterator::getChildren()
[internal]:0
Please use the argument -v to see more details.
9、编辑 ThemeViewRecursiveFilterIterator.php,添加方法 getChildren()
<?php
namespace Modules\ThemeStoreDB\Installer;
class ThemeViewRecursiveFilterIterator extends \RecursiveFilterIterator
{
protected $filters;
public function __construct(\RecursiveIterator $iterator, $ignoreResults) {
$this->filters = $ignoreResults;
parent::__construct($iterator);
}
public function accept() {
$accept = true;
if (isset($this->filters[$this->current()->getFilename()])) {
$accept = !$this->filters[$this->current()->getFilename()];
}
return $accept;
}
public function getChildren() {
return new self($this->getInnerIterator()->getChildren(), $this->filters);
}
}
10、再次运行,运行成功,但 node_modules\ 开头的文件仍被写入至数据库中。不符合预期。打印 $this->filters
array(766) {
[""]=>
bool(false)
[".browserslistrc"]=>
bool(true)
[".env"]=>
bool(true)
[".env.development"]=>
bool(true)
[".env.production"]=>
bool(true)
[".themeignore"]=>
bool(true)
["assets"]=>
bool(false)
["assets/css"]=>
bool(false)
["assets/css/app.css"]=>
bool(true)
["assets/images"]=>
bool(false)
}
11、打印 $this->current()->getPath() 、$this->current()->getFilename()
E:\wwwroot\object\resources\views\theme .browserslistrc E:\wwwroot\object\resources\views\theme .env E:\wwwroot\object\resources\views\theme .env.development E:\wwwroot\object\resources\views\theme .env.production E:\wwwroot\object\resources\views\theme .themeignore E:\wwwroot\object\resources\views\theme assets E:\wwwroot\object\resources\views\theme\assets css E:\wwwroot\object\resources\views\theme\assets\css app.css E:\wwwroot\object\resources\views\theme\assets images
12、原因在于判断文件路径是否应被过滤掉的规则不正确。重新实现如下
/**
* 添加忽略文件
* @param $f
* @param $result
* @return void
*/
public function addIgnoreResult($f, $result) {
$this->ignoreResults[$this->themeLocation . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $f)] = $result;
}
public function accept() {
return !$this->filters[$this->current()->getPath() . DIRECTORY_SEPARATOR . $this->current()->getFilename()];
}
13、再次运行,运行成功,且 node_modules 开头的文件已未被写入至数据库中。符合预期。如图3



近期评论