summaryrefslogtreecommitdiff
path: root/src/DTS
diff options
context:
space:
mode:
Diffstat (limited to 'src/DTS')
-rw-r--r--src/DTS/Errors.php30
-rw-r--r--src/DTS/Functions.php23
-rw-r--r--src/DTS/Old.php29
-rw-r--r--src/DTS/Session.php41
-rw-r--r--src/DTS/Template.php32
-rw-r--r--src/DTS/Todo.php16
-rw-r--r--src/DTS/TodoRepository.php162
-rw-r--r--src/DTS/Validated.php12
-rw-r--r--src/DTS/Validator.php59
9 files changed, 404 insertions, 0 deletions
diff --git a/src/DTS/Errors.php b/src/DTS/Errors.php
new file mode 100644
index 0000000..3c1dd5d
--- /dev/null
+++ b/src/DTS/Errors.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+class Errors
+{
+ private $errors = [];
+
+ public function add(string $key, string $value): void
+ {
+ $this->errors[$key][] = $value;
+ }
+
+ public function get(string $key): array
+ {
+ return $this->errors[$key];
+ }
+
+ public function has(string $key): bool
+ {
+ return array_key_exists($key, $this->errors);
+ }
+
+ public function count(): int
+ {
+ return count($this->errors);
+ }
+}
diff --git a/src/DTS/Functions.php b/src/DTS/Functions.php
new file mode 100644
index 0000000..2101cda
--- /dev/null
+++ b/src/DTS/Functions.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS\Functions;
+
+function respondAndExit(int $responseCode, string $header, string $body = '', array $headers = []): void
+{
+ header($header, false, $responseCode);
+
+ foreach ($headers as $header) {
+ header($header);
+ }
+
+ echo $body;
+
+ exit();
+}
+
+function redirectAndExit(string $location): void
+{
+ respondAndExit(302, 'Found', '', ["Location: $location"]);
+}
diff --git a/src/DTS/Old.php b/src/DTS/Old.php
new file mode 100644
index 0000000..0641329
--- /dev/null
+++ b/src/DTS/Old.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+class Old
+{
+ const FIELDS = [
+ 'task',
+ 'tag',
+ ];
+
+ private array $old = [];
+
+ function __construct(array $request = [])
+ {
+ foreach(self::FIELDS as $field) {
+ if (array_key_exists($field, $request)) {
+ $this->old[$field] = $request[$field];
+ }
+ }
+ }
+
+ public function get(string $key, $default = null)
+ {
+ return $this->old[$key] ?? $default;
+ }
+}
diff --git a/src/DTS/Session.php b/src/DTS/Session.php
new file mode 100644
index 0000000..35be1fe
--- /dev/null
+++ b/src/DTS/Session.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+class Session
+{
+ private static ?self $instance = null;
+
+ private array $session = [];
+
+ public static function getInstance()
+ {
+ if (!self::$instance) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ private function __construct()
+ {
+ session_start();
+
+ foreach ($_SESSION as $key => $value) {
+ $this->session[$key] = $value;
+ unset($_SESSION[$key]);
+ }
+ }
+
+ public function set(string $key, $value): void
+ {
+ $this->session[$key] = $_SESSION[$key] = $value;
+ }
+
+ public function get(string $key, $default = null)
+ {
+ return $this->session[$key] ?? $default;
+ }
+}
diff --git a/src/DTS/Template.php b/src/DTS/Template.php
new file mode 100644
index 0000000..89bd7f8
--- /dev/null
+++ b/src/DTS/Template.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+class Template
+{
+ private string $path;
+
+ function __construct(string $path)
+ {
+ $this->path = $path;
+ }
+
+ public function render(string $template, array $data = []): string
+ {
+ $file = "{$this->path}$template.php";
+
+ if (!is_file($file) || !is_readable($file)) {
+ throw new \Exception("Unable to locate template $file");
+ }
+
+ extract($data);
+
+ ob_start();
+
+ require_once($file);
+
+ return ob_get_clean();
+ }
+}
diff --git a/src/DTS/Todo.php b/src/DTS/Todo.php
new file mode 100644
index 0000000..9b08e56
--- /dev/null
+++ b/src/DTS/Todo.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+class Todo
+{
+ public int $id;
+
+ public string $task = '';
+
+ public string $tag = '';
+
+ public string $addedAt;
+}
diff --git a/src/DTS/TodoRepository.php b/src/DTS/TodoRepository.php
new file mode 100644
index 0000000..5ec759f
--- /dev/null
+++ b/src/DTS/TodoRepository.php
@@ -0,0 +1,162 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+use DTS\Todo;
+
+class TodoRepository implements \Iterator
+{
+ private string $pathToRepository;
+
+ private array $repository = [];
+
+ private array $tags = [];
+
+ private int $position = 0;
+
+ function __construct(string $pathToRepository)
+ {
+ $this->pathToRepository = $pathToRepository;
+
+ $this->load();
+ }
+
+ public function sort(bool $asc = true): TodoRepository
+ {
+ usort($this->repository, function ($a, $b) use ($asc) {
+ return $asc ? $a->task <=> $b->task
+ : $b->task <=> $a->task;
+ });
+
+ return $this;
+ }
+
+ public function filter(string $tag): TodoRepository
+ {
+ $this->repository = array_filter(
+ $this->repository,
+ fn($todo) => $todo->tag === $tag
+ );
+
+ return $this;
+ }
+
+ public function find(string $id): ?Todo
+ {
+ return $this->repository[$id] ?? null;
+ }
+
+ public function add(Todo $todo): bool
+ {
+ $this->repository[] = $todo;
+
+ return $this->save();
+ }
+
+ public function update(Todo $todo): bool
+ {
+ if (array_key_exists($todo->id, $this->repository)) {
+ $this->repository[$todo->id] = $todo;
+
+ return $this->save();
+ }
+
+ return false;
+ }
+
+ public function delete(Todo $todo): bool
+ {
+ if (array_key_exists($todo->id, $this->repository)) {
+ unset($this->repository[$todo->id]);
+
+ return $this->save();
+ }
+
+ return false;
+ }
+
+ public function tags(): array
+ {
+ return $this->tags;
+ }
+
+ public function current()
+ {
+ return $this->repository[$this->position];
+ }
+
+ public function key()
+ {
+ return $this->position;
+ }
+
+ public function next(): void
+ {
+ ++$this->position;
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return isset($this->repository[$this->position]);
+ }
+
+ private function load(): void
+ {
+ if (!is_file($this->pathToRepository) || !is_readable($this->pathToRepository)) {
+ throw new \Exception("Unable to locate repository {$this->pathToRepository}");
+ }
+
+ if (($fp = fopen($this->pathToRepository, 'r')) === FALSE) {
+ throw new \Exception("Unable to read from repository {$this->pathToRepository}");
+ }
+
+ $id = 0;
+
+ while (($data = fgetcsv($fp)) !== FALSE) {
+ $todo = new Todo();
+
+ $todo->id = $id++;
+ $todo->task = $data[0];
+ $todo->tag = $data[1];
+ $todo->addedAt = $data[2];
+
+ $this->repository[] = $todo;
+
+ $this->tags[] = $todo->tag;
+ }
+
+ $this->tags = array_filter(array_unique($this->tags));
+
+ sort($this->tags);
+
+ fclose($fp);
+ }
+
+ private function save(): bool
+ {
+ if (($fp = fopen($this->pathToRepository, 'w')) === FALSE) {
+ throw new \Exception("Unable to open repository {$this->pathToRepository}");
+ }
+
+ $success = true;
+
+ foreach ($this->repository as $todo) {
+ $success = $success && fputcsv($fp, [
+ $todo->task,
+ $todo->tag,
+ $todo->addedAt,
+ ]) !== false;
+ }
+
+ fclose($fp);
+
+ return $success;
+ }
+}
diff --git a/src/DTS/Validated.php b/src/DTS/Validated.php
new file mode 100644
index 0000000..9610538
--- /dev/null
+++ b/src/DTS/Validated.php
@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+class Validated
+{
+ public string $task = '';
+
+ public string $tag = '';
+}
diff --git a/src/DTS/Validator.php b/src/DTS/Validator.php
new file mode 100644
index 0000000..2f9c255
--- /dev/null
+++ b/src/DTS/Validator.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DTS;
+
+use DTS\Errors;
+use DTS\Validated;
+
+class Validator
+{
+ public Errors $errors;
+
+ public Validated $validated;
+
+ function __construct(array $request)
+ {
+ $this->errors = new Errors();
+
+ $this->validated = new Validated();
+
+ $this->validateTask($request['task'], 2, 256);
+
+ $this->validateTag($request['tag'], 2, 16);
+ }
+
+ private function validateTask(string $task, int $minLength, int $maxLength): void
+ {
+ $task = trim($task);
+
+ if (strlen($task) < $minLength || strlen($task) > $maxLength) {
+ $this->errors->add('task', "Must be between $minLength and $maxLength in characters in length");
+ }
+
+ if (!$this->errors->has('tite')) {
+ $this->validated->task = $task;
+ }
+ }
+
+ private function validateTag(string $tag, int $minLength, int $maxLength): void
+ {
+ $tag = trim($tag);
+
+ if ($tag === '') {
+ return;
+ }
+
+ if (strlen($tag) < $minLength || strlen($tag) > $maxLength) {
+ $this->errors->add('tag', "Must be between $minLength and $maxLength in characters in length");
+ }
+ if (preg_match('/\W/', $tag) === 1) {
+ $this->errors->add('tag', 'May only contain word characters');
+ }
+
+ if (!$this->errors->has('tag')) {
+ $this->validated->tag = strtolower($tag);
+ }
+ }
+}