Filter out unwanted file implementations in a directory based on SPL iterator
1. In a template directory, because there are some files that need to be ignored, it is also written into the table, so it needs to be filtered out. Reference: In Laravle 6, togos/phpgitignore, implementation for parsing and applying .gitignore class rules
2. The current code implementation
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. The result is for example: the file starting with node_modules is written to the database. as shown in Figure 1
4. It is expected to be realized through the RecursiveFilterIterator class to avoid writing ignore files to the database. This abstract iterator filters out unwanted values for RecursiveIterator. This type should be extended to implement custom filters. RecursiveFilterIterator::accept() must be implemented in subclasses. Reference:https://www.php.net/manual/zh/class.recursivefilteriterator.php. Recursive directory/file listing, filters “.svn”.
5. Create a new ThemeViewIgnoRefinder.php to get an array of ignore files. IncludeDirectories is set to true to include directories.
<?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. Create a new ThemeViewRecursiveFilterIterator.php to implement a custom filter
<?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. Edit the SPL iterator code implementation
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. An error is reported at runtime. as shown in Figure 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. Edit ThemeViewRecursiveFilterIterator.php, add the method 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. Run again, the operation is successful, but the file starting with node_modules\ is still written to the database. Not as expected. Print $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. Print $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. The reason is to determine whether the file path should be filtered out is incorrect. Re-implement as follows
/**
* 添加忽略文件
* @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. Run again, the operation is successful, and the file starting with node_modules has not been written to the database. in line with expectations. as shown in Figure 3


