Last active
August 26, 2024 18:16
-
-
Save thekid/175cc260d5ce6199c2128d48606b87bb to your computer and use it in GitHub Desktop.
TODO application (PHP, HTMX, SQLite)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"require": { | |
"xp-forge/handlebars-templates": "^3.1", | |
"xp-forge/frontend": "^6.3", | |
"xp-framework/rdbms": "^13.1", | |
"php": ">=8.0.0", | |
"ext-sqlite3": "*" | |
}, | |
"scripts": { | |
"dev": "xp -supervise web -m develop Todo", | |
"serve": "xp -supervise web Todo", | |
"post-update-cmd": "xp bundle" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"dependencies": { | |
"htmx.org": "^2.0" | |
}, | |
"bundles": { | |
"vendor": {"htmx.org": ["dist/htmx.min.js"], "fonts://display=swap": "Lato:wght@300"} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use rdbms\{DriverManager, DBConnection}; | |
use web\frontend\{Frontend, AssetsFrom, Handlebars, Get, Post, Delete, Put, View, Param}; | |
use web\{Application, Environment, Handler}; | |
class Todo extends Application { | |
const PATH= 'todos.db'; | |
/** Returns a database connection */ | |
private function connection(): DBConnection { | |
return DriverManager::getConnection("sqlite://./{$this->environment->path(self::PATH)->name()}"); | |
} | |
/** Creates database if it doesn't exist */ | |
public function initialize(): void { | |
if ($this->environment->path(self::PATH)->exists()) return; | |
$conn= $this->connection(); | |
$conn->query('create table todo ( | |
id integer primary key, | |
description text, | |
completed integer, | |
created datetime default CURRENT_TIMESTAMP | |
)'); | |
$conn->insert('into todo (description, completed) values ("Welcome π", 0)'); | |
} | |
/** @return [:Handler] */ | |
public function routes() { | |
$impl= new class($this->connection()) { | |
public function __construct(private $conn) { } | |
/** Renders a given TODO */ | |
private function render(int $id, string $view= 'item'): View { | |
$todo= $this->conn->query('select * from todo where id = %d', $id)->next(); | |
return View::named('todo')->fragment($view)->with($todo); | |
} | |
#[Get] | |
public function list() { | |
return View::named('todo')->with(['todos' => $this->conn->select('* from todo')]); | |
} | |
#[Post('/todos')] | |
public function create(#[Param] string $description, #[Param] bool $completed= false) { | |
$this->conn->insert( | |
'into todo (description, completed) values (%s, %d)', | |
$description, | |
$completed | |
); | |
return $this->render($this->conn->identity()); | |
} | |
#[Get('/todos/{id}')] | |
public function view(int $id) { | |
return $this->render($id); | |
} | |
#[Delete('/todos/{id}')] | |
public function remove(int $id) { | |
$this->conn->delete('from todo where id = %d', $id); | |
return View::empty()->status(202); | |
} | |
#[Get('/todos/{id}/edit')] | |
public function edit(int $id) { | |
return $this->render($id, 'edit'); | |
} | |
#[Put('/todos/{id}/completed')] | |
public function complete(int $id) { | |
$this->conn->update('todo set completed = 1 where id = %d', $id); | |
return $this->render($id); | |
} | |
#[Put('/todos/{id}/description')] | |
public function rename(int $id, #[Param] string $description) { | |
$this->conn->update('todo set description = %s where id = %d', $description, $id); | |
return $this->render($id); | |
} | |
}; | |
return [ | |
'/static' => new AssetsFrom($this->environment->webroot()), | |
'/' => new Frontend($impl, new Handlebars('.')) | |
]; | |
} | |
} |
Demo application for xp-forge/frontend#41
$ composer up
Loading composer repositories with package information
# ...
Resolving package versions
- Resolving npm/htmx.org (^1.9 => 1.9.8)
- Resolving Lato:wght@300 (fonts)
# ...
$ xp serve
@xp.web.srv.Standalone(HTTP @ peer.ServerSocket(Resource id #139 -> tcp://127.0.0.1:8080))
Serving prod:Todo(static)[] > web.logging.ToConsole
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
> Server started: http://localhost:8080 in 0.060 seconds
Sun, 19 Nov 2023 18:45:24 +0100 - PID 6084; press Ctrl+C to exit
# ...
@thekid Nice! Really interesting to see a PHP / HTMX example! Thanks for sharing this π
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Inspired by https://www.youtube.com/watch?v=akd7u69k27k - thanks @bugbytes-io π