基于 SPL 迭代器 过滤掉目录中不需要的文件实现
1、在一个模板目录中,由于存在一些需要忽略的文件,也被写入至表中,因此,需要过滤掉。参考:在 Laravle 6、TOGoS/PHPGitIgnore 中,用于解析和应用 .gitignore 类规则的实现
2、现阶段的代码实现
1 2 3 4 5 6 7 8 9 10 11 12 | 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,以包含目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?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,以实现自定义过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?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 迭代器 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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、原因在于判断文件路径是否应被过滤掉的规则不正确。重新实现如下
1 2 3 4 5 6 7 8 9 | /** * 添加忽略文件 * @param $f * @param $result * @return void */ public function addIgnoreResult( $f , $result ) { $this ->ignoreResults[ $this ->themeLocation . DIRECTORY_SEPARATOR . str_replace ( '/' , DIRECTORY_SEPARATOR, $f )] = $result ; } |
1 2 3 | public function accept() { return ! $this ->filters[ $this ->current()->getPath() . DIRECTORY_SEPARATOR . $this ->current()->getFilename()]; } |
13、再次运行,运行成功,且 node_modules 开头的文件已未被写入至数据库中。符合预期。如图3
近期评论