5: 投票

没有投票的投票是一个列表。在本章中,每个选项都变成一个表单,一个 POST route 接收投票,计数增加,重定向重新渲染页面。纯 HTTP,尚未使用 JavaScript:这个版本在任何浏览器中都能工作,所有功能都关闭。

5.1: The vote forms

In poll.phlo, turn each button in the choices view into a tiny form:

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>

Each form posts to its own URL: /poll/vote/1, /poll/vote/2, and so on. The id travels in the path, so the form needs no hidden fields. Note the quotes around the action value: attributes containing variables or slashes must be quoted. The form: display: inline rule from chapter 3 keeps the buttons on one row.

Reload http://localhost/poll: looks identical, but every button now submits a form. Clicking one gives a 404, because the route does not exist yet.

5.2: POST 路由

poll.phlo 中添加路由,靠近 GET 路由:

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')
}

从上到下阅读:

重新加载并点击 Phlo。页面重新加载,计数为 1,进度条跳到 100%。点击另一个选项,观察百分比重新分配。检查 data/poll.json 以查看磁盘上的投票情况。

5.3: 读取有效负载而不是

路径中的 id 是一种风格。另一种是请求体,您可以通过 %payload 读取。首先在 data/app.json 中启用资源:

{
    "resources": [
        "DB/DB",
        "DB/model",
        "DB/JSONDB",
        "DB/JSON.result",
        "payload"
    ]
}

基于负载的相同路由版本如下所示:

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 验证请求体:负载必须恰好包含键 option,否则路由不匹配。请求体中的键永远不会绑定为参数;您通过 %payload->option 读取它们。匹配的表单将是每个选项一个表单,形式为 <button name=option value="$option->id">

这两种风格都是惯用的。对于本教程,请保留来自 X.2 的 $id 变体;它可以顺利过渡到 async 版本。

5.4: What you have now

The build keeps itself current on every request; run the checks explicitly if you want the confirmation:

php www/app.php build::run
php www/app.php build::lint

Both settle at []. You have a complete, working poll: server-rendered, refresh-safe, zero JavaScript. Vote a few times, watch data/poll.json change, and notice the one thing that still feels 2004: the full page reload on every vote. That is the next chapter.

我们使用必要的cookie来使该网站正常工作。在您的许可下,我们还使用分析工具来改善网站。