My page
Ordinary html, plus any custom element the client provides.
Ordinary html, plus any custom element the client provides.
This post does not exist.
isDraft()) {$route->redirect(\MMO\url('blog')); return;} ?> ``` Neither `redirect()` nor `stop()` throws: the rest of the file still runs, so `return` after them. A top-level `return` simply ends the page -- what was echoed so far is kept. `stop()` also lets a page answer something other than html -- an export of the table it shows, a form it handles itself: ```php get('export') === 'xlsx') {$route->stop(Response::Xlsx(buildSheet($stats))); return;} if (($route->isPost()) && ($post = $route->getRequestBody())) { //save $post, then show the page again } ?> ``` A missing *page* is a 404 already: `PageController` throws it, before any page runs, for a path no entry matches -- and for an entry marked `"visible": false`, a 401. ### A form posting to its page A page receives its own form: `PageController` answers every method, so the form posts to the page that shows it, which checks what was sent, then either sends the browser on (the post/redirect/get pattern) or shows the form again with what is wrong, answering 422. Nothing else is needed: no controller, no route. ```php '']; if ($route->isPost()) { $input = (array)$route->getRequestBody(); //the form's fields; `lines[0][label]` arrives as an array if (!$invoice = Invoices::Create($input, $errors)) { $route->setResponse($route->getResponse()->withStatus(422)); } else {$route->redirect(\MMO\url('invoices/invoice') . '?id=' . $invoice->getId()); return;} } ?> ``` `redirect()` does not end the page: `return` after it. A test asks for the page and posts to it as a browser would, in the same process: `$this->http('POST', 'invoices/new', ['customer' => ''])` (mmo.core's `MMO\core\tests\TestCase`, docs/Testing.md). ### Escaping A page is php: `= $x ?>` prints raw. Use `htmlspecialchars()` for text, and `\MMO\core\printers\JsonPrinter::Encode()` to hand a value to javascript: ```php