First working version with non working routes

This commit is contained in:
Tim
2023-07-28 16:14:55 +02:00
commit 503d8c524a
12 changed files with 288 additions and 0 deletions

15
src/Attribute/Route.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace Ardent\Undercurrent\Attribute;
use Attribute;
#[Attribute]
class Route
{
public function __construct(
public string $path,
)
{
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Ardent\Undercurrent\Collector;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionClass;
class ClassAttributeCollector
{
public function __construct(
private readonly string $path,
private readonly string $attribute,
)
{
}
public function collect(): array
{
$classes = [];
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->path));
foreach ($files as $file) {
if ($file->getExtension() !== 'php') {
continue;
}
$class = $this->getClassFromFile($file);
if (!$class) {
continue;
}
$classes[] = $class;
}
return $classes;
}
private function getClassFromFile(mixed $file)
{
$contents = file_get_contents($file->getPathname());
$tokens = token_get_all($contents);
$namespace = '';
$class = '';
$classFound = false;
$namespaceFound = false;
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] === T_NAMESPACE) {
$namespaceFound = true;
continue;
}
if ($token[0] === T_CLASS) {
$classFound = true;
continue;
}
if ($namespaceFound && $token[0] === T_STRING) {
$namespace .= $token[1] . '\\';
continue;
}
if ($classFound && $token[0] === T_STRING) {
$class = $token[1];
break;
}
}
}
if (!$class) {
return null;
}
$class = $namespace . $class;
$attributes = $this->getClassAttributes($class);
if (!in_array($this->attribute, $attributes)) {
return null;
}
return $class;
}
private function getClassAttributes(string $class): array
{
$attributes = [];
$reflection = new ReflectionClass($class);
foreach ($reflection->getAttributes() as $attribute) {
$attributes[] = $attribute->getName();
}
return $attributes;
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace Ardent\Undercurrent\Container;
use Exception;
class GenericContainer
{
private array $definitions = [];
private array $instances = [];
public function add(string $className, ?callable $definition = null, bool $singleton = true): self
{
if (!$definition) {
$definition = function () use ($className) {
return new $className();
};
}
$this->definitions[$className] = [
'definition' => $definition,
'singleton' => $singleton,
];
return $this;
}
/**
* @template TClassName
* @param class-string<TClassName> $className
* @return TClassName
* @throws Exception
*/
public function get(string $className): object
{
if (!isset($this->definitions[$className])) {
throw new Exception("Class $className not found in container");
}
$definition = $this->definitions[$className]['definition'];
if ($this->definitions[$className]['singleton']) {
if (isset($this->instances[$className])) {
return $this->instances[$className];
}
$instance = $definition();
$this->instances[$className] = $instance;
} else {
$instance = $definition();
}
return $instance;
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Ardent\Undercurrent\Controller;
use App\Controller\BaseController;
use Ardent\Undercurrent\Attribute\Route;
use Ardent\Undercurrent\Collector\ClassAttributeCollector;
class GenericRouter
{
private array $routes = [];
public function __construct()
{
$collector = new ClassAttributeCollector(
__DIR__ . '/../../app/Controller',
Route::class,
);
$this->routes = $collector->collect();
}
public function getRoute(string $route): array
{
// return $this->routes[0];
return [
'controller' => BaseController::class,
'method' => 'HelloWorld',
];
}
}

28
src/Kernel/BaseKernel.php Normal file
View File

@ -0,0 +1,28 @@
<?php
namespace Ardent\Undercurrent\Kernel;
use App\Controller\BaseController;
use Ardent\Undercurrent\Container\GenericContainer;
use Ardent\Undercurrent\Controller\GenericRouter;
class BaseKernel
{
public function __invoke()
{
$container = new GenericContainer();
$container->add(GenericRouter::class);
$container->add(BaseController::class);
$this->render($container);
}
private function render(GenericContainer $container): void
{
$router = $container->get(GenericRouter::class);
$route = $router->getRoute($_SERVER['REQUEST_URI']);
$controller = $container->get($route['controller']);
$method = $route['method'];
echo $controller->$method();
}
}