attribute-spass/src/Infrastructure/Finder.php
lubiana 8b353ec62a
apply php styler
Signed-off-by: lubiana <lubiana123@gmail.com>
2023-09-26 18:24:12 +02:00

126 lines
3.5 KiB
PHP

<?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()];
}
}
}
}
}