feat(core): add router, session handling and view renderer
This commit is contained in:
1 parent
9a729f1609
commit
e4f8897a65
3 files changed
+164
No files matched your search
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Bazaar\Core;
|
||||
|
||||
final class Router
|
||||
{
|
||||
private array $routes = [];
|
||||
|
||||
public function get(string $path, array $handler, array $middleware = []): void
|
||||
{
|
||||
$this->add('GET', $path, $handler, $middleware);
|
||||
}
|
||||
|
||||
public function post(string $path, array $handler, array $middleware = []): void
|
||||
{
|
||||
$this->add('POST', $path, $handler, $middleware);
|
||||
}
|
||||
|
||||
public function add(string $method, string $path, array $handler, array $middleware = []): void
|
||||
{
|
||||
$this->routes[] = [
|
||||
'method' => $method,
|
||||
'pattern' => $this->compile($path),
|
||||
'handler' => $handler,
|
||||
'middleware' => $middleware,
|
||||
];
|
||||
}
|
||||
|
||||
private function compile(string $path): string
|
||||
{
|
||||
$regex = preg_replace('#\{([a-zA-Z]+)\}#', '(?P<$1>[^/]+)', $path);
|
||||
return '#^' . $regex . '$#';
|
||||
}
|
||||
|
||||
public function match(Request $request): RouteMatch
|
||||
{
|
||||
$pathMatched = false;
|
||||
foreach ($this->routes as $route) {
|
||||
if (!preg_match($route['pattern'], $request->path(), $captured)) {
|
||||
continue;
|
||||
}
|
||||
$pathMatched = true;
|
||||
if ($route['method'] !== $request->method()) {
|
||||
continue;
|
||||
}
|
||||
$params = array_filter($captured, 'is_string', ARRAY_FILTER_USE_KEY);
|
||||
return new RouteMatch($route['handler'], $params, $route['middleware'], 200);
|
||||
}
|
||||
|
||||
return new RouteMatch(null, [], [], $pathMatched ? 405 : 404);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Bazaar\Core;
|
||||
|
||||
final class Session
|
||||
{
|
||||
public function start(): void
|
||||
{
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$secure = str_starts_with((string) Config::get('APP_URL'), 'https://');
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 0,
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'secure' => $secure,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
ini_set('session.use_strict_mode', '1');
|
||||
ini_set('session.use_only_cookies', '1');
|
||||
session_name('bazaarSession');
|
||||
session_start();
|
||||
}
|
||||
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
return $_SESSION[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function put(string $key, mixed $value): void
|
||||
{
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return isset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
public function forget(string $key): void
|
||||
{
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
public function regenerate(): void
|
||||
{
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
session_regenerate_id(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(): void
|
||||
{
|
||||
$_SESSION = [];
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
session_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public function flash(string $key, string $message): void
|
||||
{
|
||||
$_SESSION['flash'][$key] = $message;
|
||||
}
|
||||
|
||||
public function pullFlash(): array
|
||||
{
|
||||
$messages = $_SESSION['flash'] ?? [];
|
||||
unset($_SESSION['flash']);
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Bazaar\Core;
|
||||
|
||||
final class View
|
||||
{
|
||||
private array $shared = [];
|
||||
|
||||
public function __construct(private readonly string $viewsPath)
|
||||
{
|
||||
}
|
||||
|
||||
public function share(string $key, mixed $value): void
|
||||
{
|
||||
$this->shared[$key] = $value;
|
||||
}
|
||||
|
||||
public function render(string $template, array $data = [], string $layout = 'layout', int $status = 200): Response
|
||||
{
|
||||
$content = $this->renderPartial($template, $data);
|
||||
$page = $this->renderPartial($layout, array_merge($data, ['content' => $content]));
|
||||
return Response::html($page, $status);
|
||||
}
|
||||
|
||||
public function renderPartial(string $template, array $data = []): string
|
||||
{
|
||||
$file = $this->viewsPath . '/' . str_replace('.', '/', $template) . '.php';
|
||||
if (!is_file($file)) {
|
||||
throw new \RuntimeException('View not found: ' . $template);
|
||||
}
|
||||
|
||||
extract($this->shared, EXTR_SKIP);
|
||||
extract($data, EXTR_OVERWRITE);
|
||||
|
||||
ob_start();
|
||||
require $file;
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user