diff --git a/src/Core/Router.php b/src/Core/Router.php new file mode 100644 index 0000000..af11c00 --- /dev/null +++ b/src/Core/Router.php @@ -0,0 +1,52 @@ +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); + } +} diff --git a/src/Core/Session.php b/src/Core/Session.php new file mode 100644 index 0000000..2c0fb40 --- /dev/null +++ b/src/Core/Session.php @@ -0,0 +1,73 @@ + 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; + } +} diff --git a/src/Core/View.php b/src/Core/View.php new file mode 100644 index 0000000..1b614e7 --- /dev/null +++ b/src/Core/View.php @@ -0,0 +1,39 @@ +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(); + } +}