基于 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
近期评论