Compare commits

...

3 commits

Author SHA1 Message Date
Maarten
6eacc7f523 Fix class imports 2024-11-26 14:22:59 +01:00
Maarten
591e0c194d Refactor classes into Http structure 2024-11-26 14:22:04 +01:00
Maarten
83bc1a1661 Add bootstrap factory for framework loading 2024-11-26 14:20:46 +01:00
18 changed files with 280 additions and 70 deletions

14
app/Application.php Normal file
View file

@ -0,0 +1,14 @@
<?php
namespace App;
class Application
{
/**
* @return void
*/
public function bootstrap(): void
{
// init application
}
}

View file

@ -3,8 +3,8 @@
namespace App\Controllers\Api; namespace App\Controllers\Api;
use App\Services\Subnet; use App\Services\Subnet;
use Core\Controllers\Controller; use Core\Http\Controllers\Controller;
use Core\View\Render; use Core\Http\View\Engine;
use Exception; use Exception;
class SubnetController extends Controller class SubnetController extends Controller
@ -12,7 +12,7 @@ class SubnetController extends Controller
/** /**
* Get all subnet data * Get all subnet data
* *
* @return \Core\View\Render * @return \Core\Http\View\Render
*/ */
public function data(): Render public function data(): Render
{ {

View file

@ -2,15 +2,15 @@
namespace App\Controllers; namespace App\Controllers;
use Core\Controllers\Controller; use Core\Http\Controllers\Controller;
use Core\View\Render; use Core\Http\View\Engine;
class HomeController extends Controller class HomeController extends Controller
{ {
/** /**
* Render index * Render index
* *
* @return \Core\View\Render * @return \Core\Http\View\Render
*/ */
public function index(): Render public function index(): Render
{ {

View file

@ -2,15 +2,15 @@
namespace App\Controllers; namespace App\Controllers;
use Core\Controllers\Controller; use Core\Http\Controllers\Controller;
use Core\View\Render; use Core\Http\View\Engine;
class TestController extends Controller class TestController extends Controller
{ {
/** /**
* Render index * Render index
* *
* @return \Core\View\Render * @return \Core\Http\View\Render
*/ */
public function test(int $id): Render public function test(int $id): Render
{ {

View file

@ -20,7 +20,11 @@
"psr-4": { "psr-4": {
"App\\": "app/", "App\\": "app/",
"Core\\": "src/" "Core\\": "src/"
} },
"files": [
"src/Helpers/helpers.php"
]
}, },
"config": { "config": {
"optimize-autoloader": true "optimize-autoloader": true

View file

@ -1,15 +1,8 @@
<?php <?php
use Core\Env\Env; use Core\Bootstrap;
use Core\Routing\Router;
require '../vendor/autoload.php'; require '../vendor/autoload.php';
// Load routes $bootstrap = Bootstrap::createInstance();
require '../config/routes.php'; $bootstrap->handle();
// Load env
Env::load();
// Dispatch router
Router::dispatch();

45
src/Bootstrap.php Normal file
View file

@ -0,0 +1,45 @@
<?php
namespace Core;
use Core\Factory\BootstrapFactory;
class Bootstrap {
/**
* @var \Core\Factory\BootstrapFactory
*/
private static BootstrapFactory $instance;
/**
* Start handling process
*
* @return \Core\Factory\BootstrapFactory
*/
public static function createInstance(): BootstrapFactory
{
self::$instance = (new Bootstrap())->run();
return Bootstrap::getInstance();
}
/**
* Get the instance
*
* @return \Core\Factory\BootstrapFactory
*/
public static function getInstance(): BootstrapFactory
{
return self::$instance;
}
/**
* Create new factory instance
*
* @return \Core\Factory\BootstrapFactory
*/
protected function run(): BootstrapFactory
{
return new BootstrapFactory();
}
}

View file

@ -2,7 +2,6 @@
namespace Core\Exceptions; namespace Core\Exceptions;
use Core\Env\Env;
use Core\Http\Request; use Core\Http\Request;
use Throwable; use Throwable;
use Whoops\Handler\Handler; use Whoops\Handler\Handler;
@ -11,7 +10,7 @@ use Whoops\Handler\PlainTextHandler;
use Whoops\Handler\PrettyPageHandler; use Whoops\Handler\PrettyPageHandler;
use Whoops\Run as Whoops; use Whoops\Run as Whoops;
class Exceptions class ExceptionHandler
{ {
/** /**
* Exceptions handler instance * Exceptions handler instance
@ -41,13 +40,12 @@ class Exceptions
/** /**
* Get correct handler * Get correct handler
* *
* @param \Core\Http\Request|null $request
* @return \Whoops\Handler\Handler * @return \Whoops\Handler\Handler
*/ */
private static function handler(Request|null $request): Handler private static function handler(): Handler
{ {
if (Env::get('debug')) { if (env('debug')) {
if ($request?->is('post')) { if (request()?->is('post')) {
return new JsonResponseHandler(); return new JsonResponseHandler();
} }
@ -60,24 +58,44 @@ class Exceptions
/** /**
* Catch all exceptions * Catch all exceptions
* *
* @param \Core\Http\Request $request
* @return void * @return void
*/ */
public static function catch(Request $request): void public static function catch(): void
{ {
self::instance($request)->register(); self::instance()->register();
} }
/** /**
* Catch single exception * Catch single exception
* *
* @param \Throwable $exception * @param \Throwable $exception
* @return void * @return never
*/ */
public static function catchOne(Throwable $exception): void public static function catchOne(Throwable $exception): never
{ {
self::instance()->handleException($exception); self::instance()->handleException($exception);
exit(0); exit(0);
} }
/**
* Make new exception
*
* @param null $abstract
* @param string|null $message
* @return never
*/
public static function make(mixed $abstract = null, string|null $message = null): never
{
if(is_string($abstract)) {
$abstract = app()->make($abstract, $message);
}
if(is_subclass_of($abstract, 'Exception')) {
self::catchOne($abstract);
}
exit(0);
}
} }

View file

@ -0,0 +1,5 @@
<?php
namespace Core\Exceptions\Exceptions;
class ClassNotFoundException extends \Exception {}

View file

@ -0,0 +1,94 @@
<?php
namespace Core\Factory;
use App\Application;
use Core\Env\Env;
use Core\Exceptions\ExceptionHandler;
use Core\Exceptions\Exceptions\ClassNotFoundException;
use Core\Http\Request;
use Core\Routing\RouteCollection;
use Core\Routing\RouteDispatcher;
class BootstrapFactory
{
private Request $request;
/**
* Handle Http core
*/
public function handle(): void
{
// Load env
Env::load();
// Create request
$this->request = app()->make(Request::class, [$_POST + $_FILES]);
// Capture all exceptions
ExceptionHandler::catch();
// Load routes
require '../config/routes.php';
try {
// Boot application
app()->make(Application::class)->bootstrap();
// Dispatch router
app()->make(RouteDispatcher::class)->dispatch($this->request, RouteCollection::retrieve());
} catch (\Exception $e) {
ExceptionHandler::catchOne($e);
}
}
/**
* @param string $abstract
* @param array $arguments
* @return mixed
*/
public function make(string $abstract, mixed $arguments = []): mixed
{
return $this->resolve($abstract, $arguments);
}
/**
* @param string $abstract
* @param array $arguments
* @return mixed|null
*/
private function resolve(string $abstract, mixed $arguments = []): mixed
{
if (class_exists($abstract)) {
try {
$reflection = new \ReflectionClass($abstract);
return $reflection->newInstanceArgs($arguments);
} catch (\ReflectionException $e) {
ExceptionHandler::catchOne($e);
}
}
ExceptionHandler::make(ClassNotFoundException::class, sprintf("Class '%s' not found", $abstract));
}
/**
* Get the request instance
*
* @return \Core\Http\Request
*/
public function request(): Request
{
return $this->request;
}
/**
* Get path to file/folder in resources folder
*
* @param string $path
* @return string
*/
public function resourcePath(string $path = ''): string
{
return "../resources/" . $path;
}
}

51
src/Helpers/helpers.php Normal file
View file

@ -0,0 +1,51 @@
<?php
use Core\Bootstrap;
use Core\Env\Env;
use Core\Http\Request;
if(!function_exists('app'))
{
/**
* Make abstract of instance or get application instance
*
* @param mixed $abstract
* @param array $arguments
* @return \Core\Factory\BootstrapFactory|mixed
*/
function app(mixed $abstract = null, array $arguments = []): mixed
{
if (is_null($abstract)) {
return Bootstrap::getInstance();
}
return Bootstrap::getInstance()->make($abstract, $arguments);
}
}
if(!function_exists('env'))
{
/**
* Get env variable
*
* @param string $key
* @return bool
*/
function env(string $key): mixed
{
return Env::get($key);
}
}
if (!function_exists('request')) {
/**
* Get the request instance
*
* @return \Core\Http\Request
*/
function request(): Request
{
return app()->request();
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Core\Controllers; namespace Core\Http\Controllers;
use Core\Http\Request; use Core\Http\Request;
use Core\Http\Response; use Core\Http\Response;

View file

@ -2,8 +2,6 @@
namespace Core\Http; namespace Core\Http;
use Core\Exceptions\Exceptions;
class Request class Request
{ {
private array $data = []; private array $data = [];
@ -16,9 +14,6 @@ class Request
public function __construct(array $data) public function __construct(array $data)
{ {
$this->data = $data; $this->data = $data;
// Capture all exceptions
Exceptions::catch($this);
} }
/** /**

View file

@ -2,9 +2,9 @@
namespace Core\Http; namespace Core\Http;
use Core\View\Render; use Core\Http\View\Engine\HtmlEngine;
use Core\View\Render\HtmlRender; use Core\Http\View\Engine\JsonEngine;
use Core\View\Render\JsonRender; use Core\Http\View\Render;
class Response class Response
{ {
@ -25,20 +25,20 @@ class Response
* Render HTML * Render HTML
* *
* @param string $view * @param string $view
* @return \Core\View\Render * @return \Core\Http\View\Render
*/ */
public function view(string $view): Render public function view(string $view): Render
{ {
return (new HtmlRender())->view($view); return (new HtmlEngine())->view($view);
} }
/** /**
* Render JSON * Render JSON
* *
* @return \Core\View\Render * @return \Core\Http\View\Render
*/ */
public function json(): Render public function json(): Render
{ {
return new JsonRender(); return new JsonEngine();
} }
} }

View file

@ -1,10 +1,10 @@
<?php <?php
namespace Core\View\Render; namespace Core\Http\View\Engine;
use Core\View\Render; use Core\Http\View\Render;
class HtmlRender extends Render class HtmlEngine extends Render
{ {
/** /**
* @inheritDoc * @inheritDoc
@ -13,7 +13,7 @@ class HtmlRender extends Render
public function render(): void public function render(): void
{ {
$basePath = $_SERVER['DOCUMENT_ROOT']; $basePath = $_SERVER['DOCUMENT_ROOT'];
$viewsPath = $basePath . '/../resources/views/' . str_replace('.', '/', $this->view) . '.php'; $viewsPath = app()->resourcePath('views/' . str_replace('.', '/', $this->view) . '.php');
if (file_exists($viewsPath)) { if (file_exists($viewsPath)) {
extract($this->data); extract($this->data);

View file

@ -1,10 +1,11 @@
<?php <?php
namespace Core\View\Render; namespace Core\Http\View\Engine;
use Core\View\Render;
class JsonRender extends Render use Core\Http\View\Render;
class JsonEngine extends Render
{ {
/** /**
* @inheritDoc * @inheritDoc

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Core\View; namespace Core\Http\View;
abstract class Render abstract class Render
{ {

View file

@ -2,11 +2,10 @@
namespace Core\Routing; namespace Core\Routing;
use Core\Env\Env; use Core\Exceptions\ExceptionHandler;
use Core\Exceptions\Exceptions;
use Core\Exceptions\Exceptions\NotFoundHttpException; use Core\Exceptions\Exceptions\NotFoundHttpException;
use Core\Http\Request; use Core\Http\Request;
use Core\View\Render; use Core\Http\View\Engine;
use Exception; use Exception;
class RouteDispatcher class RouteDispatcher
@ -26,10 +25,13 @@ class RouteDispatcher
private array $routeCollection; private array $routeCollection;
/** /**
* Dispatch the router dispatcher
*
* @param \Core\Http\Request $request * @param \Core\Http\Request $request
* @param array $routeCollection * @param array $routeCollection
* @return void
*/ */
public function __construct(Request $request, array $routeCollection) public function dispatch(Request $request, array $routeCollection): void
{ {
$this->request = $request; $this->request = $request;
$this->routeCollection = $routeCollection; $this->routeCollection = $routeCollection;
@ -48,18 +50,6 @@ class RouteDispatcher
} }
} }
/**
* Dispatch the router dispatcher
*
* @param \Core\Http\Request $request
* @param array $routeCollection
* @return void
*/
public static function dispatch(Request $request, array $routeCollection): void
{
new self($request, $routeCollection);
}
/** /**
* Locate a matching route for the incoming request. * Locate a matching route for the incoming request.
* *
@ -153,8 +143,8 @@ class RouteDispatcher
*/ */
private function handleException(Exception $e, int $statusCode, string $message): void private function handleException(Exception $e, int $statusCode, string $message): void
{ {
if (Env::get('debug')) { if (env('debug')) {
Exceptions::catchOne($e); ExceptionHandler::catchOne($e);
} }
http_response_code($statusCode); http_response_code($statusCode);