Skip to content

Commit

Permalink
Refactor MVC to enable custom page titles and JSON API support
Browse files Browse the repository at this point in the history
  • Loading branch information
KreerC committed Mar 17, 2024
1 parent 9ff47f5 commit 24cc87e
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 83 deletions.
44 changes: 37 additions & 7 deletions src/Frontend/BasePage/BasePageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@
/**
* Renders the basic structure of a page and handles routing for the main content
*/
class BasePageController implements Controller
class BasePageController extends Controller
{

private BasePageRenderer $renderer;

private Router $router;

private mixed $subController;

private array $routeData = [];

public function __construct(BasePageRenderer $renderer)
{
$this->renderer = $renderer;

$this->router = $this->getRenderer()->getRouter();
$sub = $this->router->getControllerForRequest(Router::getRequestMethod(), Router::getRequestUri());
$this->subController = $sub[0];
$this->routeData = $sub[1];
}

/**
Expand All @@ -28,31 +39,50 @@ public function getRenderer(): BasePageRenderer
return $this->renderer;
}

public function run(array $data = [])
public function run(array $data = []): void
{

// Handle JSON
if ($this->subController instanceof Controller && $this->subController->getDisplayType() === "json") {
header("Content-Type: application/json");
$this->subController->run($this->routeData);
return;
}

?>

<!DOCTYPE html>
<html lang="<?php echo Localize::translate("locale", "en") ?>">

<head>
<?php HeadView::render($data); ?>
<?php
$head = new HeadView();
$head->render(["title" => $this->subController instanceof Controller ? $this->subController->getPageTitle() : ""]);
?>
</head>

<body>
<?php NavigationView::render($data); ?>
<?php
$nav = new NavigationView();
$nav->render([]);
?>

<main>
<div class="container mt-3">
<?php
$router = $this->getRenderer()->getRouter();
$router->handleRequest(Router::getRequestMethod(), Router::getRequestUri());
if ($this->subController instanceof Controller) {
$this->subController->run($this->routeData);
} else if (is_callable($this->subController)) {
$callable = $this->subController;
$callable($this->routeData);
}
?>
</div>
</main>

<footer class="mt-5">
<?php FooterView::render($data); ?>
<?php $footer = new FooterView();
$footer->render([]); ?>
</footer>
</body>

Expand Down
4 changes: 2 additions & 2 deletions src/Frontend/BasePage/FooterView.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
/**
* Outputs the content of the <footer> tag
*/
class FooterView implements View
class FooterView extends View
{

public static function render(array $data = [])
public function render(array $data = []): void
{
?>
<hr class="mb-3" aria-hidden="true">
Expand Down
11 changes: 8 additions & 3 deletions src/Frontend/BasePage/HeadView.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@
/**
* Defines all meta information in the pages' <head> tag
*/
class HeadView implements View
class HeadView extends View
{

public static function render(array $data = [])
public function render(array $data = []): void
{
if (!empty($data["title"]))
$title = $data['title'] . " - " . Application::getInstance()->getConfig()["app"]["name"];
else
$title = Application::getInstance()->getConfig()["app"]["name"];

?>
<title>
<?php echo Application::NAME; // TODO needs to change dynamically to what the current page is ?>
<?php echo $title; ?>
</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@

use A11yBuddy\Application;
use A11yBuddy\Frontend\Localize;
use A11yBuddy\Frontend\View;
use A11yBuddy\Frontend\Controller;

class HomepageView implements View
class HomepageController extends Controller
{

public function getPageTitle(): string
{
return Localize::translate("welcome", "Welcome to a11yBuddy");
}

//TODO - we need a much better homepage with some actual content

public static function render(array $data = [])
public function run(array $data = []): void
{
?>
<h1>
Expand Down
4 changes: 2 additions & 2 deletions src/Frontend/BasePage/NavigationView.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
/**
* Renders the topmost navbar
*/
class NavigationView implements View
class NavigationView extends View
{

public static function render(array $data = [])
public function render(array $data = []): void
{
?>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@
namespace A11yBuddy\Frontend\BasePage;

use A11yBuddy\Frontend\Localize;
use A11yBuddy\Frontend\View;
use A11yBuddy\Frontend\Controller;

/**
* The default view that can be used for when something does not exist.
* A controller that is invoked when something does not exist.
* Sends a 404 response code automatically.
*/
class NotFoundView implements View
class NotFoundController extends Controller
{

public static function render(array $data = [])
public function getPageTitle(): string
{
return Localize::translate("not_found", "Page Not Found");
}

public function run(array $data = []): void
{
http_response_code(404);
?>
Expand Down
15 changes: 6 additions & 9 deletions src/Frontend/BasePageRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

use A11yBuddy\Application;
use A11yBuddy\Frontend\BasePage\BasePageController;
use A11yBuddy\Frontend\BasePage\HomepageController;
use A11yBuddy\Frontend\BasePage\NotFoundController;
use A11yBuddy\Frontend\CreateProject\CreateProjectController;
use A11yBuddy\Frontend\CreateProject\CreateProjectView;
use A11yBuddy\Frontend\BasePage\HomepageView;
use A11yBuddy\Frontend\BasePage\NotFoundView;
use A11yBuddy\Router;

/**
Expand Down Expand Up @@ -37,14 +37,11 @@ public function render(): void
*/
private function registerRoutes()
{
// Add special routes
$this->router->addRoute("GET", "/404", [NotFoundView::class, "render"]);

// All other routes
$this->router->addRoute("GET", "/", [HomepageView::class, "render"]);
$this->router->addRoute("GET", "/", HomepageController::class);

$this->router->addRoute("GET", "/create", [CreateProjectView::class, "render"]);
$this->router->addRoute("POST", "/create", [CreateProjectController::class, "run"]);
$this->router->addRoute("GET", "/create", CreateProjectController::class);
$this->router->addRoute("POST", "/create", CreateProjectController::class);

// Register custom pages
$customPages = Application::getInstance()->getConfig()["custom_pages"] ?? [];
Expand All @@ -53,7 +50,7 @@ private function registerRoutes()
* TODO: We allow the user to override previously defined routes if they want to supply their own custom landing page.
* This might result in errors if the admin is not careful, so in the future this should be handled differently.
*/
$this->router->addRoute("GET", $route, [CustomPageController::class, "run"], true);
$this->router->addRoute("GET", $route, CustomPageController::class, true);
}
}

Expand Down
36 changes: 34 additions & 2 deletions src/Frontend/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,46 @@
* Controllers are responsible for handling user input and deciding what to do with it.
* They are the glue between the user interface and the application logic.
*/
interface Controller
class Controller
{

/**
* Default function for a controller that runs when it is invoked.
* This should call do the necessary work to handle the user's request,
* like invoking a view.
*
* @param array $data An array of variables parsed from the URI
*/
public function run(array $data = []);
public function run(array $data = []): void
{
return;
}

/**
* Get the title of the page that the controller will return.
* This will be used in the <title> tag of the HTML page.
*/
public function getPageTitle(): string
{
return "";
}

/**
* Get the description of the page that the controller will return.
* This will be used in the <meta name="description"> tag of the HTML page.
*/
public function getPageDescription(): string
{
return "";
}

/**
* Get the type of display that the controller will return.
* Can be "html" or "json".
*/
public function getDisplayType(): string
{
return "html";
}

}
23 changes: 17 additions & 6 deletions src/Frontend/CreateProject/CreateProjectController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,30 @@

namespace A11yBuddy\Frontend\CreateProject;

use A11yBuddy\Application;
use A11yBuddy\Frontend\Controller;

class CreateProjectController implements Controller
class CreateProjectController extends Controller
{

public function run(array $data = [])
public function getPageTitle(): string
{
return 'Create a new project';
}

public function run(array $data = []): void
{
// TODO

// Return the view with an error message for the time being
return CreateProjectView::render([
'error' => 'This feature is not yet implemented'
]);
// Display the view with an error message for the time being
$view = new CreateProjectView();

$errors = [];
if (Application::getInstance()->getBasePageRenderer()->getRouter()->getRequestMethod() === 'POST') {
$errors["error"] = 'This feature is not yet implemented. Please try again later.';
}

$view->render($errors);
}

}
4 changes: 2 additions & 2 deletions src/Frontend/CreateProject/CreateProjectView.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

use A11yBuddy\Frontend\View;

class CreateProjectView implements View
class CreateProjectView extends View
{

public static function render(array $data = [])
public function render(array $data = []): void
{

if (isset($data['error'])) {
Expand Down
27 changes: 20 additions & 7 deletions src/Frontend/CustomPageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
namespace A11yBuddy\Frontend;

use A11yBuddy\Application;
use A11yBuddy\Frontend\BasePage\NotFoundView;
use A11yBuddy\Frontend\BasePage\NotFoundController;
use A11yBuddy\Router;

/**
* Displays the content of a custom page supplied by the user, e.g. an Imprint or Privacy Policy page.
*/
class CustomPageController implements Controller
class CustomPageController extends Controller
{

public function run(array $data = [])
public function getPageTitle(): string
{
//TODO implement custom page names for custom pages
return "";
}

public function run(array $data = []): void
{
$customPages = Application::getInstance()->getConfig()["custom_pages"] ?? [];
$route = Router::getRequestUri();
Expand All @@ -24,8 +30,7 @@ public function run(array $data = [])
$file = $customPages[$route]["files"][$lang] ?? $customPages[$route]["files"]["en"];

if (!file_exists($file)) {
NotFoundView::render();
return;
$this->notFound();
}

$fileContent = file_get_contents($file);
Expand All @@ -40,10 +45,18 @@ public function run(array $data = [])
} else {
throw new \Exception("Unknown custom page type: " . $type);
}

} else {
NotFoundView::render();
$this->notFound();
}
}

/**
* Displays a 404 error page if the custom page does not exist
*/
private function notFound(): void
{
$notFoundController = new NotFoundController();
$notFoundController->run();
}

}
Loading

0 comments on commit 24cc87e

Please sign in to comment.