First working version with non working routes
This commit is contained in:
commit
503d8c524a
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
vendor/
|
9
README.md
Normal file
9
README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Todos:
|
||||||
|
- [ ] Collect routes properly
|
||||||
|
- [ ] Process routes correctly
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
Currently the routes are hardcoded, we need we way to process
|
||||||
|
all classes maybe and sort them into a list of routes.
|
14
app/Controller/BaseController.php
Normal file
14
app/Controller/BaseController.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Ardent\Undercurrent\Attribute\Route;
|
||||||
|
|
||||||
|
class BaseController
|
||||||
|
{
|
||||||
|
#[Route('/hello')]
|
||||||
|
public function HelloWorld(): string
|
||||||
|
{
|
||||||
|
return 'Hello, World!';
|
||||||
|
}
|
||||||
|
}
|
9
app/Kernel.php
Normal file
9
app/Kernel.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Ardent\Undercurrent\Kernel\BaseKernel;
|
||||||
|
|
||||||
|
class Kernel extends BaseKernel
|
||||||
|
{
|
||||||
|
}
|
9
app/public/index.php
Normal file
9
app/public/index.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Kernel;
|
||||||
|
|
||||||
|
require_once dirname(__DIR__).'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$kernel = new Kernel();
|
||||||
|
|
||||||
|
$kernel();
|
15
composer.json
Normal file
15
composer.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "ardent/undercurrent",
|
||||||
|
"description": "A tiny no nonsense php framework",
|
||||||
|
"type": "library",
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Ardent\\Undercurrent\\": "src/",
|
||||||
|
"App\\": "app/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"license": "GPL-3.0-only"
|
||||||
|
}
|
20
composer.lock
generated
Normal file
20
composer.lock
generated
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "04c6989f1bd672a6accd35142e2adac1",
|
||||||
|
"packages": [],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.2.0"
|
||||||
|
}
|
15
src/Attribute/Route.php
Normal file
15
src/Attribute/Route.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ardent\Undercurrent\Attribute;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute]
|
||||||
|
class Route
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $path,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
83
src/Collector/ClassAttributeCollector.php
Normal file
83
src/Collector/ClassAttributeCollector.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
54
src/Container/GenericContainer.php
Normal file
54
src/Container/GenericContainer.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
31
src/Controller/GenericRouter.php
Normal file
31
src/Controller/GenericRouter.php
Normal 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
28
src/Kernel/BaseKernel.php
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user