Compare commits
3 Commits
master
...
refactor/s
Author | SHA1 | Date | |
---|---|---|---|
e012ae2a9c | |||
78b596a342 | |||
afff03166e |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
/vendor/
|
/vendor/
|
||||||
/.idea/
|
/.idea/
|
||||||
|
/.phpunit.cache/
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use IO\ExceptionHandler;
|
use IO\ExceptionHandler;
|
||||||
use IO\Input\FinderArguments;
|
use IO\Input\FinderArguments;
|
||||||
use IO\Output\DocumentListingOutput;
|
use IO\Output\DocumentListing;
|
||||||
use PDF\Document;
|
use PDF\Document;
|
||||||
|
|
||||||
require_once __DIR__ . '/../vendor/autoload.php';
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
@ -23,4 +23,4 @@ foreach ($filters as $filter) {
|
|||||||
$documents = $documents->filter(fn(Document $document) => $filter->allows($document));
|
$documents = $documents->filter(fn(Document $document) => $filter->allows($document));
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentListingOutput::forDocuments($documents)->render();
|
DocumentListing::of($documents)->render();
|
||||||
|
@ -3,17 +3,12 @@
|
|||||||
|
|
||||||
use IO\ExceptionHandler;
|
use IO\ExceptionHandler;
|
||||||
use IO\Input\ShowInfoArguments;
|
use IO\Input\ShowInfoArguments;
|
||||||
use IO\Output\DocumentOutput;
|
use IO\Output\DocumentDetails;
|
||||||
|
|
||||||
require_once __DIR__ . '/../vendor/autoload.php';
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
ExceptionHandler::registerCallback();
|
ExceptionHandler::registerCallback();
|
||||||
|
|
||||||
$arguments = ShowInfoArguments::createFromGlobals();
|
$file = ShowInfoArguments::createFromGlobals()->getFile();
|
||||||
$file = $arguments->getFile();
|
$document = DocumentFactory::create()->fromFile($file);
|
||||||
|
DocumentDetails::of($document)->render();
|
||||||
$documentFactory = DocumentFactory::create();
|
|
||||||
$document = $documentFactory->createDocument($file);
|
|
||||||
|
|
||||||
$output = DocumentOutput::forDocument($document);
|
|
||||||
$output->render();
|
|
||||||
|
@ -2,7 +2,14 @@
|
|||||||
"name": "joopschilder/pdf-finder",
|
"name": "joopschilder/pdf-finder",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": ["pdf", "documents", "search", "metadata", "info", "portable document format"],
|
"keywords": [
|
||||||
|
"pdf",
|
||||||
|
"documents",
|
||||||
|
"search",
|
||||||
|
"metadata",
|
||||||
|
"info",
|
||||||
|
"portable document format"
|
||||||
|
],
|
||||||
"description": "Utility to locate PDF files based on their metadata",
|
"description": "Utility to locate PDF files based on their metadata",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-0": {
|
||||||
@ -11,9 +18,20 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-0": {
|
||||||
|
"": [
|
||||||
|
"src",
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"symfony/console": "^5.2",
|
"symfony/console": "^5.2",
|
||||||
"cocur/slugify": "^4.0",
|
"cocur/slugify": "^4.0",
|
||||||
"illuminate/collections": "^8.33"
|
"illuminate/collections": "^8.33"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2055
composer.lock
generated
2055
composer.lock
generated
File diff suppressed because it is too large
Load Diff
25
phpunit.xml
Normal file
25
phpunit.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
cacheResultFile=".phpunit.cache/test-results"
|
||||||
|
executionOrder="depends,defects"
|
||||||
|
forceCoversAnnotation="true"
|
||||||
|
beStrictAboutCoversAnnotation="true"
|
||||||
|
beStrictAboutOutputDuringTests="true"
|
||||||
|
beStrictAboutTodoAnnotatedTests="true"
|
||||||
|
failOnWarning="true"
|
||||||
|
verbose="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="default">
|
||||||
|
<directory suffix="Test.php">tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<coverage cacheDirectory=".phpunit.cache/code-coverage"
|
||||||
|
processUncoveredFiles="true">
|
||||||
|
<include>
|
||||||
|
<directory suffix=".php">src</directory>
|
||||||
|
</include>
|
||||||
|
</coverage>
|
||||||
|
</phpunit>
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use IO\Filesystem\File;
|
||||||
use IO\Shell\Pdfinfo;
|
use IO\Shell\Pdfinfo;
|
||||||
use PDF\Document;
|
use PDF\Document;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ class DocumentFactory
|
|||||||
return new self();
|
return new self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createDocument(SplFileInfo $file): Document
|
public function fromFile(File $file): Document
|
||||||
{
|
{
|
||||||
$metadata = $this->pdfinfo->getMetadata($file);
|
$metadata = $this->pdfinfo->getMetadata($file);
|
||||||
return new Document($file, $metadata);
|
return new Document($file, $metadata);
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace Filter;
|
namespace Filter;
|
||||||
|
|
||||||
class FilterFactory
|
class FilterParser
|
||||||
{
|
{
|
||||||
public function createFromString(string $string): DocumentFilter
|
public function parse(string $string): DocumentFilter
|
||||||
{
|
{
|
||||||
if (preg_match('/^.+=.*$/', $string)) {
|
if (preg_match('/^.+=.*$/', $string)) {
|
||||||
[$prop, $term] = explode('=', $string);
|
[$prop, $term] = explode('=', $string, 2);
|
||||||
return new SpecificFilter(trim($prop), trim($term));
|
return new SpecificFilter(trim($prop), trim($term));
|
||||||
}
|
}
|
||||||
return new GenericFilter($string);
|
return new GenericFilter($string);
|
42
src/IO/Filesystem/Directory.php
Normal file
42
src/IO/Filesystem/Directory.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IO\Filesystem;
|
||||||
|
|
||||||
|
use IO\Exception\DirectoryNotFoundException;
|
||||||
|
use IO\Exception\DirectoryNotReadableException;
|
||||||
|
use IO\Exception\NotADirectoryException;
|
||||||
|
|
||||||
|
class Directory
|
||||||
|
{
|
||||||
|
private string $directory;
|
||||||
|
|
||||||
|
private function __construct(string $directory)
|
||||||
|
{
|
||||||
|
$this->directory = rtrim($directory, DIRECTORY_SEPARATOR);
|
||||||
|
$this->guardUnusableDirectory($directory);
|
||||||
|
$this->directory = realpath($directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromString(?string $directory): self
|
||||||
|
{
|
||||||
|
return new self($directory ?? getcwd());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return $this->directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function guardUnusableDirectory(string $directory): void
|
||||||
|
{
|
||||||
|
if (!file_exists($directory)) {
|
||||||
|
throw new DirectoryNotFoundException($directory);
|
||||||
|
}
|
||||||
|
if (!is_dir($directory)) {
|
||||||
|
throw new NotADirectoryException($directory);
|
||||||
|
}
|
||||||
|
if (!is_readable($directory)) {
|
||||||
|
throw new DirectoryNotReadableException($directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/IO/Filesystem/File.php
Normal file
44
src/IO/Filesystem/File.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IO\Filesystem;
|
||||||
|
|
||||||
|
use IO\Exception\FileNotFoundException;
|
||||||
|
use IO\Exception\FileNotReadableException;
|
||||||
|
use SplFileInfo;
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
private SplFileInfo $info;
|
||||||
|
|
||||||
|
private function __construct(string $filepath)
|
||||||
|
{
|
||||||
|
$this->guardUnusableFile($filepath);
|
||||||
|
$filepath = realpath($filepath);
|
||||||
|
$this->info = new SplFileInfo($filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromString(string $filepath): self
|
||||||
|
{
|
||||||
|
return new self($filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInfo(): SplFileInfo
|
||||||
|
{
|
||||||
|
return $this->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return (string)$this->getInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function guardUnusableFile(string $file): void
|
||||||
|
{
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
throw new FileNotFoundException($file);
|
||||||
|
}
|
||||||
|
if (!is_readable($file)) {
|
||||||
|
throw new FileNotReadableException($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,13 @@ namespace IO\Input;
|
|||||||
|
|
||||||
trait ArgvAccess
|
trait ArgvAccess
|
||||||
{
|
{
|
||||||
protected static function getArguments(): array
|
protected static function getScriptArgs(): array
|
||||||
{
|
{
|
||||||
// Get local copy of $argv
|
// local copy of $argv
|
||||||
global $argv;
|
global $argv;
|
||||||
$arguments = $argv;
|
$arguments = $argv;
|
||||||
|
|
||||||
// Lose the script name
|
// shift off the script name
|
||||||
array_shift($arguments);
|
array_shift($arguments);
|
||||||
|
|
||||||
return $arguments;
|
return $arguments;
|
||||||
|
@ -3,38 +3,32 @@
|
|||||||
namespace IO\Input;
|
namespace IO\Input;
|
||||||
|
|
||||||
use Filter\DocumentFilter;
|
use Filter\DocumentFilter;
|
||||||
use Filter\FilterFactory;
|
use Filter\FilterParser;
|
||||||
use IO\Exception\DirectoryNotFoundException;
|
use IO\Filesystem\Directory;
|
||||||
use IO\Exception\DirectoryNotReadableException;
|
|
||||||
use IO\Exception\NotADirectoryException;
|
|
||||||
|
|
||||||
class FinderArguments
|
class FinderArguments
|
||||||
{
|
{
|
||||||
use ArgvAccess;
|
use ArgvAccess;
|
||||||
|
|
||||||
private ?string $directory;
|
private Directory $directory;
|
||||||
private array $filters;
|
private array $filters;
|
||||||
|
|
||||||
public static function createFromGlobals(): self
|
public static function createFromGlobals(): self
|
||||||
{
|
{
|
||||||
$arguments = self::getArguments();
|
$arguments = self::getScriptArgs();
|
||||||
|
$directory = array_shift($arguments);
|
||||||
|
|
||||||
$dir = array_shift($arguments) ?? getcwd();
|
return new self($directory, $arguments);
|
||||||
$dir = rtrim($dir, DIRECTORY_SEPARATOR);
|
|
||||||
|
|
||||||
return new self($dir, $arguments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(?string $directory, array $filters)
|
public function __construct(?string $directory, array $filters)
|
||||||
{
|
{
|
||||||
$this->guardUnusableDirectory($directory);
|
$factory = new FilterParser();
|
||||||
$this->directory = realpath($directory);
|
$this->directory = Directory::fromString($directory);
|
||||||
|
$this->filters = array_map([$factory, 'parse'], $filters);
|
||||||
$factory = new FilterFactory();
|
|
||||||
$this->filters = array_map([$factory, 'createFromString'], $filters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDirectory(): string
|
public function getDirectory(): Directory
|
||||||
{
|
{
|
||||||
return $this->directory;
|
return $this->directory;
|
||||||
}
|
}
|
||||||
@ -46,17 +40,4 @@ class FinderArguments
|
|||||||
{
|
{
|
||||||
return $this->filters;
|
return $this->filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function guardUnusableDirectory(string $directory): void
|
|
||||||
{
|
|
||||||
if (!file_exists($directory)) {
|
|
||||||
throw new DirectoryNotFoundException($directory);
|
|
||||||
}
|
|
||||||
if (!is_dir($directory)) {
|
|
||||||
throw new NotADirectoryException($directory);
|
|
||||||
}
|
|
||||||
if (!is_readable($directory)) {
|
|
||||||
throw new DirectoryNotReadableException($directory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,44 +2,31 @@
|
|||||||
|
|
||||||
namespace IO\Input;
|
namespace IO\Input;
|
||||||
|
|
||||||
use IO\Exception\FileNotFoundException;
|
|
||||||
use IO\Exception\FileNotReadableException;
|
|
||||||
use IO\Exception\MissingFileArgumentException;
|
use IO\Exception\MissingFileArgumentException;
|
||||||
use SplFileInfo;
|
use IO\Filesystem\File;
|
||||||
|
|
||||||
class ShowInfoArguments
|
class ShowInfoArguments
|
||||||
{
|
{
|
||||||
use ArgvAccess;
|
use ArgvAccess;
|
||||||
|
|
||||||
private SplFileInfo $file;
|
private File $file;
|
||||||
|
|
||||||
public static function createFromGlobals(): self
|
public static function createFromGlobals(): self
|
||||||
{
|
{
|
||||||
$arguments = self::getArguments();
|
$arguments = self::getScriptArgs();
|
||||||
return new self(array_shift($arguments));
|
return new self(array_shift($arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(?string $file)
|
public function __construct(?string $filepath)
|
||||||
{
|
{
|
||||||
$this->guardUnusableFile($file);
|
if (is_null($filepath)) {
|
||||||
$this->file = new SplFileInfo($file);
|
throw new MissingFileArgumentException();
|
||||||
|
}
|
||||||
|
$this->file = File::fromString($filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFile(): SplFileInfo
|
public function getFile(): File
|
||||||
{
|
{
|
||||||
return $this->file;
|
return $this->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function guardUnusableFile(string $file): void
|
|
||||||
{
|
|
||||||
if (is_null($file)) {
|
|
||||||
throw new MissingFileArgumentException();
|
|
||||||
}
|
|
||||||
if (!file_exists($file)) {
|
|
||||||
throw new FileNotFoundException($file);
|
|
||||||
}
|
|
||||||
if (!is_readable($file)) {
|
|
||||||
throw new FileNotReadableException($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@ namespace IO\Output;
|
|||||||
use PDF\Document;
|
use PDF\Document;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class DocumentOutput implements Output
|
class DocumentDetails implements Output
|
||||||
{
|
{
|
||||||
private Document $document;
|
private Document $document;
|
||||||
|
|
||||||
public function __construct(Document $document)
|
private function __construct(Document $document)
|
||||||
{
|
{
|
||||||
$this->document = $document;
|
$this->document = $document;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function forDocument(Document $document): self
|
public static function of(Document $document): self
|
||||||
{
|
{
|
||||||
return new self($document);
|
return new self($document);
|
||||||
}
|
}
|
@ -5,17 +5,17 @@ namespace IO\Output;
|
|||||||
use PDF\Document;
|
use PDF\Document;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class DocumentListingOutput implements Output
|
class DocumentListing implements Output
|
||||||
{
|
{
|
||||||
/** @var Document[] */
|
/** @var Document[] */
|
||||||
private iterable $documents;
|
private iterable $documents;
|
||||||
|
|
||||||
public function __construct(iterable $documents)
|
private function __construct(iterable $documents)
|
||||||
{
|
{
|
||||||
$this->documents = $documents;
|
$this->documents = $documents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function forDocuments(iterable $documents): self
|
public static function of(iterable $documents): self
|
||||||
{
|
{
|
||||||
return new self($documents);
|
return new self($documents);
|
||||||
}
|
}
|
||||||
@ -55,10 +55,10 @@ class DocumentListingOutput implements Output
|
|||||||
|
|
||||||
foreach ($this->documents as $document) {
|
foreach ($this->documents as $document) {
|
||||||
$template->addRow([
|
$template->addRow([
|
||||||
$document->file->getBasename(),
|
$document->file->getInfo()->getBasename(),
|
||||||
$document->metadata->title,
|
$document->metadata->title,
|
||||||
$document->metadata->author,
|
$document->metadata->author,
|
||||||
$document->file->getPath(),
|
$document->file->getInfo()->getPath(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -13,13 +13,11 @@ class Pdfinfo
|
|||||||
$lines = $this->shellExec('pdfinfo', '-isodates', $filepath);
|
$lines = $this->shellExec('pdfinfo', '-isodates', $filepath);
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
foreach ($lines as $line) {
|
collect($lines)
|
||||||
$parts = explode(':', $line, 2);
|
->map(fn(string $line) => explode(':', $line, 2))
|
||||||
if (count($parts) === 2) {
|
->filter(fn(array $parts) => count($parts) === 2)
|
||||||
$data[trim($parts[0])] = trim($parts[1]);
|
->each(fn(array $parts) => $data[trim($parts[0])] = trim($parts[1]));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new Metadata)->fillWith($data);
|
return Metadata::fill($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,28 +2,28 @@
|
|||||||
|
|
||||||
namespace PDF;
|
namespace PDF;
|
||||||
|
|
||||||
|
use IO\Filesystem\File;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use SplFileInfo;
|
|
||||||
|
|
||||||
class Document
|
class Document
|
||||||
{
|
{
|
||||||
public SplFileInfo $file;
|
public File $file;
|
||||||
public Metadata $metadata;
|
public Metadata $metadata;
|
||||||
|
|
||||||
public function __construct(SplFileInfo $file, ?Metadata $metadata = null)
|
public function __construct(File $file, Metadata $metadata)
|
||||||
{
|
{
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
$this->metadata = $metadata ?? new Metadata();
|
$this->metadata = $metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProperty(string $prop): ?string
|
public function getProperty(string $prop): ?string
|
||||||
{
|
{
|
||||||
if (in_array($prop, ['path', 'filepath'])) {
|
if (in_array($prop, ['path', 'filepath'])) {
|
||||||
return $this->file->getPath();
|
return (string)$this->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($prop, ['file', 'name', 'filename'])) {
|
if (in_array($prop, ['file', 'name', 'filename'])) {
|
||||||
return $this->file->getBasename();
|
return $this->file->getInfo()->getBasename();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_exists($this->metadata, $prop)) {
|
if (property_exists($this->metadata, $prop)) {
|
||||||
@ -35,9 +35,11 @@ class Document
|
|||||||
|
|
||||||
public function getProperties(): array
|
public function getProperties(): array
|
||||||
{
|
{
|
||||||
|
$info = $this->file->getInfo();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'filepath' => $this->file->getPath(),
|
'filepath' => $info->getPath(),
|
||||||
'filename' => $this->file->getBasename(),
|
'filename' => $info->getBasename(),
|
||||||
] + $this->metadata->toArray();
|
] + $this->metadata->toArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,28 @@ class Metadata
|
|||||||
public ?string $title = null;
|
public ?string $title = null;
|
||||||
public ?string $userproperties = null;
|
public ?string $userproperties = null;
|
||||||
|
|
||||||
public function fillWith(array $array): Metadata
|
private function __construct(array $array)
|
||||||
{
|
{
|
||||||
$slugify = new Slugify(['separator' => '_']);
|
$slugify = new Slugify(['separator' => '_']);
|
||||||
|
$notEmpty = static fn(string $v) => trim($v) !== '';
|
||||||
|
|
||||||
$array = array_filter($array, static fn(string $v) => trim($v) !== '');
|
$array = array_filter($array, $notEmpty);
|
||||||
foreach ($array as $key => $value) {
|
foreach ($array as $key => $value) {
|
||||||
$key = $slugify->slugify($key);
|
$key = $slugify->slugify($key);
|
||||||
if (property_exists(__CLASS__, $key)) {
|
if (property_exists(__CLASS__, $key)) {
|
||||||
$this->{$key} = trim($value);
|
$this->{$key} = trim($value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
public static function fill(array $data): Metadata
|
||||||
|
{
|
||||||
|
return new self($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function empty(): Metadata
|
||||||
|
{
|
||||||
|
return new self([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toArray(): array
|
public function toArray(): array
|
||||||
|
@ -25,7 +25,7 @@ class RecursiveDocumentLocator
|
|||||||
$documents = [];
|
$documents = [];
|
||||||
foreach ($iterator as $file) {
|
foreach ($iterator as $file) {
|
||||||
if ($this->validate($file)) {
|
if ($this->validate($file)) {
|
||||||
$documents[] = $this->documentFactory->createDocument($file);
|
$documents[] = $this->documentFactory->fromFile($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
tests/ExampleDocumentAccess.php
Normal file
29
tests/ExampleDocumentAccess.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use IO\Filesystem\File;
|
||||||
|
use PDF\Document;
|
||||||
|
use PDF\Metadata;
|
||||||
|
|
||||||
|
trait ExampleDocumentAccess
|
||||||
|
{
|
||||||
|
protected function exampleDocument(?Metadata $metadata = null): Document
|
||||||
|
{
|
||||||
|
return new Document(
|
||||||
|
$this->exampleFile(),
|
||||||
|
$metadata ?? Metadata::empty()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function exampleDocumentWithMetadata(array $data): Document
|
||||||
|
{
|
||||||
|
return new Document(
|
||||||
|
$this->exampleFile(),
|
||||||
|
Metadata::fill($data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function exampleFile(): File
|
||||||
|
{
|
||||||
|
return File::fromString(__DIR__ . '/resources/example.pdf');
|
||||||
|
}
|
||||||
|
}
|
47
tests/Filter/FilterParserTest.php
Normal file
47
tests/Filter/FilterParserTest.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Filter;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use TypeError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Filter\FilterParser
|
||||||
|
*/
|
||||||
|
class FilterParserTest extends TestCase
|
||||||
|
{
|
||||||
|
private FilterParser $parser;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->parser = new FilterParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesSpecificFilters(): void
|
||||||
|
{
|
||||||
|
self::assertContainsOnlyInstancesOf(SpecificFilter::class, [
|
||||||
|
$this->parser->parse('title=poo'),
|
||||||
|
$this->parser->parse('1='),
|
||||||
|
$this->parser->parse('filepath=some_thing_else'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertNotInstanceOf(SpecificFilter::class, $this->parser->parse('='));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesGenericFilters(): void
|
||||||
|
{
|
||||||
|
// Basically, anything that does not match the pattern .+=.*
|
||||||
|
self::assertContainsOnlyInstancesOf(GenericFilter::class, [
|
||||||
|
$this->parser->parse('scoobypoo'),
|
||||||
|
$this->parser->parse('324234'),
|
||||||
|
$this->parser->parse(324234),
|
||||||
|
$this->parser->parse('baz'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotTakeNull(): void
|
||||||
|
{
|
||||||
|
$this->expectException(TypeError::class);
|
||||||
|
$this->parser->parse(null);
|
||||||
|
}
|
||||||
|
}
|
84
tests/Filter/GenericFilterTest.php
Normal file
84
tests/Filter/GenericFilterTest.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Filter;
|
||||||
|
|
||||||
|
use ExampleDocumentAccess;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use TypeError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Filter\GenericFilter
|
||||||
|
*/
|
||||||
|
class GenericFilterTest extends TestCase
|
||||||
|
{
|
||||||
|
use ExampleDocumentAccess;
|
||||||
|
|
||||||
|
public function testAllowsWhenMatchBasenameOfFile(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('example');
|
||||||
|
$document = $this->exampleDocument();
|
||||||
|
|
||||||
|
self::assertTrue($filter->allows($document));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAllowsWhenMatchesPathToFile(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('resources');
|
||||||
|
$document = $this->exampleDocument();
|
||||||
|
|
||||||
|
self::assertTrue($filter->allows($document));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAllowsWhenMatchesAnyMetadataField(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('John Snow');
|
||||||
|
$document = $this->exampleDocumentWithMetadata([
|
||||||
|
'title' => 'some title',
|
||||||
|
'author' => 'John Snow',
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertTrue($filter->allows($document));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisallowsWhenNotMatchingBasenameOfFile(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('not-an-example');
|
||||||
|
$document = $this->exampleDocument();
|
||||||
|
|
||||||
|
self::assertFalse($filter->allows($document));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisallowsWhenNotMatchingPathToFile(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('this-is-definitely-not-in-the-path' . md5(time()));
|
||||||
|
$document = $this->exampleDocument();
|
||||||
|
|
||||||
|
self::assertFalse($filter->allows($document));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisallowsWhenNotMatchingAnyMetadataField(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('peepee');
|
||||||
|
$document = $this->exampleDocumentWithMetadata([
|
||||||
|
'title' => 'some title',
|
||||||
|
'author' => 'John Snow',
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertFalse($filter->allows($document));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStringRepresentation(): void
|
||||||
|
{
|
||||||
|
$filter = new GenericFilter('i-am-a-field');
|
||||||
|
self::assertEquals(
|
||||||
|
'[*] contains \'i-am-a-field\'',
|
||||||
|
(string)$filter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotAcceptNull(): void
|
||||||
|
{
|
||||||
|
$this->expectException(TypeError::class);
|
||||||
|
new GenericFilter(null);
|
||||||
|
}
|
||||||
|
}
|
16
tests/Filter/SpecificFilterTest.php
Normal file
16
tests/Filter/SpecificFilterTest.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Filter;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Filter\GenericFilter
|
||||||
|
*/
|
||||||
|
class SpecificFilterTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
self::markTestIncomplete('Not implemented');
|
||||||
|
}
|
||||||
|
}
|
0
tests/resources/example.pdf
Normal file
0
tests/resources/example.pdf
Normal file
Loading…
Reference in New Issue
Block a user