5: Stemmen
Een peiling zonder stemmen is een lijst. In dit hoofdstuk wordt elke optie een formulier, ontvangt een POST route de stem, gaat de telling omhoog, en een omleiding her-render de pagina. Gewone HTTP, nog geen JavaScript: deze versie werkt in elke browser, met alles uit.
5.1: De stemformulieren
In poll.phlo, verander elke knop in de choices view in een klein formulier:
view choices:
<section.card>
<foreach type_poll::records() AS $option>
<form method=post action="/poll/vote/$option->id">
<button>$option->option</button>
</form>
</foreach>
</section>
Elk formulier verstuurt naar zijn eigen URL: /poll/vote/1, /poll/vote/2, enzovoort. De id reist in het pad, dus het formulier heeft geen verborgen velden nodig. Let op de aanhalingstekens rond de action waarde: attributen die variabelen of schuine strepen bevatten, moeten tussen aanhalingstekens staan. De form: display: inline regel uit hoofdstuk 3 houdt de knoppen op één rij.
Herlaad http://localhost/poll: het ziet er identiek uit, maar elke knop verstuurt nu een formulier. Op een klik verschijnt er een 404, omdat de route nog niet bestaat.
5.2: De POST route
Voeg de route toe aan poll.phlo, nabij de GET-route:
route POST poll vote $id {
if (!$option = type_poll::record(id: (int)$id)) return false
type_poll::change('id=?', (int)$id, votes: $option->votes + 1)
location('/poll')
}
Lees het van boven naar beneden:
route POST poll vote $idkomt overeen metPOST /poll/vote/<id>. Een$segmentin het pad is een variabele, beschikbaar binnen het blok.type_poll::record(id: ...)haalt één record of null op. Het exact retourneren vanfalsegeeft een route-misser aan: een onbekende id valt door en eindigt als een 404 in plaats van dat het gegevens corrumpeert.type_poll::change('id=?', $id, votes: ...)werkt het record bij via het model: een where-clausule, zijn waarden, en dan benoemde kolommen. Met JSONDB schrijf je altijd via de statische modelmethoden.location('/poll')leidt om. POST, redirect, GET: refresh-veilige stemmen sinds 2004.
Herlaad en klik op Phlo. De pagina herlaadt, de telling leest 1, en de balk springt naar 100%. Klik op een andere optie en kijk hoe de percentages zich herverdelen. Controleer data/poll.json om de stemmen op schijf te zien.
5.3: Een payload in plaats daarvan lezen
De id in het pad is één stijl. De andere is een request body, die je leest via %payload. Schakel eerst de resource in data/app.json in:
{
"resources": [
"DB/DB",
"DB/model",
"DB/JSONDB",
"DB/JSON.result",
"payload"
]
}
Een payload-gebaseerde versie van dezelfde route ziet er als volgt uit:
route POST poll vote @option {
$id = (int)%payload->option
if (!$option = type_poll::record(id: $id)) return false
type_poll::change('id=?', $id, votes: $option->votes + 1)
location('/poll')
}
@option valideert de request body: de payload moet precies de sleutel option bevatten, anders komt de route niet overeen. Body-sleutels worden nooit als parameters gebonden; je leest ze via %payload->option. De bijbehorende vorm zou één formulier zijn met <button name=option value="$option->id"> per keuze.
Beide stijlen zijn idiomatisch. Houd de $id variant uit X.2 voor deze tutorial; het maakt een soepele overgang naar de async versie.
5.4: Wat je nu hebt
Voer de controles nogmaals uit:
php www/app.php build::run
php www/app.php build::lint
Beide eindigen op []. Je hebt een complete, werkende poll: server-gerenderd, refresh-veilig, nul JavaScript. Stem een paar keer, kijk hoe data/poll.json verandert, en merk het ene ding op dat nog steeds als 2004 aanvoelt: de volledige pagina herlaad bij elke stem. Dat is het volgende hoofdstuk.