diff --git a/todos/php/README.md b/todos/php/README.md new file mode 100644 index 0000000..da7b130 --- /dev/null +++ b/todos/php/README.md @@ -0,0 +1,14 @@ +# TODO-MVP in PHP + +This implementation is written in [PHP](https://www.php.net). + +- PHP version 7.3+. + +HTML copied from Ruby implementation. + +## Instructions + +1. Clone the repository +2. Requires PHP installed. +3. From the php/ directory run: `php -S localhost:8000` +4. Open browser to http://localhost:8000 diff --git a/todos/php/autoload.php b/todos/php/autoload.php new file mode 100644 index 0000000..4355ae0 --- /dev/null +++ b/todos/php/autoload.php @@ -0,0 +1,33 @@ + '/classes/' + ]; + + foreach($loaders as $prefix => $base_dir){ + $len = strlen($prefix); + if(strncmp($prefix, $class,$len) !== 0){ + continue; + } + $relative_class = substr($class, $len); + + $file = __DIR__ . $base_dir . + str_replace('\\', '/', + $relative_class) . + '.php'; + + if (file_exists($file)) { + require $file; + return; + } + } //end foreach +}); diff --git a/todos/php/classes/controller.php b/todos/php/classes/controller.php new file mode 100644 index 0000000..693beef --- /dev/null +++ b/todos/php/classes/controller.php @@ -0,0 +1,75 @@ +requestPost = $post; + $this->requestGet = $get; + } + + /** + * Route: / or /index + * If a http POST has been received, add the item, otherwise list items. + * + * @param todo $todo + * @return void + */ + public function index(todo &$todo){ + if (isset($this->requestPost['item'])) { + $todo->addItem($this->requestPost['item']); + } + return 'page'; + } + + /** + * Route: /done + * + * @param todo $todo + * @return void + */ + public function done(todo &$todo){ + if (isset($this->requestPost['item'])) { + $todo->setItemDone($this->requestPost['item']); + } + return 'page'; + } + + /** + * Route: /notdone + * + * @param todo $todo + * @return void + */ + public function notdone(todo &$todo){ + if (isset($this->requestPost['item'])) { + $todo->setItemNotDone($this->requestPost['item']); + } + return 'page'; + } + + /** + * Route: /delete + * + * @param todo $todo + * @return string + */ + public function delete(todo &$todo){ + if (isset($this->requestPost['item'])) { + $todo->delete($this->requestPost['item']); + } + return 'page'; + } +} diff --git a/todos/php/classes/todo.php b/todos/php/classes/todo.php new file mode 100644 index 0000000..d7cee75 --- /dev/null +++ b/todos/php/classes/todo.php @@ -0,0 +1,86 @@ +items = $list; + } + + /** + * Add a new todo item, default to not done. + * + * @param string $name + * @return void + */ + public function addItem(string $name) + { + $this->items[] = array('name' => $name, 'done' => 0); + } + + /** + * Delete an item at the given number. + * + * @param int $num + * @return void + */ + public function delete(int $num) + { + unset($this->items[$num]); + } + + /** + * Fetch our current list of todo items as an array. + * + * @return array + */ + public function getItems(): array + { + return $this->items; + } + + /** + * Get our array of current items as a JSON string. + * For passing to Javascript or persistence in hidden form fields. + * + * @return string + */ + public function getItemsJSON(): string + { + return json_encode($this->items); + } + + /** + * Mark a todo item as complete. + * + * @param integer $num + * @return void + */ + public function setItemDone(int $num) + { + $this->items[$num]['done'] = 1; + } + + /** + * Mark a todo item as incomplete. + * + * @param integer $num + * @return void + */ + public function setItemNotDone(int $num) + { + $this->items[$num]['done'] = 0; + } +} diff --git a/todos/php/index.php b/todos/php/index.php new file mode 100644 index 0000000..628eeb4 --- /dev/null +++ b/todos/php/index.php @@ -0,0 +1,46 @@ +Return home."); + exit(); +} + +// Set up values for our 'template': +$tpl_todos = $todoList->getItems(); +$tpl_currentList = htmlspecialchars($todoList->getItemsJSON()); + +// Include our html page template, which uses the above values. +require_once($template.'.tpl.php'); diff --git a/todos/php/page.tpl.php b/todos/php/page.tpl.php new file mode 100644 index 0000000..d118fde --- /dev/null +++ b/todos/php/page.tpl.php @@ -0,0 +1,89 @@ + + + + Todo MVP + + + + +

Todo MVP

+
+
+ + + +
+
+ +
+

Todo list

+ +
+ + diff --git a/todos/php/static/check.svg b/todos/php/static/check.svg new file mode 100644 index 0000000..2df5dee --- /dev/null +++ b/todos/php/static/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/php/static/plus.svg b/todos/php/static/plus.svg new file mode 100644 index 0000000..23c27d8 --- /dev/null +++ b/todos/php/static/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/php/static/tick.png b/todos/php/static/tick.png new file mode 100644 index 0000000..71fb4ad Binary files /dev/null and b/todos/php/static/tick.png differ diff --git a/todos/php/static/todo.css b/todos/php/static/todo.css new file mode 100644 index 0000000..0cfd878 --- /dev/null +++ b/todos/php/static/todo.css @@ -0,0 +1,154 @@ +:root { + --text-color: rgb(20,20,20); + --border-color: black; + --title-color: rgb(60,60,60); + --done-color: rgb(200,200,200); + --background-color: white; + box-sizing: border-box; + padding: 0; + margin: 0; +} + +body { + min-height: 100vh; + padding: 0; + align-content: center; + margin: 0; + font-family: sans-serif; + line-height: 1.3rem; + font-size: 24px; + + background-color: var(--background-color); + color: var(--text-color); +} + +label { + font-size: 0.8rem; +} + +input { + box-sizing: border-box; + border: var(--border-color) solid 2px; + background-color: var(--background-color); +} + +section { + padding: 1.5rem; + margin-left: auto; + margin-right: auto; + max-width: 40rem; +} + +.new-todo form { + display: grid; + grid-template-columns: auto 29px; + grid-template-rows: auto; + column-gap: 1rem; +} + +.new-todo label[for="new-item"] { + grid-row: 1 / span 1; + grid-column: 1 / span 2; + margin: auto 1rem; +} + +.new-todo input#new-item { + grid-row: 1 / span 1; + grid-column: 1 / span 1; + padding: 0.5rem; + font-size: 1rem; +} + +.new-todo form input#add-new-item { + grid-row: 1 / span 1; + grid-column: 2 / span 1; + margin: auto; +} + +.button-container { + float: right; + display: flex; + flex-direction: column; + height: 100%; +} + +ul { + margin: 0; + padding: 0; +} + +ul:empty::after { + content: "You've not added any todos to the list. Use the box above to add a new todo."; + font-size: 1rem; + margin: 1rem; + font-style: italic; + border: 2px dotted black; + padding: 0.5rem; + display: block; + text-align: justify; + text-align-last: center; +} + +li { + display: flex; + border-bottom: 1px dotted var(--border-color); +} + +li:last-child { + border-bottom: none; +} + +li .item-name { + flex: auto; + margin: auto; + padding: 0 1rem; +} + +li form input, +.new-todo form input#add-new-item { + width: 30px; + height: 30px; + padding: 0; + + background-repeat: no-repeat; + background-size: contain; + background-position: center; + + /* hide text */ + text-indent: 100%; + white-space: nowrap; + overflow: hidden; +} + +.todo form input { + margin: 1em; +} + +.todo form input.delete { + background-image: url('trashcan.svg'); + cursor: pointer; + border: none; +} +input#add-new-item { background-image: url('plus.svg'); cursor: pointer; } +.todo form input.complete { background-image: none; cursor: pointer;} +.todo form input.uncomplete { background-image: url('check.svg'); cursor: pointer; } + +.done { + color: var(--done-color); +} + +.todo form { + display: contents; +} + +h1 { + font-weight: 200; + color: var(--title-color); + margin: 2rem; + display: none; +} + +h2 { + border-bottom: 1px solid black; + padding: 0 0 1rem 1rem; +} diff --git a/todos/php/static/trashcan.svg b/todos/php/static/trashcan.svg new file mode 100644 index 0000000..3d8c051 --- /dev/null +++ b/todos/php/static/trashcan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/php/static/x.svg b/todos/php/static/x.svg new file mode 100644 index 0000000..e377314 --- /dev/null +++ b/todos/php/static/x.svg @@ -0,0 +1 @@ + \ No newline at end of file