Symfony Finder: получить все файлы с определенным расширением и все каталоги в определенном каталоге

#php #symfony #symfony4

#php #symfony #symfony4

Вопрос:

Я использую Symfony Finder , чтобы получить все файлы с определенным расширением и все каталоги в определенном каталоге.

 
    protected function getDirectoryContent(string $directory): array
    {
        $finder = Finder::create()
            ->in($directory)
            ->depth(0)
            ->name(['*.json', '*.php'])
            ->sortByName();

        return iterator_to_array($finder, true);
    }

  

Таким образом, этот метод возвращает только все файлы с расширением .php или .json в определенном каталоге. Например, структура каталогов, которую я ищу, выглядит следующим образом:

 /my/directory/
├── A
├── A.JSON
├── anotherfile.kas
├── file0.ds
├── file1.json
├── file2.php
├── file3.php
├── B
└── C
  

A , B и C являются каталогами.

Когда я передаю вышеуказанное directory path в качестве $directory аргумента в методе, который я показал выше, я получаю массив со следующими элементами:

 file1.json
file2.php
file3.php
  

Отлично !, но мой вопрос в том, как я мог бы также добавить все directories в результирующий массив? Я ожидаю получить массив, подобный следующему:

 A
B
C
file1.json
file2.php
file3.php
  

Ответ №1:

В вашем случае вы обращаетесь к finder:

  • Пожалуйста, добавьте рекурсивный итератор каталогов с глубиной 0 (все в порядке, мы хотим искать только в корне)
  • Пожалуйста, добавьте итератор имен файлов (это неправильно, потому что вы находите только файлы).

В результате это неправильно, потому что эти два правила противоречат друг другу — потому что вы хотите искать только файлы.

Но symfony finder можно использовать CallbackIterator с моделью фильтра. В этой ситуации вы можете добавить много правил или условий. В вашем примере:

 namespace Acme;

use SymfonyComponentFinderFinder;
use SymfonyComponentFinderSplFileInfo;

include __DIR__.'/vendor/autoload.php';

$finder = Finder::create();

$finder
    ->in(__DIR__)
    ->depth(0)
    ->filter(static function (SplFileInfo $file) {
        return $file->isDir() || preg_match('/.(php|json)$/', $file->getPathname());
    });

print_r(iterator_to_array($finder));
  

В этом случае вы говорите:

  • Пожалуйста, найдите только в root.
  • Пожалуйста, проверьте — или файл или совпадение по моему шаблону.

Комментарии:

1. Спасибо! @ZhukV, я задал тот же вопрос в репозитории symfony на github, пользователь дал мне идею, но я не счел это очень хорошей идеей, поскольку с его решением я бы повторял 2 раза каждый каталог. github.com/symfony/symfony/issues/38949#issuecomment-720137475 . Мне кажется, что ваше решение намного эффективнее, поскольку оно будет проходить через каталог только один раз, а затем фильтровать полученный массив. Еще раз большое вам спасибо.