Controllers
Controllers are classes that handle HTTP requests, interact with models, and return responses or views. They provide better organization than defining all logic in route closures, especially for larger applications.
Controllers live in app/controllers/ and must extend the base Controller class.
Folder Structure
app/
└── controllers/
├── UserController.php
├── PostController.php
└── AdminController.php
Creating a Controller
A basic controller extends the base Controller class. Each public method can be mapped
to a route, and dynamic route parameters are automatically injected as method arguments.
<?php
class UserController extends Controller
{
public function index()
{
echo "List all users";
}
public function show($id)
{
echo "User Profile ID: " . $id;
}
public function create()
{
echo "Show create user form";
}
public function store()
{
echo "Handle form submission";
}
public function edit($id)
{
echo "Edit user " . $id;
}
public function destroy($id)
{
echo "Delete user " . $id;
}
}
Note
Only public methods are callable via routes. Private and protected methods are not accessible from the router.
Mapping Routes to Controllers
Navigate to app/config/routes.php and point routes at controller methods.
The :: symbol separates the controller class name from the method name.
<?php
$router->get('/users', 'UserController::index');
$router->get('/users/{id}', 'UserController::show');
$router->get('/users/create', 'UserController::create');
$router->post('/users', 'UserController::store');
$router->get('/users/{id}/edit', 'UserController::edit');
$router->delete('/users/{id}', 'UserController::destroy');
Alternative separators — all three are equivalent:
<?php
$router->get('/users', 'UserController::index'); // recommended
$router->get('/users', 'UserController->index');
$router->get('/users', 'UserController@index');
If no method is specified, index() is called by default:
<?php
$router->get('/users', 'UserController'); // calls UserController::index()
Controller Constructor
Use the constructor to load shared libraries, models, or helpers that are used
across multiple methods. Always call parent::__construct() first.
<?php
class UserController extends Controller
{
public function __construct()
{
parent::__construct();
// Load a model
$this->call->model('UserModel');
// Load libraries
$this->call->library('session');
$this->call->library('form_validation');
// Load a helper
$this->call->helper('url');
}
public function index()
{
$users = $this->UserModel->all();
$this->call->view('user/index', ['users' => $users]);
}
}
Loading Resources
Resources can be loaded in the constructor (shared across all methods) or inside individual methods (loaded only when needed).
Loading a model:
<?php
$this->call->model('UserModel');
$users = $this->UserModel->all();
Loading multiple models at once:
<?php
$this->call->model(['UserModel', 'PostModel']);
Loading a library:
<?php
$this->call->library('session');
$this->call->library('form_validation');
Loading a helper:
<?php
$this->call->helper('url');
Returning Views
Use $this->call->view() to render a template file from app/views/.
Pass data as an associative array — each key becomes a variable inside the view.
<?php
public function show($id)
{
$this->call->model('UserModel');
$user = $this->UserModel->find($id);
$this->call->view('user/profile', [
'user' => $user,
'title' => 'User Profile',
]);
}
Inside app/views/user/profile.php the variables are available directly:
<h1><?= $title ?></h1>
<p>Name: <?= $user['name'] ?></p>
<p>Email: <?= $user['email'] ?></p>
Handling Request Data
Use the Request class (available via $this->request) to access input data
inside controller methods.
Reading POST data:
<?php
public function store()
{
$name = $this->request->post('name');
$email = $this->request->post('email');
$this->call->model('UserModel');
$id = $this->UserModel->insert([
'name' => $name,
'email' => $email,
]);
redirect('/users/' . $id);
}
Reading GET parameters:
<?php
public function index()
{
$page = $this->request->get('page') ?? 1;
$this->call->model('UserModel');
$result = $this->UserModel->paginate(15, $page);
$this->call->view('user/index', $result);
}
Detecting the request method:
<?php
public function form()
{
if ($this->request->method() === 'post') {
// handle submission
} else {
$this->call->view('user/form');
}
}
Full CRUD Controller Example
<?php
class UserController extends Controller
{
public function __construct()
{
parent::__construct();
$this->call->model('UserModel');
}
// GET /users
public function index()
{
$users = $this->UserModel->all();
$this->call->view('user/index', ['users' => $users]);
}
// GET /users/{id}
public function show($id)
{
$user = $this->UserModel->find($id);
if (!$user) {
show_404();
}
$this->call->view('user/show', ['user' => $user]);
}
// GET /users/create
public function create()
{
$this->call->view('user/create');
}
// POST /users
public function store()
{
$data = [
'name' => $this->request->post('name'),
'email' => $this->request->post('email'),
];
$id = $this->UserModel->insert($data);
redirect('/users/' . $id);
}
// GET /users/{id}/edit
public function edit($id)
{
$user = $this->UserModel->find($id);
$this->call->view('user/edit', ['user' => $user]);
}
// PUT /users/{id}
public function update($id)
{
$data = [
'name' => $this->request->post('name'),
'email' => $this->request->post('email'),
];
$this->UserModel->update($id, $data);
redirect('/users/' . $id);
}
// DELETE /users/{id}
public function destroy($id)
{
$this->UserModel->delete($id);
redirect('/users');
}
}
Routes for the above controller:
<?php
$router->get('/users', 'UserController::index');
$router->get('/users/create', 'UserController::create');
$router->get('/users/{id}', 'UserController::show');
$router->post('/users', 'UserController::store');
$router->get('/users/{id}/edit', 'UserController::edit');
$router->put('/users/{id}', 'UserController::update');
$router->delete('/users/{id}', 'UserController::destroy');
Controller with Route Groups and Middleware
<?php
// app/config/routes.php
$router->group(['prefix' => '/admin', 'middleware' => 'AuthMiddleware'], function($router) {
$router->get('/users', 'Admin\UserController::index');
$router->get('/users/{id}', 'Admin\UserController::show');
$router->delete('/users/{id}', 'Admin\UserController::destroy');
});
Method Reference
Methods and properties available inside any controller that extends Controller:
Method / Property |
Description |
|---|---|
|
Must be called first in a controller constructor to boot the framework |
|
Loads a model; accessible as |
|
Loads a library; accessible as |
|
Loads a helper file |
|
Renders a view file from |
|
Returns a POST input value |
|
Returns a GET query parameter |
|
Returns the current HTTP method in lowercase |
|
Direct access to the database query builder |
|
Triggers the 404 error page |
|
Redirects to the given URL |
Tips and Best Practices
Always call
parent::__construct()as the first line of a controller constructor.Load models and libraries in the constructor when they are needed across multiple methods; load them inline when only one method needs them.
Keep controllers thin — delegate database logic to models and presentation to views.
Name controllers after the resource they manage (e.g.,
UserController,PostController).One controller should handle one resource. Avoid mixing unrelated logic in a single controller.
Use route groups with middleware to protect sets of controller routes rather than adding auth checks inside every method.
Use
show_404()when a requested record does not exist instead of returning an empty view.