Creating the Database and Model

In this section, we set up the data layer by creating a SQLite database table for our books resource, seeding it with sample data, and defining a model to access it. By the end, you’ll have a working books table populated with example rows.

Create the Migrations

Migrations let you version-control your database schema by defining what to apply and how to roll it back. Let’s make ones for simple authors and books tables.

Run the Spark command:

php spark make:migration CreateAuthorsTable
php spark make:migration CreateBooksTable

This creates a new file under app/Database/Migrations/.

Edit app/Database/Migrations/CreateAuthorsTable.php to look like this:

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateAuthorsTable extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id' => [
                'type'           => 'INTEGER',
                'unsigned'       => true,
                'auto_increment' => true,
            ],
            'name' => [
                'type'       => 'VARCHAR',
                'constraint' => '255',
                'null'       => false,
            ],
            'created_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
            'updated_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
        ]);

        $this->forge->addPrimaryKey('id');
        $this->forge->addUniqueKey('name');
        $this->forge->createTable('authors');
    }

    public function down()
    {
        $this->forge->dropTable('authors');
    }
}

Each author only needs a name for our purposes. We’ve made the name a unique key to prevent duplicates.

Now, edit app/Database/Migrations/CreateBooksTable.php to look like this:

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateBooksTable extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id' => [
                'type'           => 'INTEGER',
                'unsigned'       => true,
                'auto_increment' => true,
            ],
            'title' => [
                'type'       => 'VARCHAR',
                'constraint' => '255',
                'null'       => false,
            ],
            'author_id' => [
                'type'     => 'INTEGER',
                'unsigned' => true,
                'null'     => false,
            ],
            'year' => [
                'type' => 'INTEGER',
                'null' => true,
            ],
            'created_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
            'updated_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
        ]);

        $this->forge->addPrimaryKey('id');
        $this->forge->addForeignKey('author_id', 'authors', 'id');
        $this->forge->createTable('books');
    }

    public function down()
    {
        $this->forge->dropTable('books');
    }
}

This contains a foreign key reference to the authors table. It lets us associate each book with an author and keep author names in one place.

Now run the migration:

php spark migrate

Now, the database has the structure needed to hold our book and author records.

Create a seeder

Seeders load sample data for development so you have something to work with right away. Here, we’ll add some example books and their authors.

Run:

php spark make:seeder BookSeeder

Edit the file at app/Database/Seeds/BookSeeder.php:

<?php

namespace App\Database\Seeds;

use CodeIgniter\Database\Seeder;

class BookSeeder extends Seeder
{
    public function run()
    {
        // Define author data and insert
        $authorData = [
            ['name' => 'Frank Herbert'],
            ['name' => 'William Gibson'],
            ['name' => 'Ursula K. Le Guin'],
        ];

        $this->db->table('authors')->insertBatch($authorData);

        // Get all inserted authors, keyed by name for easy lookup
        $authors = $this->db->table('authors')
            ->get()
            ->getResultArray();

        $authorsByName = array_column($authors, 'id', 'name');

        // Define books with author references
        $books = [
            [
                'title'     => 'Dune',
                'author_id' => $authorsByName['Frank Herbert'],
                'year'      => 1965,
            ],
            [
                'title'     => 'Neuromancer',
                'author_id' => $authorsByName['William Gibson'],
                'year'      => 1984,
            ],
            [
                'title'     => 'The Left Hand of Darkness',
                'author_id' => $authorsByName['Ursula K. Le Guin'],
                'year'      => 1969,
            ],
        ];

        $this->db->table('books')->insertBatch($books);
    }
}

This seeder first inserts authors into the authors table, captures their IDs, and then uses those IDs to insert books into the books table.

Then run the seeder:

php spark db:seed BookSeeder

You should see confirmation messages indicating the rows were inserted.

Create the Book model

Models make database access simple and reusable by providing an object-oriented interface to your tables and a fluent query API. Let’s create models for the authors and books tables.

Generate one:

php spark make:model AuthorModel
php spark make:model BookModel

Both models will be simple extensions of CodeIgniter’s base Model class.

Edit app/Models/AuthorModel.php:

<?php

namespace App\Models;

use CodeIgniter\Model;

class AuthorModel extends Model
{
    protected $table         = 'authors';
    protected $primaryKey    = 'id';
    protected $allowedFields = ['name'];
    protected $useTimestamps = true;
}

Edit app/Models/BookModel.php:

<?php

namespace App\Models;

use CodeIgniter\Model;

class BookModel extends Model
{
    protected $table         = 'books';
    protected $primaryKey    = 'id';
    protected $allowedFields = ['title', 'author_id', 'year'];
    protected $useTimestamps = true;
}

This tells CodeIgniter which table to use and which fields can be mass-assigned.

In the next section, we’ll use your new models to power a RESTful API controller. You’ll build the /api/books endpoint and see how CodeIgniter’s Api\ResponseTrait makes CRUD operations easy.