Initial commit, framework/frontend assets setup

This commit is contained in:
Maarten 2024-11-25 18:59:11 +01:00
commit 9d9858bb37
32 changed files with 4651 additions and 0 deletions

View file

@ -0,0 +1,32 @@
<?php
namespace Core\Controllers;
use Core\Http\Request;
use Core\Http\Response;
class Controller
{
/**
* Request handler
*
* @var \Core\Http\Request
*/
protected Request $request;
/**
* Response handler
*
* @var \Core\Http\Response
*/
protected Response $response;
/**
* Load controller helpers
*/
public function __construct(Request $request)
{
$this->request = $request;
$this->response = new Response();
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Core\Exceptions;
use Throwable;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Run as Whoops;
class Exceptions
{
/**
* Exceptions handler instance
*
* @var Whoops
*/
private static Whoops $instance;
/**
* Get exceptions handler instance
*
* @return \Whoops\Run
*/
public static function handler(): Whoops
{
if (!isset(self::$instance)) {
$instance = new Whoops();
$instance->pushHandler(new PrettyPageHandler());
self::$instance = $instance;
}
return self::$instance;
}
/**
* Catch all exceptions
*
* @return void
*/
public static function catch(): void
{
self::handler()->register();
}
/**
* Catch single exception
*
* @param \Throwable $exception
* @return void
*/
public static function catchOne(Throwable $exception): void
{
self::handler()->handleException($exception);
}
}

69
src/Http/Request.php Normal file
View file

@ -0,0 +1,69 @@
<?php
namespace Core\Http;
class Request
{
/**
* Get request method
*
* @return mixed
*/
public function method(): mixed
{
return $_SERVER['REQUEST_METHOD'];
}
/**
* Get request url
*
* @return string
*/
public function url(): string
{
return strtok($_SERVER['REQUEST_URI'], '?');
}
/**
* Check if request is specific method
*
* @param string $method
* @return bool
*/
public function is(string $method): bool
{
return ($this->method() === strtoupper($method));
}
/**
* Check if request has POST data
*
* @param string $param
* @return bool
*/
public final function has(string $param): bool
{
return isset($_POST[$param]);
}
/**
* Get POST data
*
* @param string|null $param
* @param mixed|null $default
* @return mixed
*/
public final function get(string|null $param = null, mixed $default = null): mixed
{
if($param == null) {
return $_POST;
}
if($this->has($param)) {
return $_POST[$param];
}
return $default;
}
}

44
src/Http/Response.php Normal file
View file

@ -0,0 +1,44 @@
<?php
namespace Core\Http;
use Core\View\JsonRender;
use Core\View\Render;
use Core\View\Render\HtmlRender;
class Response
{
/**
* Set statuscode for response
*
* @param int $status
* @return $this
*/
public function status(int $status): static
{
http_response_code($status);
return $this;
}
/**
* Render HTML
*
* @param string $view
* @return \Core\View\Render
*/
public function view(string $view): Render
{
return (new HtmlRender())->view($view);
}
/**
* Render JSON
*
* @return \Core\View\Render
*/
public function json(): Render
{
return new JsonRender();
}
}

92
src/Router/Router.php Normal file
View file

@ -0,0 +1,92 @@
<?php
namespace Core\Router;
use Core\Exceptions\Exceptions;
use Core\Http\Request;
use Core\View\Render;
use Exception;
class Router
{
/**
* List of routes
*
* @var array
*/
protected static array $routes = [];
/**
* Add GET route
*
* @param string $route
* @param string $controller
* @param string $action
* @return void
*/
public static function get(string $route, string $controller, string $action): void
{
self::register($route, $controller, $action, "GET");
}
/**
* Add POST route
*
* @param string $route
* @param string $controller
* @param string $action
* @return void
*/
public static function post(string $route, string $controller, string $action): void
{
self::register($route, $controller, $action, "POST");
}
/**
* Register route
*
* @param string $route
* @param string $controller
* @param string $action
* @param string $method
* @return void
*/
public static function register(string $route, string $controller, string $action, string $method): void
{
self::$routes[$method][$route] = [
'controller' => $controller,
'action' => $action,
];
}
/**
* Dispatch router and run application
*
* @return void
*/
public static function dispatch(): void
{
// Capture all exceptions
Exceptions::catch();
// Init request
$request = new Request();
$url = $request->url();
$method = $request->method();
if (array_key_exists($url, self::$routes[$method])) {
$controller = self::$routes[$method][$url]['controller'];
$action = self::$routes[$method][$url]['action'];
$controller = new $controller($request);
$response = $controller->$action();
if ($response instanceof Render) {
$response->render();
}
} else {
Exceptions::catchOne(new Exception("No route found for: $url"));
}
}
}

16
src/View/JsonRender.php Normal file
View file

@ -0,0 +1,16 @@
<?php
namespace Core\View;
class JsonRender extends Render
{
/**
* @inheritDoc
* @throws \Exception
*/
public function render(): void
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode($this->data);
}
}

58
src/View/Render.php Normal file
View file

@ -0,0 +1,58 @@
<?php
namespace Core\View;
abstract class Render
{
/**
* View data
*
* @var array
*/
protected array $data = [];
/**
* View template
*
* @var string
*/
protected readonly string $view;
/**
* Set view template
*
* @param string $view
* @return $this
*/
public function view(string $view): static
{
$this->view = $view;
return $this;
}
/**
* Add data to the view
*
* @param array|string $key
* @param mixed|null $value
* @return $this
*/
public function with(array|string $key, mixed $value = null): static
{
if (!is_array($key)) {
$key = [$key => $value];
}
$this->data = array_merge($this->data, $key);
return $this;
}
/**
* Render HTML view
*
* @return void
*/
public abstract function render(): void;
}

View file

@ -0,0 +1,28 @@
<?php
namespace Core\View\Render;
use Core\View\Render;
class HtmlRender extends Render
{
/**
* @inheritDoc
* @throws \Exception
*/
public function render(): void
{
$basePath = $_SERVER['DOCUMENT_ROOT'];
$viewsPath = $basePath . '/../resources/views/' . str_replace('.', '/', $this->view) . '.php';
if (file_exists($viewsPath)) {
extract($this->data);
include $viewsPath;
return;
}
throw new \Exception('View not found');
}
}