Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
Setup MVC pattern (#39)
Browse files Browse the repository at this point in the history
* fix(makefile): add makefile

* fix(readme): config, tests

* feat(routing): update route system

* feat(with): implement with method like laravel

* fix(controller): send data from controller to view

* feat(errors): abort pages
  • Loading branch information
AlxisHenry committed Jan 12, 2023
1 parent 023b63a commit 9ef1911
Show file tree
Hide file tree
Showing 18 changed files with 367 additions and 77 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,22 @@ return [
/**
* Files settings
*/
'MAX_FILE_SIZE' => 50000000, // value in bytes (default: 50MB)
'MAX_FILE_SIZE' => "50000000", // value in bytes (default: 50MB)
];
```

### :test_tube: Tests

**Run linters**

```
make lint
```

**Run the tests using the following command**

```
npm run tests
make tests || npm run tests
```

## :wave: Authors
Expand Down
17 changes: 4 additions & 13 deletions app/Classes/Redirect.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
<?php

declare(strict_types=1);

class Redirect {

/**
* @param string $url
*
* @return void
* @param string $route
*/
public static function to(string $url): void
public static function to(string $route): void
{
if (!Route::check($url)) $url = '/';
header("Location: $url");
header("Location: $route");
}

/**
Expand All @@ -21,11 +16,7 @@ public static function to(string $url): void
public static function back(): void
{
$previous = explode('/', $_SERVER['HTTP_REFERER'])[3];
if (Route::check($previous)) {
header("Location: /$previous");
} else {
header("Location: /");
}
header("Location: /$previous");
}

}
141 changes: 108 additions & 33 deletions app/Classes/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,134 @@

declare(strict_types=1);

class Route {
class Route extends RouteManager {

/**
* @var array<int,string> $routes
* @var string $method
*/
private static array $routes = [
0 => '',
1 => 'archive',
2 => 'upload',
];

private string $method;

/**
* @var ?string $name
*/
private ?string $name;

/**
* @var string $callback
*/
private string $callback;

/**
* @var string|false $route
* @var string $uri
*/
private static string|false $route;
private string $uri;

/**
* @param string $route
* @return bool
* @param string $uri
* @param string $callback
*
* @return Route
*/
public static function check(string $route): bool
public static function get(string $uri, string $callback): Route
{
return in_array($route, self::$routes);
return new Route(method: "GET", uri: $uri, callback: $callback);
}

/**
* @param string $uri
* @param string $callback
*
* @return Route
*/
public static function post(string $uri, string $callback): Route
{
return new Route(method: "POST", uri: $uri, callback: $callback);
}

/**
* @param array<string,string> $properties
*/
public function __construct(string ...$properties) /** @phpstan-ignore-line */
{
$this->setProperties($properties);
}

/**
* @param array<string, string>
* @return void
*/
public static function make(): void
private function setProperties(array $properties): void /** @phpstan-ignore-line */
{
$route = array_search(explode('/', $_SERVER['REQUEST_URI'])[1], self::$routes);
self::$route = array_key_exists((int) $route, self::$routes) ? self::$routes[$route] : false;
$this->setMethod(method: $properties["method"]);
$this->uri = $properties["uri"];
$this->callback = $properties["callback"];
}

/**
* @param string $method
* @return void
*/
public static function view(): void
{
$viewPath = __DIR__ . '/../../resources/views/pages';
switch (self::$route) {
case '':
include_once "$viewPath/dashboard.php";
break;
case 'archive':
include_once "$viewPath/zip.php";
break;
case 'upload':
include_once "$viewPath/upload.php";
break;
default:
break;
private function setMethod(string $method): void
{
$this->method = $this->availableMethod($method) ? $method : "GET";
}

/**
* @throws Exception
* @return void
*/
public function call(): void
{
$method = $_SERVER["REQUEST_METHOD"];

if ($method !== $this->getMethod()) {
View::abort("405", header: true);
return;
}

try {
$callback = explode('@', $this->callback);
$controller = $callback[0];
$method = $callback[1];
$closure = new $controller();
$closure->$method();
} catch (\Throwable $th) {
throw new Exception("Invalid controller name in route call method $th");
}
}

}
/**
* @param string $name
* @return Route
*/
public function name(string $name): Route
{
$this->name = $name;
return $this;
}

/**
* @return ?string
*/
public function getName(): ?string
{
return $this->name;
}

/**
* @return string
*/
public function getUri(): string
{
return $this->uri;
}

/**
* @return string
*/
public function getMethod(): string
{
return $this->method;
}

}
23 changes: 23 additions & 0 deletions app/Classes/RouteManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

class RouteManager {

/**
* @var array<string> METHODS
*/
protected const METHODS = ["GET", "POST"];

public function __construct() {}

/**
* @param string $method
* @return bool
*/
protected function availableMethod(string $method): bool
{
return in_array($method, $this::METHODS);
}

}
48 changes: 48 additions & 0 deletions app/Classes/Router.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

class Router {

/**
* @var array $routes<int,Route>
*/
public array $routes; /** @phpstan-ignore-line */

/**
* @params array<Route> $routes
* @return Router
*/
public static function load(array $routes): Router /** @phpstan-ignore-line */
{
foreach ($routes as $route) {
if (!is_object($route) && !($route instanceof Route)) { /** @phpstan-ignore-line */
throw new Exception("Route given to Router isn't instance of Route class.");
}
}
return new Router($routes);
}

/**
* @param array<int,Route> $routes
*/
public function __construct(array $routes)
{
$this->routes = $routes;
}

/**
* @return void
*/
public function run(): void
{
foreach ($this->routes as $route) {
if (explode('?', $_SERVER["REQUEST_URI"])[0] === $route->getUri()) {
$route->call();
return;
}
}
View::abort("404", header: true);
}

}
61 changes: 61 additions & 0 deletions app/Classes/View.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

class View {

/**
* @var string ROOT
*/
public const ROOT = __DIR__ . "/../../resources/views";

/**
* @param string $view
* @return string
*/
public static function find(string $view): string
{
$el = explode(".", $view);
if (count($el) === 1) return $el[0];
$view = self::ROOT;
foreach ($el as $l) {
$view .= "/$l";
}
$view .= ".php";
return $view;
}

/**
* @param string $view
* @param array $data
* @throws Exception
* @return void
*/
public static function show(string $view, array $data = []): void
{
try {
foreach ($data as $k => $v) { $$k = $v; }
include self::ROOT . "/layouts/head.php";
include self::find($view);
include self::ROOT . "/layouts/foot.php";
} catch (\Throwable $th) {
throw new Exception("Invalid path to view given to View::show() static function $th");
}
}

/**
* @param string $view
* @param bool $header
* @param array $data
* @return void
*/
public static function abort(string $view, bool $header = false, array $data = []): void
{
try {
if ($header) include self::ROOT . "/layouts/head.php";
include self::find("errors.$view");
if ($header) include self::ROOT . "/layouts/foot.php";
} catch (\Throwable $th) {
throw new Exception("Invalid path to view given to View::show() static function $th");
}
}

}
Loading

0 comments on commit 9ef1911

Please sign in to comment.