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