Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

With Eloquent Laravel Package

mod-ci/with-eloquent

View on GitHub
Deep Wiki
Context7

Getting Started

This module glues illuminate/database (Eloquent) onto a CodeIgniter 3 codebase. As a Laravel developer, treat it as "Eloquent without the framework": you get models, relationships, the query builder, and the Capsule manager, but no Artisan, no service container, no facades, and no migration runner.

Minimal setup

  1. Confirm the host app is CodeIgniter 3 (bcit-ci/CodeIgniter) on PHP 7.4+ (8.1+ if you want current illuminate/database).
  2. Install:
    composer require mod-ci/with-eloquent
    
    If your install is module-based (HMVC-style), the package drops into application/modules/with_eloquent/; otherwise rely on Composer's autoloader.
  3. Enable Composer autoload in application/config/config.php:
    $config['composer_autoload'] = FCPATH . 'vendor/autoload.php';
    
  4. Copy the module's config into application/config/eloquent.php and point it at the same credentials as application/config/database.php. Keep this file as the single source of truth for Eloquent connections.
  5. Register the module so Capsule is booted once per request (a pre_system or post_controller_constructor hook is the usual place, or the module's own bootstrap if it self-registers).
  6. Smoke test from any controller:
    $user = \App\Models\User::find(1);
    var_dump($user->toArray());
    

Where to look first

  • The module's config/eloquent.php — connection names, fetch mode, and whether it mirrors CI's $db group.
  • The base model class it ships (often CI_Model-adjacent) — this is where $connection, $table, and $timestamps defaults live.
  • vendor/illuminate/database/Capsule/Manager.php — every gotcha downstream traces back to how (and how often) Capsule is booted.

First use case

A read-heavy admin screen backed by CI's Query Builder is the lowest-risk adoption point. Swap one listing query for an Eloquent model, confirm pagination and JSON output match, then expand outward into the write paths.

Implementation Patterns

Base model, once

Create a project-level base so you never repeat connection wiring:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

abstract class BaseModel extends Model
{
    protected $connection = 'default';   // must match eloquent.php
    public $timestamps  = true;
    protected $guarded  = ['id'];
    protected $perPage   = 25;
}

Models in controllers

Eloquent models are instantiated directly; CI's $this->load->model() will not find them unless the module overrides the loader. A thin CI wrapper keeps existing controller idioms intact:

class User_model extends CI_Model
{
    public function find($id) { return \App\Models\User::find($id); }
    public function paginate($n = 25) { return \App\Models\User::paginate($n); }
}

Eager loading and scopes

The same patterns you use in Laravel transfer verbatim — which is the whole point of adopting this module:

$orders = \App\Models\Order::with(['customer', 'lines.product'])
    ->where('status', 'open')
    ->orderByDesc('created_at')
    ->paginate(20);

Local scopes, hasMany/belongsToMany, whereHas, and withCount all work. Push reusable filters into scopes rather than controller code so both CI and Eloquent call sites stay consistent.

Pagination into CI views

paginate() returns an Illuminate\Pagination\LengthAwarePaginator, not CI's $this->pagination. Render it explicitly and pass markup to the view:

$data['orders'] = $orders->items();
$data['links']  = $orders->appends($this->input->get())->links('pagination::bootstrap-4');
$this->load->view('orders/index', $data);

Transactions

Prefer Capsule's connection-level transaction helper over manual beginTransaction/commit, and never span a CI connection and an Eloquent connection in one transaction unless both point at the same PDO handle:

\Illuminate\Database\Capsule\Manager::connection()->transaction(function () use ($payload) {
    $order = \App\Models\Order::create($payload);
    $order->lines()->createMany($payload['lines']);
});

Mixing with the CI Query Builder

Use Capsule::table(...) for the Eloquent-side builder and $this->db for legacy CI code. If you must share the connection, configure Eloquent to reuse CI's PDO instance in the module bootstrap; otherwise assume two connections and design transactions accordingly.

Hydration and validation

Keep form_validation as the validation layer and hydrate Eloquent after it passes:

if ($this->form_validation->run() === false) { /* re-render */ }

\App\Models\Customer::create([
    'name'  => $this->input->post('name', true),
    'email' => $this->input->post('email', true),
]);

Schema and seeding without Artisan

Use illuminate/database's Schema builder from a CLI script or a CI controller guarded by is_cli(), or install Phinx. Do not expect php artisan migrate — it does not exist here.

JSON APIs

No response()->json(); use CI's output class with the model's array form:

$this->output
     ->set_content_type('application/json')
     ->set_output(json_encode($orders->toArray()));

toArray() respects $hidden/$visible/$appends, so define those on the model instead of hand-building arrays in controllers.

Gotchas and Tips

  • Two configs, one database. application/config/database.php and application/config/eloquent.php drift immediately. Generate one from the other, or have the module bootstrap read CI's $db array directly.
  • Boot Capsule exactly once. Registering the module on every model instantiation leaks memory and re-adds connections; put it in a hook or the autoloader, not in a base model constructor.
  • $this->load->model() will not see Eloquent classes. The CI loader looks in application/models/ by filename convention. Either keep wrappers there or resolve classes through Composer's PSR-4 autoload directly.
  • QueryException is not a CI CI_Model error. It will bubble past CI's database error handler. Wrap risky writes in try/catch and route to log_message('error', ...) so failures land in CI's log pipeline.
  • Package metadata points at the CodeIgniter repository, not the module. Verify you are installing the actual mod-ci/with-eloquent source, and pin a commit or tag — a repo mismatch here is the fastest way to end up with the wrong code.
  • PHP/Illuminate version matrix. illuminate/database versions are pinned to PHP minor versions. Lock the pair (illuminate/database:^9 on PHP 8.0, ^10 on 8.1+) before upgrading the host.
  • Timezone and date formats. Eloquent casts timestamps to Carbon; CI's $config['time_reference'] and PHP's date_default_timezone_set must match the connection's timezone, or created_at values shift silently.
  • Pagination markup and URI segment conflicts. CI's $config['uri_segment'] is irrelevant to the Eloquent paginator, but your CI routes may still be built around it. Use appends() to preserve query string filters across pages.
  • N+1 bites harder here. You have no Laravel debugbar. Add Capsule::connection()->enableQueryLog() behind a ENVIRONMENT === 'development' guard, or a DB::listen() dump in the module bootstrap.
  • Mass assignment. Set $fillable or $guarded on every model. $this->input->post() returns null for absent keys, which can null out columns unexpectedly if you pass the raw array into create().
  • Model events do not replace CI hooks. If existing code depends on CI's post_controller hooks for auditing, Eloquent's saving/saved events will not fire those — bridge them explicitly.
  • No caching layer. Eloquent has no built-in query cache; use CI's $this->cache or illuminate/cache if already pulled in. Do not assume Cache::remember exists until you confirm the dependency.
  • Soft deletes require the column and the trait. use SoftDeletes; plus deleted_at in the schema, or every query silently ignores the concept and your "archive" screen shows nothing.
  • Testing. Bootstrap Capsule in phpunit.xml's bootstrap (or a setUpBeforeClass) against a test connection. Laravel's RefreshDatabase trait is not available; use schema-builder drop/create in setup and truncate between tests.
  • Extension point to watch. The module's Capsule bootstrap is the right seam for global scopes (multi-tenancy, soft-delete-by-default) and for DB::listen. Put cross-cutting concerns there rather than in every model.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core