Blog CRUD using ORM

This guide demonstrates a basic Blog CRUD implementation using LavaLust’s Model-View-Controller pattern with the updated ORM features.

Folder structure

app/
├── controllers/
│   └── BlogController.php
│
├── models/
│   └── BlogModel.php
│
└── views/
    └── blog/
        ├── index.php
        ├── create.php
        ├── edit.php
        └── show.php

Table Structure

Column

Type

Nullable

Description

id

INT, AUTO_INCREMENT

No

Primary key

title

VARCHAR(255)

No

Blog post title

content

TEXT

No

Blog post content

author

VARCHAR(100)

No

Author name

created_at

DATETIME

No

Timestamp of creation

updated_at

DATETIME

Yes

Timestamp of last update

Model

<?php
class BlogModel extends Model
{
    protected $table = 'blog';
    protected $primary_key = 'id';
    protected $fillable = ['title', 'content', 'author'];
    protected $guarded = ['id'];
    protected $timestamps = true;
    protected $created_at_column = 'created_at';
    protected $updated_at_column = 'updated_at';
    protected $has_soft_delete = false;
    protected $soft_delete_column = 'deleted_at';

    public function get_all_posts()
    {
        return $this->all();
    }

    public function get_post($id)
    {
        return $this->find($id);
    }

    public function create_post($data)
    {
        return $this->insert($data);
    }

    public function update_post($id, $data)
    {
        return $this->update($id, $data);
    }

    public function delete_post($id)
    {
        return $this->delete($id);
    }
}

Controller

<?php
class BlogController extends Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->call->model('BlogModel');
    }

    public function index()
    {
        $data['posts'] = $this->BlogModel->get_all_posts();
        $this->call->view('blog/index', $data);
    }

    public function view($id)
    {
        $data['post'] = $this->BlogModel->get_post($id);
        $this->call->view('blog/view', $data);
    }

    public function create()
    {
        if ($_POST) {
            $this->BlogModel->create_post([
                'title'      => filter_io('string', $this->io->post('title')),
                'content'    => filter_io('string', $this->io->post('content')),
                'author'     => 'Admin'
            ]);
            redirect('blog');
        } else {
            $this->call->view('blog/create');
        }
    }

    public function edit($id)
    {
        if ($_POST) {
            $this->BlogModel->update_post($id, [
                'title'      => filter_io('string', $this->io->post('title')),
                'content'    => filter_io('string', $this->io->post('content'))
            ]);
            redirect('blog');
        } else {
            $data['post'] = $this->BlogModel->get_post($id);
            $this->call->view('blog/edit', $data);
        }
    }

    public function delete($id)
    {
        $this->BlogModel->delete_post($id);
        redirect('blog');
    }
}

Views

Index View - List all posts

<?php foreach($posts as $post): ?>
    <h2><?= html_escape($post['title']) ?></h2>
    <p><?= str_limitwords($post['content'], 20) ?></p>
    <a href="<?= site_url('blog/view/' . $post['id']) ?>">Read More</a>
    <a href="<?= site_url('blog/edit/' . $post['id']) ?>">Edit</a>
    <a href="<?= site_url('blog/delete/' . $post['id']) ?>">Delete</a>
<?php endforeach; ?>

View Single Post

<h1><?= html_escape($post['title']) ?></h1>
<p><?= html_escape($post['content']) ?></p>
<p>Author: <?= html_escape($post['author']) ?></p>

Create/Edit Form

<form method="post" action="//put your route here">
    <label>Title</label>
    <input type="text" name="title" value="<?= $post['title'] ?? '' ?>" />
    <label>Content</label>
    <textarea name="content"><?= $post['content'] ?? '' ?></textarea>
    <button type="submit">Save</button>
</form>

Notes

  • Always sanitize input using filter_io() or LavaLust’s security helpers

  • Always sanitize output using html_escape()

  • The Model now returns arrays, not objects

  • Use $fillable to whitelist mass assignable attributes

  • Use $guarded to blacklist attributes from mass assignment

  • Set $timestamps = true to automatically manage created_at and updated_at

  • Enable soft delete by setting $has_soft_delete = true and adding a deleted_at column

  • The Model handles database interaction

  • The Controller handles request logic

  • The View displays data to the user