move code to repository root
This commit is contained in:
parent
47e227257c
commit
9ce2c0ae4c
35 changed files with 2025 additions and 0 deletions
121
src/Infrastructure/Finder.php
Normal file
121
src/Infrastructure/Finder.php
Normal 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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue