Controllers should contain any business logic related to the template – or, at least, business logic that doesn't belong to a separate module or class. One of the key concepts of MVC is separation of concerns, and the first step towards that goal is not mixing business logic with markup generation.
Controllers are optional
Note that Controllers are also completely optional: if a Page can be rendered without complex business rules, meaning that you just need some basic control structures, loops, and echo/print statements, it is perfectly fine to leave Controllers out of the equation and request data directly from ProcessWire's API.
For an example: it's OK to echo content from a page field or iterate over page's children in the view file, but if you're building a search query based on user input, the code used for this purpose definitely belongs into a Controller.
When a Page is rendered, Wireframe will check if it can find and instantiate a template-specific Controller class. If it can't, it'll just continue rendering the Page without one.
Files and class names
First things first: in Wireframe a Controller is tied to a single template, and should contain a class (and one class only) named after the template. Controller files need to be placed into the controllers directory under /site/templates/, and the syntax for Controller class names is [TemplateNameInCamelCase]Controller.
For an example the Controller class for the "home" template would be HomeController, and this class should be placed in /site/templates/controllers/HomeController.php. If the template was "basic-page", Controller class would be BasicPageController, and the filename would be /site/templates/controllers/BasicPageController.php.
Creating a Controller
Here's a very simple Controller implementation for the "home" template (/site/templates/controllers/HomeController.php):
<?php
namespace Wireframe\Controller;
/**
* This is the Controller class for the home template.
*/
class HomeController extends \Wireframe\Controller {
/**
* Render method gets executed automatically when page is rendered.
*/
public function render() {
$this->view->some_var = "some value";
}
/**
* Another method. Controller methods can be accessed as parameters from
* within Layout files and View Files.
*
* @return string
*/
public function someOtherVar(): string {
return "some other value";
}
}
Here are some key points to keep in mind when working with Controllers:
- Place Controller files in /site/templates/controllers/ directory
- Note that it's possible to override this directory using Wireframe config settings – in that case please refer to your config settings instead.
- Use namespace Wireframe\Controller for your Controllers, and extend either the \Wireframe\Controller base class, or another Controller class
- This namespace allows Wireframe autoload rules to find your controllers. If the namespace is wrong, the Controller class can't be instantiated properly.
- Usually you'll want to extend the \Wireframe\Controller base class, but if you want to create your own base classes, that's also possible.
- Class and file name format is [TemplateName]Controller
- For an example: HomeController / HomeController.php for the "home" template, and BasicPageController / BasicPageController.php for the "basic-page" template.
- Controller::init() and Controller::render() methods get executed automatically
- init() method is called as soon as the Controller class has been instantiated. This makes it the earliest point in the Controller's lifecycle to trigger your own actions, cache content, etc.
- render() method is called right before the page is rendered. If you need to pass variables to the View or perform some action when the page is viewed, this is what you're looking for.
- Other public methods are made available as params in Layouts and View Files
- If you have a public method called myName() in a Controller class, accessing $this->myName in a layout or view file for related template will refer to the return value of said method.
- Public Controller methods prefixed with three underscores (___) are hookable
- Since the \Wireframe\Controller base class extends Wire, any public Controller method prefixed with three underscores can be hooked into using ProcessWire's hook system.