Controllers
Controllers are the heart of your application, as they determine how HTTP requests should be handled.
What is a Controller?
A Controller is simply a class file that handles a HTTP request. URI Routing associates a URI with a controller.
Included Properties
Every controller you create should extend CodeIgniter\Controller
class.
This class provides several features that are available to all of your controllers.
Request Object
The application’s main Request Instance is always available
as a class property, $this->request
.
Response Object
The application’s main Response Instance is always available
as a class property, $this->response
.
Logger Object
An instance of the Logger class is available as a class property,
$this->logger
.
Helpers
You can define an array of helper files as a class property. Whenever the controller is loaded these helper files will be automatically loaded into memory so that you can use their methods anywhere inside the controller:
<?php
namespace App\Controllers;
class MyController extends BaseController
{
protected $helpers = ['url', 'form'];
}
forceHTTPS
A convenience method for forcing a method to be accessed via HTTPS is available within all controllers:
<?php
if (! $this->request->isSecure()) {
$this->forceHTTPS();
}
By default, and in modern browsers that support the HTTP Strict Transport Security header, this call should force the browser to convert non-HTTPS calls to HTTPS calls for one year. You can modify this by passing the duration (in seconds) as the first parameter:
<?php
if (! $this->request->isSecure()) {
$this->forceHTTPS(31536000); // one year
}
Note
A number of time-based constants are always available for you to use, including YEAR
, MONTH
, and more.
Validating data
$this->validate()
To simplify data checking, the controller also provides the convenience method validate()
.
The method accepts an array of rules in the first parameter,
and in the optional second parameter, an array of custom error messages to display
if the items are not valid. Internally, this uses the controller’s
$this->request
instance to get the data to be validated.
The Validation Library docs have details on
rule and message array formats, as well as available rules:
<?php
namespace App\Controllers;
class UserController extends BaseController
{
public function updateUser(int $userID)
{
if (! $this->validate([
'email' => "required|is_unique[users.email,id,{$userID}]",
'name' => 'required|alpha_numeric_spaces',
])) {
return view('users/update', [
'errors' => $this->validator->getErrors(),
]);
}
// do something here if successful...
}
}
If you find it simpler to keep the rules in the configuration file, you can replace
the $rules
array with the name of the group as defined in Config\Validation.php
:
<?php
namespace App\Controllers;
class UserController extends BaseController
{
public function updateUser(int $userID)
{
if (! $this->validate('userRules')) {
return view('users/update', [
'errors' => $this->validator->getErrors(),
]);
}
// do something here if successful...
}
}
Note
Validation can also be handled automatically in the model, but sometimes it’s easier to do it in the controller. Where is up to you.
$this->validateData()
Sometimes you may want to check the controller method parameters or other custom data.
In that case, you can use the $this->validateData()
method.
The method accepts an array of data to validate in the first parameter:
<?php
namespace App\Controllers;
class StoreController extends BaseController
{
public function product(int $id)
{
$data = [
'id' => $id,
'name' => $this->request->getVar('name'),
];
$rule = [
'id' => 'integer',
'name' => 'required|max_length[255]',
];
if (! $this->validateData($data, $rule)) {
// ...
}
// ...
}
}
Private methods
In some cases, you may want certain methods hidden from public access.
To achieve this, simply declare the method as private
or protected
.
That will prevent it from being served by a URL request. For example,
if you were to define a method like this for the Helloworld
controller:
<?php
namespace App\Controllers;
class Products extends BaseController
{
protected function utility()
{
// some code
}
}
then trying to access it using the following URL will not work:
example.com/index.php/helloworld/utility/
Auto Routing (Improved)
Since v4.2.0, the new more secure Auto Routing has been introduced.
This section describes the functionality of the new auto-routing. It automatically routes an HTTP request, and executes the corresponding controller method without route definitions.
Since v4.2.0, the auto-routing is disabled by default. To use it, see Enable Auto Routing.
Consider this URI:
example.com/index.php/helloworld/
In the above example, CodeIgniter would attempt to find a controller named App\Controllers\Helloworld
and load it, when auto-routing is enabled.
Note
When a controller’s short name matches the first segment of a URI, it will be loaded.
Let’s try it: Hello World!
Let’s create a simple controller so you can see it in action. Using your text editor, create a file called Helloworld.php,
and put the following code in it. You will notice that the Helloworld
Controller is extending the BaseController
. you can
also extend the CodeIgniter\Controller
if you do not need the functionality of the BaseController.
The BaseController provides a convenient place for loading components and performing functions that are needed by all your controllers. You can extend this class in any new controller.
<?php
namespace App\Controllers;
class Helloworld extends BaseController
{
public function getIndex()
{
return 'Hello World!';
}
}
Then save the file to your app/Controllers/ directory.
Important
The file must be called Helloworld.php, with a capital H
. Controller class names MUST start with an uppercase letter and ONLY the first character can be uppercase.
Important
A controller method that will be executed by Auto Routing (Improved) needs HTTP verb (get
, post
, put
, etc.) prefix like getIndex()
, postCreate()
.
Now visit your site using a URL similar to this:
example.com/index.php/helloworld
If you did it right you should see:
Hello World!
This is valid:
<?php
namespace App\Controllers;
class Helloworld extends BaseController
{
// ...
}
This is not valid:
<?php
namespace App\Controllers;
class helloworld extends BaseController
{
// ...
}
This is not valid:
<?php
namespace App\Controllers;
class HelloWorld extends BaseController
{
// ...
}
Also, always make sure your controller extends the parent controller class so that it can inherit all its methods.
Note
The system will attempt to match the URI against Controllers by matching each segment against folders/files in app/Controllers/, when a match wasn’t found against defined routes. That’s why your folders/files MUST start with a capital letter and the rest MUST be lowercase.
Here is an example based on PSR-4 Autoloader:
<?php
/*
* Folder and file structure:
* \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
*/
$routes->get('helloworld', '\App\Controllers\HelloWorld::index');
If you want another naming convention you need to manually define it using the Defined Route Routing.
Methods
In the above example, the method name is getIndex()
.
The method (HTTP verb + Index()
) is loaded if the second segment of the URI is empty.
The second segment of the URI determines which method in the controller gets called.
Let’s try it. Add a new method to your controller:
<?php
namespace App\Controllers;
class Helloworld extends BaseController
{
public function getIndex()
{
return 'Hello World!';
}
public function getComment()
{
return 'I am not flat!';
}
}
Now load the following URL to see the getComment()
method:
example.com/index.php/helloworld/comment/
You should see your new message.
Warning
For security reasons be sure to declare any new utility methods as protected
or private
.
Passing URI Segments to Your Methods
If your URI contains more than two segments they will be passed to your method as parameters.
For example, let’s say you have a URI like this:
example.com/index.php/products/shoes/sandals/123
Your method will be passed URI segments 3 and 4 ('sandals'
and '123'
):
<?php
namespace App\Controllers;
class Products extends BaseController
{
public function getShoes($sandals, $id)
{
return $sandals . $id;
}
}
Defining a Default Controller
CodeIgniter can be told to load a default controller when a URI is not
present, as will be the case when only your site root URL is requested. Let’s try it
with the Helloworld
controller.
To specify a default controller open your app/Config/Routes.php file and set this variable:
<?php
$routes->setDefaultController('Helloworld');
Where Helloworld
is the name of the controller class you want to be used.
A few lines further down Routes.php in the “Route Definitions” section, comment out the line:
<?php
$routes->get('/', 'Home::index');
If you now browse to your site without specifying any URI segments you’ll see the “Hello World” message.
Note
The line $routes->get('/', 'Home::index');
is an optimization that you will want to use in a “real-world” app. But for demonstration purposes we don’t want to use that feature. $routes->get()
is explained in URI Routing
For more information, please refer to the Routes Configuration Options section of the URI Routing documentation.
Organizing Your Controllers into Sub-directories
If you are building a large application you might want to hierarchically organize or structure your controllers into sub-directories. CodeIgniter permits you to do this.
Simply create sub-directories under the main app/Controllers/, and place your controller classes within them.
Important
Folder names MUST start with an uppercase letter and ONLY the first character can be uppercase.
When using this feature the first segment of your URI must specify the folder. For example, let’s say you have a controller located here:
app/Controllers/Products/Shoes.php
To call the above controller your URI will look something like this:
example.com/index.php/products/shoes/show/123
Note
You cannot have directories with the same name in app/Controllers/ and public/. This is because if there is a directory, the web server will search for it and it will not be routed to CodeIgniter.
Each of your sub-directories may contain a default controller which will be called if the URL contains only the sub-directory. Simply put a controller in there that matches the name of your default controller as specified in your app/Config/Routes.php file.
CodeIgniter also permits you to map your URIs using its Defined Route Routing..
Auto Routing (Legacy)
This section describes the functionality of Auto Routing (Legacy) that is a routing system from CodeIgniter 3. It automatically routes an HTTP request, and executes the corresponding controller method without route definitions. The auto-routing is disabled by default.
Warning
To prevent misconfiguration and miscoding, we recommend that you do not use Auto Routing (Legacy). It is easy to create vulnerable apps where controller filters or CSRF protection are bypassed.
Important
Auto Routing (Legacy) routes a HTTP request with any HTTP method to a controller method.
Consider this URI:
example.com/index.php/helloworld/
In the above example, CodeIgniter would attempt to find a controller named Helloworld.php and load it.
Note
When a controller’s short name matches the first segment of a URI, it will be loaded.
Let’s try it: Hello World!
Let’s create a simple controller so you can see it in action. Using your text editor, create a file called Helloworld.php,
and put the following code in it. You will notice that the Helloworld
Controller is extending the BaseController
. you can
also extend the CodeIgniter\Controller
if you do not need the functionality of the BaseController.
The BaseController provides a convenient place for loading components and performing functions that are needed by all your controllers. You can extend this class in any new controller.
For security reasons be sure to declare any new utility methods as protected
or private
:
<?php
namespace App\Controllers;
class Helloworld extends BaseController
{
public function index()
{
return 'Hello World!';
}
}
Then save the file to your app/Controllers/ directory.
Important
The file must be called Helloworld.php, with a capital H
. Controller class names MUST start with an uppercase letter and ONLY the first character can be uppercase.
Now visit your site using a URL similar to this:
example.com/index.php/helloworld
If you did it right you should see:
Hello World!
This is valid:
<?php
namespace App\Controllers;
class Helloworld extends BaseController
{
// ...
}
This is not valid:
<?php
namespace App\Controllers;
class helloworld extends BaseController
{
// ...
}
This is not valid:
<?php
namespace App\Controllers;
class HelloWorld extends BaseController
{
// ...
}
Also, always make sure your controller extends the parent controller class so that it can inherit all its methods.
Note
The system will attempt to match the URI against Controllers by matching each segment against folders/files in app/Controllers/, when a match wasn’t found against defined routes. That’s why your folders/files MUST start with a capital letter and the rest MUST be lowercase.
Here is an example based on PSR-4 Autoloader:
<?php
/*
* Folder and file structure:
* \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
*/
$routes->get('helloworld', '\App\Controllers\HelloWorld::index');
If you want another naming convention you need to manually define it using the Defined Route Routing.
Methods
In the above example, the method name is index()
. The index()
method
is always loaded by default if the second segment of the URI is
empty. Another way to show your “Hello World” message would be this:
example.com/index.php/helloworld/index/
The second segment of the URI determines which method in the controller gets called.
Let’s try it. Add a new method to your controller:
<?php
namespace App\Controllers;
class Helloworld extends BaseController
{
public function index()
{
return 'Hello World!';
}
public function comment()
{
return 'I am not flat!';
}
}
Now load the following URL to see the comment method:
example.com/index.php/helloworld/comment/
You should see your new message.
Passing URI Segments to Your Methods
If your URI contains more than two segments they will be passed to your method as parameters.
For example, let’s say you have a URI like this:
example.com/index.php/products/shoes/sandals/123
Your method will be passed URI segments 3 and 4 ('sandals'
and '123'
):
<?php
namespace App\Controllers;
class Products extends BaseController
{
public function shoes($sandals, $id)
{
return $sandals . $id;
}
}
Defining a Default Controller
CodeIgniter can be told to load a default controller when a URI is not
present, as will be the case when only your site root URL is requested. Let’s try it
with the Helloworld
controller.
To specify a default controller open your app/Config/Routes.php file and set this variable:
<?php
$routes->setDefaultController('Helloworld');
Where Helloworld
is the name of the controller class you want to be used.
A few lines further down Routes.php in the “Route Definitions” section, comment out the line:
<?php
$routes->get('/', 'Home::index');
If you now browse to your site without specifying any URI segments you’ll see the “Hello World” message.
Note
The line $routes->get('/', 'Home::index');
is an optimization that you will want to use in a “real-world” app. But for demonstration purposes we don’t want to use that feature. $routes->get()
is explained in URI Routing
For more information, please refer to the Routes Configuration Options section of the URI Routing documentation.
Organizing Your Controllers into Sub-directories
If you are building a large application you might want to hierarchically organize or structure your controllers into sub-directories. CodeIgniter permits you to do this.
Simply create sub-directories under the main app/Controllers/, and place your controller classes within them.
Important
Folder names MUST start with an uppercase letter and ONLY the first character can be uppercase.
When using this feature the first segment of your URI must specify the folder. For example, let’s say you have a controller located here:
app/Controllers/Products/Shoes.php
To call the above controller your URI will look something like this:
example.com/index.php/products/shoes/show/123
Note
You cannot have directories with the same name in app/Controllers/ and public/. This is because if there is a directory, the web server will search for it and it will not be routed to CodeIgniter.
Each of your sub-directories may contain a default controller which will be called if the URL contains only the sub-directory. Simply put a controller in there that matches the name of your default controller as specified in your app/Config/Routes.php file.
CodeIgniter also permits you to map your URIs using its Defined Route Routing..
Remapping Method Calls
As noted above, the second segment of the URI typically determines which
method in the controller gets called. CodeIgniter permits you to override
this behavior through the use of the _remap()
method:
<?php
namespace App\Controllers;
class Products extends BaseController
{
public function _remap()
{
// Some code here...
}
}
Important
If your controller contains a method named _remap()
,
it will always get called regardless of what your URI contains. It
overrides the normal behavior in which the URI determines which method
is called, allowing you to define your own method routing rules.
The overridden method call (typically the second segment of the URI) will
be passed as a parameter to the _remap()
method:
<?php
namespace App\Controllers;
class Products extends BaseController
{
public function _remap($method)
{
if ($method === 'some_method') {
return $this->{$method}();
}
return $this->default_method();
}
}
Any extra segments after the method name are passed into _remap()
. These parameters can be passed to the method
to emulate CodeIgniter’s default behavior.
Example:
<?php
namespace App\Controllers;
class Products extends BaseController
{
public function _remap($method, ...$params)
{
$method = 'process_' . $method;
if (method_exists($this, $method)) {
return $this->{$method}(...$params);
}
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
}
Extending the Controller
If you want to extend the controller, see Extending the Controller.
That’s it!
That, in a nutshell, is all there is to know about controllers.