diff --git a/public/assets/styles/main.css b/public/assets/styles/main.css new file mode 100644 index 0000000..a08cff0 --- /dev/null +++ b/public/assets/styles/main.css @@ -0,0 +1,29 @@ +body { + background: #1f1f1f; + color: #cdcdcd; +} + +/* unvisited link */ +a:link { + color: #ff8844; + text-decoration: none; +} + +/* visited link */ +a:visited { + color: #ff8844; + text-decoration: none; +} + +/* mouse over link */ +a:hover { + color: #ff8844; + text-decoration: none; +} + +/* selected link */ +a:active { + color: #ff8844; + text-decoration: none; + font-weight: bold; +} \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..f697e3a --- /dev/null +++ b/public/index.php @@ -0,0 +1,13 @@ +<?php +ini_set(option: 'display_errors', value: 1); +ini_set(option: 'display_startup_errors', value: 1); +error_reporting(error_level: E_ALL); + +require dirname(path: __DIR__) . '/src/bootstrap.php'; + +use App\Controller\AddressBook; + +$container = new \App\Service\Container(); + +$addressBook = $container->get(AddressBook::class); +//$addressBook = new AddressBook(); diff --git a/src/Controller/AddressBook.php b/src/Controller/AddressBook.php new file mode 100644 index 0000000..2a2e0ba --- /dev/null +++ b/src/Controller/AddressBook.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Controller; + +use App\Service\Template; +use stdClass; + +class AddressBook extends stdClass +{ + public function __construct(Template $template) + { + $template->render(templateName: 'index.tpl'); + } +} \ No newline at end of file diff --git a/src/Entity/AddressBookEntry.php b/src/Entity/AddressBookEntry.php new file mode 100644 index 0000000..f944311 --- /dev/null +++ b/src/Entity/AddressBookEntry.php @@ -0,0 +1,16 @@ +<?php + +namespace App\Entity; + +class AddressBookEntry +{ + public function __construct( + private int $userid, + private string $first, + private string $last, + private string $nick, + ) + { + // empty body + } +} \ No newline at end of file diff --git a/src/Entity/User.php b/src/Entity/User.php new file mode 100644 index 0000000..29dfd52 --- /dev/null +++ b/src/Entity/User.php @@ -0,0 +1,17 @@ +<?php + +namespace App\Entity; + +class User +{ + public function __construct( + private string $nick, + private string $password, + private string $first = '', + private string $last = '', + private int $id = 0 + ) + { + // empty body + } +} \ No newline at end of file diff --git a/src/Service/Container.php b/src/Service/Container.php new file mode 100644 index 0000000..440bb0b --- /dev/null +++ b/src/Service/Container.php @@ -0,0 +1,33 @@ +<?php + +namespace App\Service; + +use App\Controller\AddressBook; +use Exception; +use stdClass; + +class Container +{ + // no autowiring yet, maybe later, but it might fit for a demo + + private Template $template; + private AddressBook $addressBook; + + public function __construct() + { + $this->template = new Template(templateDir: dirname(path: __DIR__, levels: 2) . '/templates/'); + $this->addressBook = new AddressBook(template: $this->template); + } + + + /** + * @throws Exception + */ + public function get(string $class): stdClass + { + return match($class) { + 'App\Controller\AddressBook' => $this->addressBook, + default => throw new Exception(message: "Missing class definition: $class") + }; + } +} \ No newline at end of file diff --git a/src/Service/Template.php b/src/Service/Template.php new file mode 100644 index 0000000..a844515 --- /dev/null +++ b/src/Service/Template.php @@ -0,0 +1,40 @@ +<?php + +namespace App\Service; + +use Exception; + +class Template +{ + public function __construct(private readonly string $templateDir) + { + // empty body + } + + /** + * @throws Exception + */ + public function render(string $templateName): void + { + $template = file_get_contents(filename: $this->templateDir . $templateName); + + // search for includes + preg_match_all(pattern: '/{% include ?\'?(.*?)\'? ?%}/i', subject: $template, matches: $matches, flags: PREG_SET_ORDER); + + foreach ($matches as $value) { + $token = $value[0]; + $include = $this->templateDir . $value[1]; + if (file_exists(filename: $include)) { + $replacement = file_get_contents(filename: $include); + } else { + throw new Exception(message: "Missing included file: $include"); + } + $template = str_replace(search: $token, replace: $replacement, subject: $template); + } + + // remove the original template code + $template = preg_replace(pattern: '/{% include ?\'?(.*?)\'? ?%}/i', replacement: '', subject: $template); + + echo $template; + } +} \ No newline at end of file diff --git a/src/bootstrap.php b/src/bootstrap.php new file mode 100644 index 0000000..5646681 --- /dev/null +++ b/src/bootstrap.php @@ -0,0 +1,18 @@ +<?php + +spl_autoload_register(callback: function($className) { + $prefix = 'App'; + $baseDir = __DIR__; + + $len = strlen(string: $prefix); + if (strncmp(string1: $prefix, string2: $className, length: $len) !== 0) { + return; + } + $realClassName = substr(string: $className, offset: $len); + $classLocation = $baseDir . str_replace(search: '\\', replace: '/', subject: $realClassName) . '.php'; + if (file_exists(filename: $classLocation)) { + require $classLocation; + } else { + die("Invalid class: $className"); + } +}); diff --git a/templates/_footer.tpl b/templates/_footer.tpl new file mode 100644 index 0000000..8f950a9 --- /dev/null +++ b/templates/_footer.tpl @@ -0,0 +1,3 @@ + <!-- mind the javascript --> + </body> +</html> \ No newline at end of file diff --git a/templates/_header.tpl b/templates/_header.tpl new file mode 100644 index 0000000..c1c74b8 --- /dev/null +++ b/templates/_header.tpl @@ -0,0 +1,5 @@ +<html> + <head> + <title>Address Book</title> + <link rel="stylesheet" href="/assets/styles/main.css"> + </head> \ No newline at end of file diff --git a/templates/index.tpl b/templates/index.tpl new file mode 100644 index 0000000..ce1d3a4 --- /dev/null +++ b/templates/index.tpl @@ -0,0 +1,8 @@ +{% include '_header.tpl' %} + +<h1>Address Book</h1> +<a href="/">🏠 Home</a> +<a href="/">⚙ Admin</a> +<a href="/">🚪 Login</a> + +{% include '_footer.tpl' %}