Welcome to FrostSW!

FrostMVC PHP Framework

Documentation   |   Version
FrostMVC / app / controllers

controllers/

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.

Creating a controller

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!']);
    }
}
  • The namespace is your app namespace ($config['namespace'] in settings.php) followed by \controllers. FrostMVC autoloads the class from that namespace.
  • Framework classes are in the 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.

Routing the controller

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.


Methods and URL values

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.

Reading input

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.

Using models and libraries

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).

Responding

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