diff options
Diffstat (limited to 'src/DTS')
| -rw-r--r-- | src/DTS/Errors.php | 30 | ||||
| -rw-r--r-- | src/DTS/Functions.php | 23 | ||||
| -rw-r--r-- | src/DTS/Old.php | 29 | ||||
| -rw-r--r-- | src/DTS/Session.php | 41 | ||||
| -rw-r--r-- | src/DTS/Template.php | 32 | ||||
| -rw-r--r-- | src/DTS/Todo.php | 16 | ||||
| -rw-r--r-- | src/DTS/TodoRepository.php | 162 | ||||
| -rw-r--r-- | src/DTS/Validated.php | 12 | ||||
| -rw-r--r-- | src/DTS/Validator.php | 59 |
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); + } + } +} |
