Initial commit
This commit is contained in:
25
src/DocumentFactory.php
Normal file
25
src/DocumentFactory.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use IO\Shell\Pdfinfo;
|
||||
use PDF\Document;
|
||||
|
||||
class DocumentFactory
|
||||
{
|
||||
private Pdfinfo $pdfinfo;
|
||||
|
||||
public function __construct(?Pdfinfo $pdfinfo = null)
|
||||
{
|
||||
$this->pdfinfo = $pdfinfo ?? new Pdfinfo();
|
||||
}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function createDocument(SplFileInfo $file): Document
|
||||
{
|
||||
$metadata = $this->pdfinfo->getMetadata($file);
|
||||
return new Document($file, $metadata);
|
||||
}
|
||||
}
|
||||
12
src/Filter/DocumentFilter.php
Normal file
12
src/Filter/DocumentFilter.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Filter;
|
||||
|
||||
use PDF\Document;
|
||||
|
||||
interface DocumentFilter
|
||||
{
|
||||
public function allows(Document $document): bool;
|
||||
|
||||
public function __toString(): string;
|
||||
}
|
||||
15
src/Filter/FilterFactory.php
Normal file
15
src/Filter/FilterFactory.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Filter;
|
||||
|
||||
class FilterFactory
|
||||
{
|
||||
public function createFromString(string $string): DocumentFilter
|
||||
{
|
||||
if (preg_match('/^.+=.*$/', $string)) {
|
||||
[$prop, $term] = explode('=', $string);
|
||||
return new SpecificFilter(trim($prop), trim($term));
|
||||
}
|
||||
return new GenericFilter($string);
|
||||
}
|
||||
}
|
||||
34
src/Filter/GenericFilter.php
Normal file
34
src/Filter/GenericFilter.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Filter;
|
||||
|
||||
use PDF\Document;
|
||||
|
||||
class GenericFilter implements DocumentFilter
|
||||
{
|
||||
private string $term;
|
||||
|
||||
public function __construct(string $term)
|
||||
{
|
||||
$this->term = $term;
|
||||
}
|
||||
|
||||
public function allows(Document $document): bool
|
||||
{
|
||||
if ($this->term === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($document->getProperties() as $key => $value) {
|
||||
if (stripos($value, $this->term) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return sprintf('[*] contains \'%s\'', $this->term);
|
||||
}
|
||||
}
|
||||
42
src/Filter/SpecificFilter.php
Normal file
42
src/Filter/SpecificFilter.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Filter;
|
||||
|
||||
use PDF\Document;
|
||||
use RuntimeException;
|
||||
|
||||
class SpecificFilter implements DocumentFilter
|
||||
{
|
||||
private string $property;
|
||||
private string $term;
|
||||
|
||||
public function __construct(string $property, string $term)
|
||||
{
|
||||
$this->property = strtolower($property);
|
||||
$this->term = strtolower($term);
|
||||
}
|
||||
|
||||
public function allows(Document $document): bool
|
||||
{
|
||||
if ($this->property === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$property = $document->getProperty($this->property);
|
||||
if ($this->term === '' && !empty($property)) {
|
||||
// Filter is "prop=", which only checks if it exists.
|
||||
return true;
|
||||
}
|
||||
return stripos($property, $this->term) !== false;
|
||||
} catch (RuntimeException $e) {
|
||||
// No such property exists, we don't pass
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return sprintf('property \'%s\' contains \'%s\'', $this->property, $this->term);
|
||||
}
|
||||
}
|
||||
11
src/IO/Exception/DirectoryNotFoundException.php
Normal file
11
src/IO/Exception/DirectoryNotFoundException.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Exception;
|
||||
|
||||
class DirectoryNotFoundException extends IOException
|
||||
{
|
||||
public function __construct(string $directory)
|
||||
{
|
||||
parent::__construct(sprintf('Directory \'%s\' not found', $directory));
|
||||
}
|
||||
}
|
||||
11
src/IO/Exception/FileNotFoundException.php
Normal file
11
src/IO/Exception/FileNotFoundException.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Exception;
|
||||
|
||||
class FileNotFoundException extends IOException
|
||||
{
|
||||
public function __construct(string $file)
|
||||
{
|
||||
parent::__construct(sprintf('File \'%s\' not found', $file));
|
||||
}
|
||||
}
|
||||
11
src/IO/Exception/FileNotReadableException.php
Normal file
11
src/IO/Exception/FileNotReadableException.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Exception;
|
||||
|
||||
class FileNotReadableException extends IOException
|
||||
{
|
||||
public function __construct(string $file)
|
||||
{
|
||||
parent::__construct(sprintf('File \'%s\' is not readable', $file));
|
||||
}
|
||||
}
|
||||
9
src/IO/Exception/IOException.php
Normal file
9
src/IO/Exception/IOException.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
abstract class IOException extends RuntimeException
|
||||
{
|
||||
}
|
||||
12
src/IO/Exception/MissingFileArgumentException.php
Normal file
12
src/IO/Exception/MissingFileArgumentException.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Exception;
|
||||
|
||||
|
||||
class MissingFileArgumentException extends IOException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Missing file argument');
|
||||
}
|
||||
}
|
||||
11
src/IO/Exception/NotADirectoryException.php
Normal file
11
src/IO/Exception/NotADirectoryException.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Exception;
|
||||
|
||||
class NotADirectoryException extends IOException
|
||||
{
|
||||
public function __construct(string $directory)
|
||||
{
|
||||
parent::__construct(sprintf('Argument \'%s\' is not a directory', $directory));
|
||||
}
|
||||
}
|
||||
24
src/IO/ExceptionHandler.php
Normal file
24
src/IO/ExceptionHandler.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace IO;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ExceptionHandler
|
||||
{
|
||||
private static bool $registered = false;
|
||||
|
||||
public static function registerCallback(): void
|
||||
{
|
||||
if (self::$registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_exception_handler(static function (Throwable $t) {
|
||||
print($t->getMessage());
|
||||
exit(1);
|
||||
});
|
||||
|
||||
self::$registered = true;
|
||||
}
|
||||
}
|
||||
18
src/IO/Input/ArgvAccess.php
Normal file
18
src/IO/Input/ArgvAccess.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Input;
|
||||
|
||||
trait ArgvAccess
|
||||
{
|
||||
protected static function getArguments(): array
|
||||
{
|
||||
// Get local copy of $argv
|
||||
global $argv;
|
||||
$arguments = $argv;
|
||||
|
||||
// Lose the script name
|
||||
array_shift($arguments);
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
55
src/IO/Input/FinderArguments.php
Normal file
55
src/IO/Input/FinderArguments.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Input;
|
||||
|
||||
use Filter\DocumentFilter;
|
||||
use Filter\FilterFactory;
|
||||
use IO\Exception\DirectoryNotFoundException;
|
||||
use IO\Exception\NotADirectoryException;
|
||||
|
||||
class FinderArguments
|
||||
{
|
||||
use ArgvAccess;
|
||||
|
||||
private ?string $directory;
|
||||
private array $filters;
|
||||
|
||||
public function __construct(?string $directory, array $filters)
|
||||
{
|
||||
$this->directory = $directory;
|
||||
$this->filters = $filters;
|
||||
|
||||
$factory = new FilterFactory();
|
||||
$this->filters = array_map([$factory, 'createFromString'], $this->filters);
|
||||
}
|
||||
|
||||
public static function createFromGlobals(): self
|
||||
{
|
||||
$arguments = self::getArguments();
|
||||
|
||||
$dir = array_shift($arguments) ?? getcwd();
|
||||
$dir = rtrim($dir, DIRECTORY_SEPARATOR);
|
||||
|
||||
return new self($dir, $arguments);
|
||||
}
|
||||
|
||||
public function getDirectory(): string
|
||||
{
|
||||
if (!file_exists($this->directory)) {
|
||||
throw new DirectoryNotFoundException($this->directory);
|
||||
}
|
||||
if (!is_dir($this->directory)) {
|
||||
throw new NotADirectoryException($this->directory);
|
||||
}
|
||||
|
||||
return $this->directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DocumentFilter[]
|
||||
*/
|
||||
public function getFilters(): array
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
}
|
||||
41
src/IO/Input/ShowInfoArguments.php
Normal file
41
src/IO/Input/ShowInfoArguments.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Input;
|
||||
|
||||
use IO\Exception\FileNotFoundException;
|
||||
use IO\Exception\FileNotReadableException;
|
||||
use IO\Exception\MissingFileArgumentException;
|
||||
use SplFileInfo;
|
||||
|
||||
class ShowInfoArguments
|
||||
{
|
||||
use ArgvAccess;
|
||||
|
||||
private ?string $file;
|
||||
|
||||
public function __construct(?string $file)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
public static function createFromGlobals(): self
|
||||
{
|
||||
$arguments = self::getArguments();
|
||||
return new self(array_shift($arguments));
|
||||
}
|
||||
|
||||
public function getFile(): SplFileInfo
|
||||
{
|
||||
if (is_null($this->file)) {
|
||||
throw new MissingFileArgumentException();
|
||||
}
|
||||
if (!file_exists($this->file)) {
|
||||
throw new FileNotFoundException($this->file);
|
||||
}
|
||||
if (!is_readable($this->file)) {
|
||||
throw new FileNotReadableException($this->file);
|
||||
}
|
||||
|
||||
return new SplFileInfo($this->file);
|
||||
}
|
||||
}
|
||||
67
src/IO/Output/DocumentListingOutput.php
Normal file
67
src/IO/Output/DocumentListingOutput.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Output;
|
||||
|
||||
use PDF\Document;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DocumentListingOutput implements Output
|
||||
{
|
||||
/** @var Document[] */
|
||||
private iterable $documents;
|
||||
|
||||
public function __construct(iterable $documents)
|
||||
{
|
||||
$this->documents = $documents;
|
||||
}
|
||||
|
||||
public static function forDocuments(iterable $documents): self
|
||||
{
|
||||
return new self($documents);
|
||||
}
|
||||
|
||||
public function render(?OutputInterface $output = null): void
|
||||
{
|
||||
if (count($this->documents) === 0) {
|
||||
print('Your search yielded no results.' . PHP_EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$template = new TableTemplate([
|
||||
'Filename' => [
|
||||
'min_width' => 40,
|
||||
'max_width' => 80,
|
||||
],
|
||||
'Title' => [
|
||||
'min_width' => 40,
|
||||
'max_width' => 80,
|
||||
'null_value' => '-',
|
||||
|
||||
],
|
||||
'Author' => [
|
||||
'min_width' => 16,
|
||||
'max_width' => 32,
|
||||
'null_value' => '-',
|
||||
],
|
||||
'Path' => [
|
||||
'min_width' => 16,
|
||||
'max_width' => 32,
|
||||
'formatter' => static function (string $path) {
|
||||
$search = sprintf('/home/%s', get_current_user());
|
||||
return str_replace($search, '~', $path);
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
foreach ($this->documents as $document) {
|
||||
$template->addRow([
|
||||
$document->file->getBasename(),
|
||||
$document->metadata->title,
|
||||
$document->metadata->author,
|
||||
$document->file->getPath(),
|
||||
]);
|
||||
}
|
||||
|
||||
$template->generate($output)->render();
|
||||
}
|
||||
}
|
||||
42
src/IO/Output/DocumentOutput.php
Normal file
42
src/IO/Output/DocumentOutput.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Output;
|
||||
|
||||
use PDF\Document;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DocumentOutput implements Output
|
||||
{
|
||||
private Document $document;
|
||||
|
||||
public function __construct(Document $document)
|
||||
{
|
||||
$this->document = $document;
|
||||
}
|
||||
|
||||
public static function forDocument(Document $document): self
|
||||
{
|
||||
return new self($document);
|
||||
}
|
||||
|
||||
public function render(?OutputInterface $output = null): void
|
||||
{
|
||||
$template = new TableTemplate([
|
||||
'Property' => [
|
||||
'min_width' => 20,
|
||||
'max_width' => 20,
|
||||
],
|
||||
'Value' => [
|
||||
'min_width' => 80,
|
||||
'max_width' => 80,
|
||||
'null_value' => '-',
|
||||
],
|
||||
]);
|
||||
|
||||
foreach ($this->document->getProperties() as $property => $value) {
|
||||
$template->addRow([$property, $value]);
|
||||
}
|
||||
|
||||
$template->generate($output)->render();
|
||||
}
|
||||
}
|
||||
8
src/IO/Output/Output.php
Normal file
8
src/IO/Output/Output.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Output;
|
||||
|
||||
interface Output
|
||||
{
|
||||
public function render(): void;
|
||||
}
|
||||
74
src/IO/Output/TableTemplate.php
Normal file
74
src/IO/Output/TableTemplate.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Output;
|
||||
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class TableTemplate
|
||||
{
|
||||
private array $headers;
|
||||
private array $properties;
|
||||
private array $rows = [];
|
||||
|
||||
public function __construct(array $properties)
|
||||
{
|
||||
$this->headers = array_keys($properties);
|
||||
$this->properties = array_values($properties);
|
||||
}
|
||||
|
||||
public function addRow(array $row): void
|
||||
{
|
||||
$row = array_values($row);
|
||||
|
||||
foreach ($row as $columnIndex => &$value) {
|
||||
if (isset($this->properties[$columnIndex]['null_value'])) {
|
||||
$value ??= $this->properties[$columnIndex]['null_value'];
|
||||
}
|
||||
if (isset($this->properties[$columnIndex]['formatter'])) {
|
||||
$value = call_user_func($this->properties[$columnIndex]['formatter'], $value);
|
||||
}
|
||||
if (isset($this->properties[$columnIndex]['max_width'])) {
|
||||
$value = $this->trim($value, $this->properties[$columnIndex]['max_width']);
|
||||
}
|
||||
}
|
||||
unset($value);
|
||||
|
||||
$this->rows[] = $row;
|
||||
}
|
||||
|
||||
public function generate(?OutputInterface $output = null): Table
|
||||
{
|
||||
$table = new Table($output ?? new ConsoleOutput());
|
||||
$table->setStyle('box-double');
|
||||
$table->setHeaders($this->headers);
|
||||
|
||||
foreach ($this->properties as $columnIndex => $columnProperties) {
|
||||
if (isset($columnProperties['min_width'])) {
|
||||
$table->setColumnWidth($columnIndex, $columnProperties['min_width']);
|
||||
}
|
||||
if (isset($columnProperties['max_width'])) {
|
||||
$table->setColumnMaxWidth($columnIndex, $columnProperties['max_width']);
|
||||
}
|
||||
}
|
||||
|
||||
$table->setRows($this->rows);
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims a string if it's longer than $length and adds '...' to the end if trimmed.
|
||||
* @param string $string
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
private function trim(string $string, int $length): string
|
||||
{
|
||||
if (strlen($string) <= $length) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return '' . substr($string, 0, $length - 3) . '...';
|
||||
}
|
||||
}
|
||||
25
src/IO/Shell/Pdfinfo.php
Normal file
25
src/IO/Shell/Pdfinfo.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Shell;
|
||||
|
||||
use PDF\Metadata;
|
||||
|
||||
class Pdfinfo
|
||||
{
|
||||
use ShellCommandExecutor;
|
||||
|
||||
public function getMetadata(string $filepath): Metadata
|
||||
{
|
||||
$lines = $this->shellExec('pdfinfo', '-isodates', $filepath);
|
||||
|
||||
$data = [];
|
||||
foreach ($lines as $line) {
|
||||
$parts = explode(':', $line, 2);
|
||||
if (count($parts) === 2) {
|
||||
$data[trim($parts[0])] = trim($parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return (new Metadata)->fillWith($data);
|
||||
}
|
||||
}
|
||||
19
src/IO/Shell/ShellCommandExecutor.php
Normal file
19
src/IO/Shell/ShellCommandExecutor.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace IO\Shell;
|
||||
|
||||
trait ShellCommandExecutor
|
||||
{
|
||||
protected function shellExec(string $command, string ...$args): array
|
||||
{
|
||||
$args = array_map('escapeshellarg', $args);
|
||||
|
||||
$output = shell_exec(sprintf(
|
||||
'%s %s 2>/dev/null',
|
||||
escapeshellcmd($command),
|
||||
implode(' ', $args)
|
||||
));
|
||||
|
||||
return explode(PHP_EOL, $output);
|
||||
}
|
||||
}
|
||||
43
src/PDF/Document.php
Normal file
43
src/PDF/Document.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace PDF;
|
||||
|
||||
use RuntimeException;
|
||||
use SplFileInfo;
|
||||
|
||||
class Document
|
||||
{
|
||||
public SplFileInfo $file;
|
||||
public Metadata $metadata;
|
||||
|
||||
public function __construct(SplFileInfo $file, ?Metadata $metadata = null)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->metadata = $metadata ?? new Metadata();
|
||||
}
|
||||
|
||||
public function getProperty(string $prop): ?string
|
||||
{
|
||||
if (in_array($prop, ['path', 'filepath'])) {
|
||||
return $this->file->getPath();
|
||||
}
|
||||
|
||||
if (in_array($prop, ['file', 'name', 'filename'])) {
|
||||
return $this->file->getBasename();
|
||||
}
|
||||
|
||||
if (property_exists($this->metadata, $prop)) {
|
||||
return $this->metadata->{$prop};
|
||||
}
|
||||
|
||||
throw new RuntimeException('No such property');
|
||||
}
|
||||
|
||||
public function getProperties(): array
|
||||
{
|
||||
return [
|
||||
'filepath' => $this->file->getPath(),
|
||||
'filename' => $this->file->getBasename(),
|
||||
] + $this->metadata->toArray();
|
||||
}
|
||||
}
|
||||
53
src/PDF/Metadata.php
Normal file
53
src/PDF/Metadata.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace PDF;
|
||||
|
||||
use Cocur\Slugify\Slugify;
|
||||
|
||||
class Metadata
|
||||
{
|
||||
public ?string $abbreviation = null;
|
||||
public ?string $author = null;
|
||||
public ?string $creationdate = null;
|
||||
public ?string $creator = null;
|
||||
public ?string $encrypted = null;
|
||||
public ?string $form = null;
|
||||
public ?string $javascript = null;
|
||||
public ?string $keywords = null;
|
||||
public ?string $linearized = null;
|
||||
public ?string $moddate = null;
|
||||
public ?string $optimized = null;
|
||||
public ?string $page_rot = null;
|
||||
public ?string $page_size = null;
|
||||
public ?string $pages = null;
|
||||
public ?string $pdf_subtype = null;
|
||||
public ?string $pdf_version = null;
|
||||
public ?string $producer = null;
|
||||
public ?string $standard = null;
|
||||
public ?string $subject = null;
|
||||
public ?string $subtitle = null;
|
||||
public ?string $suspects = null;
|
||||
public ?string $tagged = null;
|
||||
public ?string $title = null;
|
||||
public ?string $userproperties = null;
|
||||
|
||||
public function fillWith(array $array): Metadata
|
||||
{
|
||||
$slugify = new Slugify(['separator' => '_']);
|
||||
|
||||
$array = array_filter($array, static fn(string $v) => trim($v) !== '');
|
||||
foreach ($array as $key => $value) {
|
||||
$key = $slugify->slugify($key);
|
||||
if (property_exists(__CLASS__, $key)) {
|
||||
$this->{$key} = trim($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return get_object_vars($this);
|
||||
}
|
||||
}
|
||||
30
src/RecursiveDocumentLocator.php
Normal file
30
src/RecursiveDocumentLocator.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use PDF\Document;
|
||||
|
||||
class RecursiveDocumentLocator
|
||||
{
|
||||
private DocumentFactory $documentFactory;
|
||||
|
||||
public function __construct(?DocumentFactory $documentFactory = null)
|
||||
{
|
||||
$this->documentFactory = $documentFactory ?? new DocumentFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<Document>|Document[]
|
||||
*/
|
||||
public function findDocuments(string $directory): Collection
|
||||
{
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($directory),
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
|
||||
return collect($iterator)
|
||||
->filter(static fn(SplFileInfo $fileInfo) => $fileInfo->isFile())
|
||||
->filter(static fn(SplFileInfo $fileInfo) => preg_match('/.pdf$/i', $fileInfo->getBasename()))
|
||||
->map(fn(SplFileInfo $fileInfo) => $this->documentFactory->createDocument($fileInfo));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user