The controller is the brain of the MVC. It receives the request, talks to the models, and decides which view to show.
A controller is a class in app/controllers that extends FrostMVC's Controller class.
Create app/controllers/BlogController.php. The class name must match the file name:
app/controllers/BlogController.php
<?php
namespace MyApp\controllers;
use FrostMVC\Controller;
use FrostMVC\View;
class BlogController extends Controller {
public function index() {
View::get('blog/index', ['title' => 'Hello World!']);
}
}
$config['namespace'] in settings.php) followed by \controllers. FrostMVC autoloads the class from that namespace.FrostMVC namespace; import each one you use with use, e.g. use FrostMVC\Form;.index() runs when the URL names the controller but no method, e.g. /blog.Register the controller in app/routes.php so a URL reaches it:
use MyApp\controllers\BlogController;
function blog($pages) {
View::route(BlogController::class, $pages);
}
Open http://localhost/<your-folder>/blog to run BlogController::index(). See Routing for how the rest of the URL maps to methods and arguments.
Every public method is a page. The next parts of the URL become its arguments, so
/blog/view/1145 calls view('1145'):
public function view($id) {
$post = (new Posts)->get()->where('id', $id)->readRow();
if (!$post) {
Functions::error('This post does not exist.');
}
View::get('blog/view', ['post' => $post]);
}
Keep helper methods private or protected so they cannot be opened from the browser.
Use the Form helpers instead of $_GET/$_POST. They sanitise the value for you:
$page = Form::fig('page', FILTER_VALIDATE_INT); // $_GET['page']
$title = Form::fip('title'); // $_POST['title']
$query = Form::val('q'); // GET first, then POST
$isPost = Form::fis('REQUEST_METHOD') === 'POST'; // $_SERVER value
POST requests are checked for a valid CSRF token before your controller runs. Forms opened with Form::start() (or form.start() in Twig) include the token automatically.
Import a model and create it where you need it:
use MyApp\models\Posts;
$latest = (new Posts)->get()->order('created', 'DESC')->limit(10)->read();
Or load models and libraries once in the constructor and use them as properties:
public function __construct($pages = '') {
parent::__construct($pages);
$this->require->model(['Posts', 'Authors'], $this); // $this->Posts, $this->Authors
$this->require->library('Mailer', $this); // $this->Mailer from libraries/
}
When you override the constructor, always call parent::__construct($pages).
View::get('blog/view', $data) | Render the Twig view app/views/blog/view.php.twig with $data. |
Functions::io_relocate($url) | Redirect the browser and stop. |
Functions::xhrResult('success', $data) | Send a JSON response (with a refreshed CSRF token) and stop. Use it for AJAX calls. |
Functions::error($message, '', 404) | Show the error page with an HTTP status and stop. |
Session::set('success', 'Saved!') | Store a message for the next page; read it once there with session.flash('success'). |
A typical save action, using the post-redirect-get pattern:
public function save() {
if (Form::fis('REQUEST_METHOD') === 'POST') {
(new Posts)->insert(['title' => Form::fip('title'), 'body' => Form::fip('body', 'html')])->execute();
Session::set('success', 'Post saved!');
Functions::io_relocate(BASEPATH . '/blog');
}
View::get('blog/edit');
}
Next: Models & Database · Reference: Controller, Loader, Functions