抽象迭代器 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Fri, 24 Jun 2022 10:17:36 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 基于 SPL 迭代器 过滤掉目录中不需要的文件实现 https://www.shuijingwanwq.com/2022/06/13/6597/ https://www.shuijingwanwq.com/2022/06/13/6597/#respond Mon, 13 Jun 2022 01:22:31 +0000 https://www.shuijingwanwq.com/?p=6597 浏览量: 76 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
导致的结果就是例如: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
运行时报错

图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
再次运行,运行成功,且 node_modules 开头的文件已未被写入至数据库中。符合预期

图3

]]>
https://www.shuijingwanwq.com/2022/06/13/6597/feed/ 0