Controllers
A controller is where a request lands once routing has decided which class and method should handle it. Its job is coordination: read whatever the request needs (URL segments, form input), talk to a model if data is required, and hand a finished response back — usually a rendered view. This page covers how controllers are structured, named, and written in CodeIgniter 4.
1. Every Controller Extends BaseController
CodeIgniter's own base Controller class lives in the framework itself, but every controller
you write extends App\Controllers\BaseController instead — a thin class, generated for
you at app/Controllers/BaseController.php, that itself extends CodeIgniter's
Controller. This extra layer exists specifically so you have a safe, project-owned place to
add shared behaviour (helpers loaded on every request, common properties, etc.) without ever touching
framework code directly.
<?php
namespace App\Controllers;
use CodeIgniter\Controller;
class BaseController extends Controller
{
// Shared setup and helper properties for all your controllers
}
2. Naming and Namespacing
Controller classes live in app/Controllers/ and belong to the App\Controllers
namespace (or a sub-namespace matching a subfolder, for organizing larger applications). The class name
should match the filename, and by convention it's written in PascalCase:
<?php
namespace App\Controllers;
class Articles extends BaseController
{
// Actions go here
}
This file would live at app/Controllers/Articles.php. If it were organized under an admin
area instead, it might live at app/Controllers/Admin/Articles.php with the namespace
App\Controllers\Admin, matching the folder path exactly — CodeIgniter's autoloader
relies on this namespace-to-path convention to find the class at all.
3. Actions Are Just Public Methods
There's no special interface or annotation required to make a method callable as an action — any
public method on a controller is a potential target for a route. That's it. Private and
protected methods, by contrast, are invisible to routing and safe to use as internal helpers within the
controller.
public function index()
{
// Handles GET /articles
}
4. Receiving URL Segments as Parameters
Recall from Routing that a route like
$routes->get('articles/(:num)', 'Articles::show/$1'); captures a URL segment and passes
it through as $1. On the controller side, that captured value simply arrives as a normal
method parameter, in order:
public function show($id)
{
// $id holds whatever (:num) captured from the URL, e.g. "5"
}
The same applies whether the segment arrived via an explicit route or via automatic routing — either way, extra URL segments after the method name become positional arguments to that method.
5. Loading a Model
When an action needs data, it typically reaches for a model. The most direct way is instantiating it straight from its fully qualified class name:
$model = new \App\Models\ArticleModel();
$article = $model->find($id);
find(), and the
full range of database operations they support get their own detailed lesson at
Models & Query Builder. For now, just know that a model is a plain
class you instantiate and call methods on like anything else.6. Returning a Rendered View
Once a controller has whatever data it needs, it typically hands that data to a view and returns the
rendered result. CodeIgniter's global view() function takes a view path and an associative
array of data made available to that view as variables:
return view('articles/show', ['article' => $article]);
The details of how views locate templates, share layouts, and escape output safely are covered fully on the next page, Views.
7. A Full Worked Example
Putting all of the above together, here's a complete Articles controller with an
index() action listing all articles and a show($id) action displaying one:
<?php
namespace App\Controllers;
class Articles extends BaseController
{
public function index()
{
$model = new \App\Models\ArticleModel();
$data['articles'] = $model->findAll();
return view('articles/index', $data);
}
public function show($id)
{
$model = new \App\Models\ArticleModel();
$article = $model->find($id);
if ($article === null) {
return $this->response->setStatusCode(404);
}
return view('articles/show', ['article' => $article]);
}
}
Paired with the routes from the previous lesson — $routes->get('articles', 'Articles::index');
and $routes->get('articles/(:num)', 'Articles::show/$1'); — this single class fully
handles both the article listing page and individual article pages.
8. Advanced: initController()
CodeIgniter 4 controllers support an initController() method, called automatically right
after the controller is instantiated and before your action runs. It's most often used to gain access to
the request/response objects and logger a little earlier than the constructor would normally allow, or to
run setup logic shared across many actions. This is an advanced, occasional-use feature — most
controllers never need to override it, since BaseController and plain constructor logic cover
the vast majority of cases.
view() function locates templates, passes data safely, and supports layouts and partials.