Create models in CodeIgniter 4
Now we are going to see how we can create a fundamental component in our MVC, which has been the component that allows us to work with the data base layer using the migrations in CodeIgniter 4 that we created earlier, which cannot be other than the model, the model is simply a class, just as it happens With other frameworks like Laravel that extends Model, for the model, unlike version 3, we have to define several attributes to be able to use it or to be functional.
Remember that the primary function of a model is to connect a model to a table in the database.
We have to indicate the insertable fields, that is, those fields that we are going to use to manage said table linked to the table; in other words the columns; for example, let's start with a table like the following:

Therefore, we want to manage all the columns of the previous database table for our model, and following the comments above:
We also have to indicate the property called table, to indicate which table our model matches with which table in the configured database:
<?php
namespace App\Models; // Adjust the namespace according to your structure
use CodeIgniter\Model; // Or the corresponding Model class for your framework
class MovieModel extends Model
{
/**
* @var string Database table name.
*/
protected $table = 'movies';
/**
* @var string Primary key of the table.
*/
protected $primaryKey = 'id';
/**
* @var string[] Fields that are allowed to be mass-assigned (inserted/updated).
*/
protected $allowedFields = [
'title',
'description',
'category_id',
];
}Main Properties in the Models
You are about to name the most important properties that you can use to define the model, you can see the rest of the properties that you can define for the model in the official documentation; some very interesting properties would be for example.
$returnType
Here we can indicate if we want by default the data that we can obtain by making select type queries to the database, return them in an array type structure ('array') or object type ('object').
$createdField
Here we can indicate the name of the field for the creation date, and it will be established when we create a new record.
$validationRules
With this property we can indicate the validation rules on the columns of our model that will be used in the creation and update phase.
Other important properties of models in CodeIgniter 4:
The model layer in the MVC (Model-View-Controller) design pattern is the layer that handles business logic and communication with the database. That is, it is the layer that performs the CRUD operations (Create, Read, Update and Delete) in a database, usually a model governs a table in the database. Let's see the most common properties that we can apply to our models in CodeIgniter 4 and what they are for.
$table
Specifies the database table with which this model works.
$primaryKey
This is the name of the column that uniquely identifies the records in this table. This does not necessarily have to match the primary key that is specified in the database; used with methods like find() to find out which column to match the specified value against.
$useAutoIncrement
Specifies whether the table uses an auto-increment function for $primaryKey. If set to false, you are responsible for providing the primary key value for each record in the table.
$returnType
This setting allows you to define the type of data that is returned. Valid values are 'array' (the default value), 'object', or the fully qualified name of a class that can be used with the getCustomResultObject() method of the Result object.
$useSoftDeletes
If true, any calls to the delete() method will set the delete_at to the database, instead of deleting the row. This can preserve data when it can be referenced elsewhere, or it can maintain a "recycle bin" of objects that can be restored, or even just preserve it as part of a security trace. If true, the find*() methods will only return undeleted rows, unless the withDeleted() method is called before the find*() method is called.
$allowedFields
This array should be updated with the field names that can be set during the save(), insert() or update() methods. Any field name other than this will be discarded. This helps protect the integrity of columns that we don't want the application to be able to interact with.
$useTimestamps
This boolean value determines whether the current date is automatically added to all inserts and updates. If true, it will set the current time in the format specified by $dateFormat. This requires that the table have columns named created_at and updated_at in the appropriate data type.
$createdField
Specifies which database field to use for the data record creation timestamp.
$updatedField
Specifies which field in the database should be used to hold the data record update timestamp.
These are some of the most common configurations and you can see the full list here:
https://codeigniter.com/user_guide/models/model.html#id6
Common operations
As in any MVC framework, the models are another of the MVC layers and it is the layer that allows connecting to the database. A model is used to interact with the database and perform management operations on it, that is, create, update, delete and drill down records, each model is tied to a table in the database, the models are the only way to access the database.
To create a model in CodeIgniter 4, you can use the CLI with the following command:
$ php spark make:model NameModelThis command will create a new class for the model in app/Models. You can also indicate properties to customize the connection such as the name of the PK, table, custom functions and much more.
Once a model has been created, it can be used in a controller or anywhere else in the application to interact with the database.
Key functions in the models
Apart from the operations that we have already performed, there are many combinations that you can perform according to your needs; Let's look at some of what we can do in CodeIgniter 4.
Joins
The joins are used to combine results between different tables looking for the relational field; in CodeIgniter we have different types of joins (left, right, inner…) just like we have in SQL; as the first parameter of the join() function we pass the table to relate, and as the next parameter, equality.
$peliculaModel->asObject()
->select('peliculas.*, categorias.titulo as categoria')
->join('categorias, 'categorias.id = peliculas.categoria_id')
->find()Paginate
This function can also be simulated in SQL, although in CodeIgniter we go a step further; later we will see how to use this function in detail; but in essence it is to use the paginate() function indicating the pagination level as a parameter.
$peliculaModel->asObject()
->select('peliculas.*, categorias.titulo as categoria')
->join('categorias, 'categorias.id = peliculas.categoria_id')
->paginate(10)where
The wheres are essential in most of the queries we make and therefore you have to keep them in mind; receives two parameters corresponding to the column to compare and its value.
$peliculaModel->asObject()
->select('peliculas.*, categorias.titulo as categoria')
->join('categorias, 'categorias.id = peliculas.categoria_id')
->where('categorias.id', $categoria_id')
->find()Nested with orWhere conditions
Similar to the previous case, but applying the or conditions instead of the where conditions:
$usuarioModel->orWhere('email', $email)->orWhere('usuario', $usuario)->first();Conditions Like
Likes are widely used when we are doing partial searches; its use is similar to the where:
$peliculaModel->asObject()
->select('peliculas.*, categorias.titulo as categoria')
->join('categorias, 'categorias.id = peliculas.categoria_id')
->like('peliculas.titulo', $buscar)
->find()Grouped
In this example we see how to use the groupBy function to group by similar fields; (depending on the version of MySQL you are using, the fields to be grouped may have to match the columns specified in the select) whose function in CodeIgniter allows you to return exactly the columns you specify, indicating aliases in the process.
$peliculaModel->asObject()
->select('peliculas.*, categorias.titulo as categoria')
->join('categorias, 'categorias.id = peliculas.categoria_id')
->join('imagenes', 'peliculas.id = pelicula_id', 'left')
->groupBy('peliculas.id');
->find()See compiled query
Finally, when you are building your queries, you often want to see the generated SQL to know exactly how you are building the query, since, with the structure based on functions to create a query, it is often not entirely clear.
To see the query, we need to get an instance of the 'CodeIgniter Query Builder' class with which we have a generic instance to connect to any table without using a model:
$db = \Config\Database::connect();
$builder = $db->table('peliculas');With the query, instead of using final functions like get() or first() we use the getCompiledSelect() function instead:
return $builder->limit(10, 20)->getCompiledSelect();And we get:
SELECT * FROM `peliculas` LIMIT 20, 10The most important thing is to note that there are equivalences between the query types that we can use in SQL, with a set of functions that we have in CodeIgniter; these functions are learned with practice, knowing which parameters you must pass, which ones are optional and how you can customize them.
This material is part of my complete course and book on CodeIgniter 4.
Created_at and updated_at columns
That we have the advantage of defining a field that is automatically filled with the current date at the time the record is created and more interesting, that when we edit that record, the current date is defined, it is something extremely simple in frameworks like Laravel and that in CodeIgniter 4, we can also use in a simple way. We need to define about 3 attributes in our model:
- $useTimestamps - Boolean that indicates if you are going to enable the timestamp for creation and update.
- $createdField - Define the name of the column of the creation field.
- $updatedField - Define the name of the update field column.
For example, in the following model, we define the corresponding properties along with the 3 noted above:
<?php
namespace App\Models;
use CodeIgniter\Model;
class ProductsControlModel extends Model
{
protected $table = 'products_control';
protected $primaryKey = 'id';
protected $allowedFields = ['product_id', 'type','count', 'created_at', 'updated_at'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';Foreign relations in CodeIgniter 4

Relationships are the heart of relational databases, relationships are a set of rules that describe how the tables in the database are related to each other; and hence the relation name. In a relational database, data is organized into tables, with each table representing an entity or object; but many times they are related to each other, if we have a car relationship, the cars have brands, therefore, we can have a table for the cars and another for the brands and we relate them to each other through the unique identifier that is assigned to each table, that is, the PK.
This primary key when it is established in the table to be related (in this example, we must register the PK of the models table in the cars table) is known as a FOREIGN KEY type restriction or foreign key in Spanish. Let's see how to handle it in Codeigniter 4.
Migration of the table to relate
In CodeIgniter 4, as it happens with Laravel, in order to structure this type of relationship, we have to define it from the migrations; In this example, I am going to take a couple of tables from my entire course, those of movies and categories in which a movie or film belongs to a category; first the migration of the table to relate, that is, the one of movies:
<?php namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Categories extends Migration
{
public function up(){
$this->forge->addField([
'id' => [
'type' => 'INT',
'constraint' => 5,
'unsigned' => TRUE,
'auto_increment' => TRUE
],
'title' => [
'type' => 'VARCHAR',
'constraint' => '255',
],
]);
$this->forge->addKey('id', TRUE);
$this->forge->createTable('categories');
}
//--------------------------------------------------------------------
public function down()
{
$this->forge->dropTable('categories');
}
}Typically, an id and name field for the categories and in the down function we do the inverse operations to that of one, that if in the up we create a table, we destroy it with the down; remember that the issue of migrations in CodeIgniter has already been discussed.
Migration of the FK or foreign key
Finally the table that we are going to relate by means of the foreign key:
<?php namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Movies extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'constraint' => 5,
'unsigned' => TRUE,
'auto_increment' => TRUE
],
title=> [
'type' => 'VARCHAR',
'constraint' => 255
]
'category_id' => [
'type' => 'INT',
'constraint' => 5,
'unsigned' => TRUE
],
****
]);
$this->forge->addKey('id', TRUE);
$this->forge->addForeignKey('category_id' , categories,'id','CASCADE','CASCADE');
$this->forge->createTable('movies');
}
//--------------------------------------------------------------------
public function down()
{
$this->forge->dropTable('movies');
}
}A migration with an ID field to keep it simple and the rest of the fields that in an exemplary way we only have the one of the title; the important thing here is the column called category_id that we use with it later to define the foreign key through the addForeignKey function, which receives:
- The name of the column in movies, i.e. the table that will hold the FK relationship
- The name of the table to relate, categories in our case
- The column of the table to relate, that is, the PK of categories that is called id
Models
Finally, the models of the previous migrations:
<?php namespace App\Models;
use CodeIgniter\Model;
class MovieModel extends Model
{
protected $table = 'movies';
protected $primaryKey = 'id';
protected $allowedFields = ['title','category_id'];
}
<?php namespace App\Models;
use CodeIgniter\Model;
class CategoryModel extends Model
{
protected $table = 'categories';
protected $primaryKey = 'id';
protected $allowedFields = ['title'];
public function get($id = null)
{
if ($id === null) {
return $this->findAll();
}
return $this->asArray()
->where(['id' => $id])
->first();
}
}Extra: Create a record with foreign relationship
To create a record you don't have to define some additional rules and structure; the FK relation to the final is an integer column with an extra constraint that is the FK; so, we directly pass the value of the key to relate; In this example, we are assuming that this data is received from a form:
$movie = new MovieModel();
if ($this->validate('movies')) {
$id = $movie->insert([
'title' => $this->request->getPost('title'),
'description' => $this->request->getPost('description'),
'category_id' => $this->request->getPost('category_id'),
]);Other information about the models
- In the models our business logic goes, components such as specific functions that we want to use within the app, such as get all or a set of records are simply functions that we create for each process; for example, a function to get all records.
- When we work with queries, there are functions that we can use for free (already provided by the framework) to work with the records; for example, the method called find, to obtain a record, or the first, insert, save, update whose names are self-explanatory or indicate what function they perform.
- Models are a component that matches migrations, since it is usual that there is a one-to-one correspondence between tables, migrations and models, in the case of CodeIgniter 4, migrations are a separate file and composition that the of the model, that is, they are independent, unlike other frameworks such as Django or Flask, whose migration composition is generated from the models.
Database join queries in CodeIgniter 4

In SQL, JOINs are an operation used to combine two or more relational tables based on a common column or set of columns, generally FK type columns or foreign keys are used to make this connection between different tables. They are used to retrieve data from multiple related tables, allowing the data to be presented in a more complete and meaningful way; for example, if we have a table of posts and another of categories, we can indicate that a post contains a category by means of a FK in the table of posts and then do a JOIN that allows us to connect the table of posts with the table of categories and obtain the full detail of the post; We can do the same with multiple tables.
There are different types of JOINs in SQL, such as INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL OUTER JOIN, each with a different purpose depending on the user's need.
In the CodeIgniter 4 application, according to the documentation, we have 3 types of joins available. Here are the following:
- Inner Join
- Left Join
- Right Join
- Inner Join: This join fetches data based on a common value condition between two or more than two tables. Based on the matching condition, it will return all the data we expected. Removes those rows from the result set that do not have a matching condition.
- Left Join – This also works the same as the match condition between two or more than two tables. But in this case we also get the rows from the table on the left that do not match the condition of the table on the right side. It means that we get all the rows in the table on the left, including the values in the table on the right.
- Right Join – Rows with the same matching conditions, including all rows on the right side with no match conditions.
The use of joins in CodeIgniter 4 is very easy and all we have to do is build the main query:
$query = $productModel->asObject()->select("pc.*, u.email, puc.description, puc.direction")In this case, an example model, called "productModel" and now, we are going to perform the join(s):
$query = $productModel->asObject()->select("pc.*, u.email, puc.description, puc.direction")
->join('products_control as pc', 'pc.product_id = products.id')In which, you can place as many joins as you need and/or your relationships allow, in my case, a product, has a foreign relationship with "'products_control" and "'products_control" a foreign relationship (fk) with "users" and finally with "'products_users_control"
$query = $productModel->asObject()->select("pc.*, u.email, puc.description, puc.direction")
->join('products_control as pc', 'pc.product_id = products.id')
->join('users as u', 'pc.user_id = u.id')
->join('products_users_control as puc', 'pc.id = puc.product_control_id');Key points
The join function receives two mandatory parameters and a third optional one.
As the first parameter we indicate the name of the table which we want to join.
Optionally, we indicate an alias by "as" to avoid repeating the table name when we want to reference the table: products_control as pc
As a second parameter we indicate the condition; which is generally to place the equality of our relation (fk)
As the third parameter you can specify the type of join: left, right, outer, inner, left outer, and right outer: join('products_control as pc', 'pc.product_id = products.id','left')
Without more to say, the relations that we use in my complete course on CodeIgniter 4:
class ProductModel extends Model
{
protected $table = 'products';
protected $primaryKey = 'id';
protected $allowedFields = ['name', 'code', 'description', 'entry', 'exit', 'stock', 'price'];
public function get($id = null)
{
if ($id === null) {
return $this->findAll();
}
return $this->asArray()
->where(['id' => $id])
->first();
}
}
class ProductControlModel extends Model
{
protected $table = 'products_control';
protected $primaryKey = 'id';
protected $allowedFields = ['product_id', 'type','count', 'created_at', 'updated_at','user_id'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
public function get($id = null)
{
if ($id === null) {
return $this->findAll();
}
return $this->asArray()
->where(['id' => $id])
->first();
}
}
class ProductUserControlModel extends Model
{
protected $table = 'products_users_control';
protected $primaryKey = 'id';
protected $allowedFields = ['product_id', 'user_id', 'product_control_id', 'type', 'count', 'created_at', 'updated_at', 'description', 'direction'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
public function get($id = null)
{
if ($id === null) {
return $this->findAll();
}
return $this->asArray()
->where(['id' => $id])
->first();
}
}
<?php
class User extends BaseController{
use ResponseTrait;
}Remember that in the complete CodeIgniter 4 course, you have much more information and data about the use of this framework.
The JOINS, we always use them to obtain the data of several tables; managing joins in SQL is hard, but working in CodeIgniter is also easy to use. It is either a left join or a right join in CodeIgniter.
We just need to call a method in CodeIgniter $this->db->join('table'.'condition','left,right'). Joins take three parameters: first is the table, second is the condition, and third is the left join or right join in CodeIgniter.
Next step, generate test data using Seeders in CodeIgniter 4.
I agree to receive announcements of interest about this Blog.
We are going to work with the models layer in CodeIgniter 4, which has been one of the layers of our MVC that allows us to work with the data; and we are going to know all the main properties of the models in C4.