move code to repository root

This commit is contained in:
lubiana 2023-01-25 22:09:06 +01:00
parent 47e227257c
commit 9ce2c0ae4c
No known key found for this signature in database
35 changed files with 2025 additions and 0 deletions

View file

@ -0,0 +1,121 @@
<?php declare(strict_types=1);
namespace Lubian\AttributeMagic\Infrastructure;
use Iterator;
use Lubian\AttributeMagic\Infrastructure\Event\AsListener;
use Lubian\AttributeMagic\Infrastructure\Event\Listener;
use Lubian\AttributeMagic\Infrastructure\Route\AsHandler;
use Lubian\AttributeMagic\Infrastructure\Route\Handler;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionClass;
use SplFileInfo;
use function array_diff;
use function array_map;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function get_declared_classes;
use function iterator_to_array;
use function serialize;
use function str_ends_with;
use function unserialize;
final class Finder
{
public const CACHE_FILE = __DIR__ . '/../../var/classesCache';
/**
* @param class-string[] $classNames
*/
public function __construct(
private readonly string $path,
private array $classNames = [],
private readonly bool $cached = false,
) {
}
/**
* @return Listener[]
*/
public function getListeners(): array
{
$this->populateClassnames();
return array_map(
static fn (array $h): Listener => new Listener($h[0]->eventClass, $h[0]->priority, $h[1], $h[2]),
iterator_to_array($this->getAttributes(AsListener::class)),
);
}
/**
* @return Handler[]
*/
public function getHandlers(): array
{
$this->populateClassnames();
return array_map(
static fn (array $h): Handler => new Handler($h[0]->method, $h[0]->path, $h[1], $h[2]),
iterator_to_array($this->getAttributes(AsHandler::class)),
);
}
private function populateClassnames(): void
{
if ($this->classNames !== []) {
return;
}
if ($this->cached === true && file_exists(self::CACHE_FILE)) {
$data = file_get_contents(self::CACHE_FILE);
if ($data === false) {
return;
}
/** @var class-string[] $result */
$result = unserialize($data);
$this->classNames = $result;
return;
}
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->path));
/** @var SplFileInfo $file */
foreach ($it as $file) {
if (! str_ends_with((string) $file, '.php')) {
continue;
}
$classesBeforeLoad = get_declared_classes();
require_once (string) $file;
$classesAfterLoad = get_declared_classes();
$this->classNames = [...$this->classNames, ...array_diff($classesAfterLoad, $classesBeforeLoad)];
}
if ($this->cached === true) {
file_put_contents(self::CACHE_FILE, serialize($this->classNames));
}
}
/**
* @template T
* @param class-string<T> $attributeClass
* @return Iterator<array{T, class-string, non-empty-string}>
*/
private function getAttributes(
string $attributeClass
): Iterator {
foreach ($this->classNames as $class) {
$reflectionClass = new ReflectionClass($class);
foreach ($reflectionClass->getMethods() as $method) {
foreach ($method->getAttributes($attributeClass) as $attribute) {
yield [
$attribute->newInstance(),
$class,
$method->getName(),
];
}
}
}
}
}