Building a CRUD Application with CodeIgniter 4.6 , HTMX, and SweetAlert2

 In this tutorial, we’ll build a User Management System using CodeIgniter 4, HTMX for dynamic front-end interactions, and SweetAlert2 for displaying alerts. We’ll use the provided UserModel to handle database operations and create a fully functional CRUD application.


Prerequisites:

  • Basic knowledge of PHP and CodeIgniter 4.

  • Familiarity with HTMX and JavaScript.

  • CodeIgniter 4 installed and configured.


Step 1: Setting Up the UserModel

The UserModel provided is already well-structured. It includes:

  • Table configuration (users).

  • Automatic timestamps for created_at and updated_at.

  • Soft deletes using deleted_at.

  • Validation rules for name and email.

Here’s the UserModel again for reference:

php
Copy
<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model{
    protected $table = 'users'; // Table name in the database
    protected $primaryKey = 'id'; // Primary key column name
    protected $useAutoIncrement = true; // Set false if using manual IDs

    protected $allowedFields = ['name', 'email', 'password', 'created_at', 'updated_at', 'deleted_at'];
    
    protected $useTimestamps = true; // Enables automatic timestamps
    protected $createdField = 'created_at'; // Column for created timestamp
    protected $updatedField = 'updated_at'; // Column for updated timestamp

    protected $useSoftDeletes = true; // Enables soft delete
    protected $deletedField = 'deleted_at'; // Column for soft deletes

    protected $validationRules = [
        'name' => 'required|min_length[3]|max_length[255]',
        'email' => 'required|valid_email'
    ];
    
    protected $validationMessages = [
        'name' => [
            'required' => 'Name is required',
            'min_length' => 'Name must have at least 3 characters'
        ]
    ];
}

Step 2: Creating the UserController

Next, let’s create a UserController to handle CRUD operations. We’ll use HTMX to make the front-end dynamic and SweetAlert2 to display success/error messages.

php
Copy
<?php

namespace App\Controllers;

use App\Models\UserModel;
use CodeIgniter\API\ResponseTrait;

class UserController extends BaseController
{
    use ResponseTrait;

    protected $userModel;

    public function __construct()
    {
        $this->userModel = new UserModel();
    }

    // List all users
    public function index()
    {
        $data['users'] = $this->userModel->findAll();
        return view('user_list', $data);
    }

    // Show create form
    public function create()
    {
        return view('user_create');
    }

    // Store a new user
    public function store()
    {
        $data = $this->request->getPost();

        if (!$this->userModel->save($data)) {
            return $this->respond([
                'status' => 'error',
                'errors' => $this->userModel->errors()
            ]);
        }

        return $this->respond([
            'status' => 'success',
            'message' => 'User created successfully!'
        ]);
    }

    // Show edit form
    public function edit($id)
    {
        $data['user'] = $this->userModel->find($id);
        return view('user_edit', $data);
    }

    // Update a user
    public function update($id)
    {
        $data = $this->request->getPost();

        if (!$this->userModel->update($id, $data)) {
            return $this->respond([
                'status' => 'error',
                'errors' => $this->userModel->errors()
            ]);
        }

        return $this->respond([
            'status' => 'success',
            'message' => 'User updated successfully!'
        ]);
    }

    // Delete a user (soft delete)
    public function delete($id)
    {
        $this->userModel->delete($id);

        return $this->respond([
            'status' => 'success',
            'message' => 'User deleted successfully!'
        ]);
    }
}

Step 3: Creating Views with HTMX

We’ll use HTMX to handle form submissions and dynamically update the UI without reloading the page.

user_list.php (List all users)

html
Copy
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>User List</title>
    <script src="https://unpkg.com/htmx.org"></script>
    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
</head>
<body>
    <h1>User List</h1>
    <a href="/users/create" hx-get="/users/create" hx-target="#content">Create User</a>
    <div id="content">
        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($users as $user): ?>
                <tr>
                    <td><?= $user['id'] ?></td>
                    <td><?= $user['name'] ?></td>
                    <td><?= $user['email'] ?></td>
                    <td>
                        <a href="/users/edit/<?= $user['id'] ?>" hx-get="/users/edit/<?= $user['id'] ?>" hx-target="#content">Edit</a>
                        <a href="/users/delete/<?= $user['id'] ?>" hx-delete="/users/delete/<?= $user['id'] ?>">Delete</a>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>

    <script>
        document.addEventListener('htmx:afterRequest', handleResponse);
        function handleResponse(event) {
            const response = event.detail.xhr.response;

            try {
                const responseData = JSON.parse(response);

                if (responseData.status === 'success') {
                    Swal.fire({
                        icon: 'success',
                        title: 'Success',
                        text: responseData.message,
                    }).then(() => {
                        window.location.reload(); // Reload page after success
                    });
                } else {
                    const errors = responseData.errors || { general: "An unknown error occurred" };
                    let errorMessages = Object.values(errors).map(error => `<p>${error}</p>`).join('');

                    Swal.fire({
                        icon: 'error',
                        title: 'Error',
                        html: errorMessages,
                    });
                }
            } catch (e) {
                Swal.fire({
                    icon: 'error',
                    title: 'Error',
                    text: 'An unexpected error occurred. Please try again.',
                });
                console.error('Error parsing response:', e);
            }
        }
    </script>
</body>
</html>

user_create.php (Create user form)

html
Copy
<div>
    <h2>Create User</h2>
    <form hx-post="/users/store" hx-target="#content">
        <label for="name">Name:</label>
        <input type="text" name="name" required>
        <label for="email">Email:</label>
        <input type="email" name="email" required>
        <button type="submit">Submit</button>
    </form>
</div>

user_edit.php (Edit user form)

html
Copy
<div>
    <h2>Edit User</h2>
    <form hx-post="/users/update/<?= $user['id'] ?>" hx-target="#content">
        <label for="name">Name:</label>
        <input type="text" name="name" value="<?= $user['name'] ?>" required>
        <label for="email">Email:</label>
        <input type="email" name="email" value="<?= $user['email'] ?>" required>
        <button type="submit">Update</button>
    </form>
</div>

Step 4: Testing the Application

  1. Start your CodeIgniter server.

  2. Navigate to /users to see the list of users.

  3. Use the "Create User" link to add a new user.

  4. Edit or delete users using the respective buttons.


Conclusion

In this tutorial, we built a CRUD application using CodeIgniter 4HTMX, and SweetAlert2. This combination allows for a seamless user experience with dynamic updates and beautiful alerts. You can extend this application by adding features like pagination, search, or user authentication.

Happy coding! 🚀

Share:

Creating Tables in CodeIgniter 4 Without PHP Spark

CodeIgniter 4 provides a powerful migration system to create and manage database tables. While the recommended approach is using php spark migrate, some developers may prefer creating tables manually, especially if they do not have access to the command line or prefer working directly with PHP scripts.

In this guide, we will cover how to create tables in CodeIgniter 4 without using php spark by leveraging the built-in migration feature programmatically.


Step 1: Enable Migrations in CodeIgniter 4

Before creating tables, ensure that migrations are enabled in your CodeIgniter 4 project.

  1. Open app/Config/Migrations.php

  2. Set $enabled to true:

    public $enabled = true;

Step 2: Create a Migration File Manually

Instead of using php spark make:migration, create a migration file manually inside the app/Database/Migrations directory.

  1. Navigate to app/Database/Migrations/

  2. Create a PHP file with a meaningful name, e.g., 2025-02-02-CreateUsersTable.php


Step 3: Define the Migration Class

Open the newly created file and define the table structure:

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateUsersTable extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id' => [
                'type'           => 'INT',
                'constraint'     => 11,
                'unsigned'       => true,
                'auto_increment' => true,
            ],
            'name' => [
                'type'       => 'VARCHAR',
                'constraint' => '100',
            ],
            'email' => [
                'type'       => 'VARCHAR',
                'constraint' => '100',
                'unique'     => true,
            ],
            'password' => [
                'type' => 'VARCHAR',
                'constraint' => '255',
            ],
            'created_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
            'updated_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
            'deleted_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
        ]);
        
        $this->forge->addKey('id', true);
        $this->forge->createTable('users');
    }

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

Step 4: Run the Migration Without PHP Spark

Since we are not using php spark migrate, we need to execute the migration manually.

  1. Open app/Controllers/Migrate.php

  2. Create a new controller (if not already created):

<?php

namespace App\Controllers;

use CodeIgniter\Controller;
use CodeIgniter\Database\Migrations\Runner;

class Migrate extends Controller
{
    public function index()
    {
        $migrations = service('migrations');
        
        try {
            $migrations->latest();
            echo "Migration completed successfully.";
        } catch (Exception $e) {
            echo "Migration failed: " . $e->getMessage();
        }
    }

    public function rollback()
    {
        $migrations = service('migrations');
        
        try {
            $migrations->regress(0);
            echo "Rollback completed successfully.";
        } catch (Exception $e) {
            echo "Rollback failed: " . $e->getMessage();
        }
    }
}

Step 5: Execute the Migration from the Browser

  1. Start your CodeIgniter server: php -S localhost:8080 -t public

  2. Open your browser and visit: http://localhost:8080/migrate

  3. If everything is set up correctly, you should see: Migration completed successfully.

  4. Check your database to confirm that the users table has been created.


How to Drop the Table

If you want to remove the table, you can trigger the down method in the migration file.

  1. Open your browser and visit: http://localhost:8080/migrate/rollback

  2. This will execute down(), which removes the users table.

  3. Check your database to confirm that the table has been dropped.


Conclusion

By following these steps, you can manually create and drop tables in CodeIgniter 4 without using the php spark command. This approach is useful when working in restricted environments or when automating migrations via controllers.

Happy coding!

Share: