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

Slim Eloquent Laravel Package

zeuxisoo/slim-eloquent

Brings Laravel's Eloquent ORM to Slim Framework, letting Slim applications use ActiveRecord-style models, relationships, and the fluent query builder without the full Laravel stack. Simple configuration for database connections and a familiar, expressive API for everyday persistence.

View on GitHub
Deep Wiki
Context7

Getting Started

slim-eloquent is not an ORM — it is a bootstrap shim that pulls Laravel's illuminate/database (the Eloquent capsule) into a Slim app. Day to day you will spend ~1% of your time on the package and 99% on the Eloquent API underneath it, so treat the README as "how do I get a Capsule wired to my container" and then use standard Eloquent docs.

1. Install and inspect what you actually got.

composer require zeuxisoo/slim-eloquent
composer show zeuxisoo/slim-eloquent
composer show illuminate/database

The second command is the important one. This package is a thin wrapper, and its require block pins an illuminate/database major version. On a modern PHP 8.x project that pin is frequently the blocker (see Gotchas). Read vendor/zeuxisoo/slim-eloquent/composer.json and the source before writing anything — it is small enough to read in one sitting, and that tells you more than the README.

2. Bootstrap the capsule once, at app bootstrap.

Whatever helper the package exposes, the effective work is always the same:

use Illuminate\Database\Capsule\Manager as Capsule;
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;

$capsule = new Capsule;

$capsule->addConnection([
    'driver'    => 'mysql',
    'host'      => $_ENV['DB_HOST'],
    'database'  => $_ENV['DB_NAME'],
    'username'  => $_ENV['DB_USER'],
    'password'  => $_ENV['DB_PASS'],
    'charset'   => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix'    => '',
]);

// Order matters: dispatcher -> global -> boot
$capsule->setEventDispatcher(new Dispatcher(new Container));
$capsule->setAsGlobal();
$capsule->bootEloquent();

Put this in app/bootstrap/database.php and require it from public/index.php / config/bootstrap.php. Do not scatter it across route files.

Then register the capsule in the Slim container so handlers can get it injected:

// Slim 3 / Slim 4 (with a PSR-11 container set via AppFactory::setContainer)
$container = $app->getContainer();
$container->set('db', function () use ($capsule) {
    return $capsule;
});

3. Where to look first in the vendor code. Find the class that wraps Capsule (or Manager) and check: does it call bootEloquent()? Does it call setAsGlobal()? Does it accept an existing container? Those three answers determine almost every gotcha you will hit later.

4. First use case. A single read endpoint, to confirm the wiring is correct before you build abstractions:

// app/Model/User.php
namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $table = 'users';
    protected $fillable = ['name', 'email'];
    protected $hidden = ['password'];
}
// routes.php
$app->get('/users/{id}', function ($request, $response, $args) {
    $user = \App\Model\User::find($args['id']);

    if (!$user) {
        return $response->withStatus(404)
            ->withHeader('Content-Type', 'application/json')
            ->write(json_encode(['error' => 'not found']));
    }

    return $response->withHeader('Content-Type', 'application/json')
        ->write($user->toJson());
});

If find() works, the capsule is booted correctly and everything else is ordinary Eloquent.

Implementation Patterns

Container-aware bootstrap, not globals in route files. Keep one Database factory and inject it. Anything that reaches for Capsule::connection() from inside a model or a service becomes untestable fast.

final class Db
{
    private Capsule $capsule;

    public function __construct(array $config)
    {
        $this->capsule = new Capsule;
        $this->capsule->addConnection($config);
        $this->capsule->setEventDispatcher(new Dispatcher(new Container));
        $this->capsule->setAsGlobal();
        $this->capsule->bootEloquent();
    }

    public function connection(?string $name = null): ConnectionInterface
    {
        return $this->capsule->getConnection($name);
    }

    public function capsule(): Capsule
    {
        return $this->capsule;
    }
}

Thin controller layer, fat models or repositories. With no Laravel container, dependency injection into models does not exist, so push query logic onto model scopes and static-ish query builders rather than into route callbacks.

class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    public function orders()
    {
        return $this->hasMany(Order::class);
    }
}
$users = User::active()->with('orders')->orderBy('id')->limit(50)->get();

Eager loading is not optional. Without Laravel's debug tooling and strict-mode defaults in many pinned versions, N+1 queries are silent. Always ->with() relations you serialize.

Serialization boundary. Return arrays, not models, from handlers so $hidden/$visible and date formats are consistent:

$response->getBody()->write(json_encode(
    $users->map(fn ($u) => $u->only(['id', 'name', 'email']))->all()
));

Transactions around multi-write handlers.

$db->connection()->transaction(function () use ($request) {
    $order = Order::create([...]);
    foreach ($payload['items'] as $item) {
        $order->items()->create($item);
    }
});

Catch Illuminate\Database\QueryException in Slim error middleware and map integrity-constraint violations to 409.

Schema management without Artisan. There are no migrations. Use the schema builder directly in a stand-alone script, or use Phinx / plain SQL. The schema builder is already available:

$schema = $db->connection()->getSchemaBuilder();
$schema->create('users', function ($table) {
    $table->increments('id');
    $table->string('email')->unique();
    $table->timestamps();
});

Multiple connections. addConnection($config, 'reporting'), then protected $connection = 'reporting'; on the model. Useful for read replicas and legacy schemas.

Testing. Point the capsule at sqlite with :memory: in a test bootstrap, run the schema builder in setUp(), and you get a per-test isolated database without any Laravel test traits.

Query observability. Wire the dispatcher (setEventDispatcher) and then:

$capsule->getConnection()->listen(function ($query) use ($logger) {
    $logger->debug($query->sql, $query->bindings);
});

Or ad hoc: $capsule->getConnection()->enableQueryLog(); … ->getQueryLog().

Slim 2 vs Slim 3/4. Slim 2 uses \Slim\Slim and $app->container->singleton(...); Slim 3/4 use PSR-11 $container->set(...). Older versions of this package target Slim 2 — check the tag you install against your Slim major before assuming the integration code in the README applies.

Gotchas and Tips

The illuminate/database pin is the real risk. This is a 5-star, 0-dependent package; expect its composer constraints to be old (4.x/5.x era). If Composer refuses to install against PHP 8.2, do not fight it — you can reproduce the entire functionality with composer require illuminate/database:^10 plus the ~15 lines of capsule bootstrap above. Budget for that outcome rather than debugging version conflicts.

Call setAsGlobal() and bootEloquent() or face confusing failures. bootEloquent() is what installs the connection resolver on Model. Skip it and Model::find() throws "A facade root has not been set" / "No connection resolver". setAsGlobal() is what makes the DB facade and Capsule::connection() resolve.

No event dispatcher, no observers and no model events. creating, saving, deleted, observers, and some soft-delete behaviour all require setEventDispatcher(new Dispatcher(new Container)) before bootEloquent(). This is the single most common silent bug when porting Laravel code.

Facades only half-work. Illuminate\Support\Facades\DB needs Container::setInstance() — setAsGlobal() handles this in current versions, but on older pins it may not. Prefer injecting the connection over reaching for DB::table(); it also keeps tests honest.

No pagination rendering. LengthAwarePaginator->links() needs illuminate/view and a view factory. In an API context use $paginator->items(), total(), perPage(), currentPage() and build your own envelope. Also set Paginator::currentPageResolver(...) if you read ?page=.

Mass assignment will bite you on first write. Without Laravel's defaults, Model::create($request->getParsedBody()) throws MassAssignmentException unless you declare $fillable/$guarded. Do not "fix" it with Model::unguard() globally — that is a real vulnerability in a JSON API.

Date/timezone drift. Eloquent stores UTC-naive timestamps; set date_default_timezone_set('UTC') in bootstrap and format on output. Carbon is a transitive dependency — pin it explicitly if you use it.

Attribute casting is your friend for legacy schemas. protected $casts = ['meta' => 'array', 'active' => 'boolean'] avoids hand-decoding JSON columns and keeps toArray() clean.

Debugging checklist, in order: (1) does $capsule->getConnection()->select('select 1') work? (2) is Model::getConnectionResolver() non-null? (3) is a dispatcher set? (4) does getQueryLog() show the SQL you expect? That sequence localises 95% of failures.

Extension points worth knowing. Custom connections via $capsule->getDatabaseManager()->extend('driver', fn ...); custom casts via CastsAttributes; a base Model subclass that sets $dateFormat, $connection, and a toApi() helper is a cheap way to standardise output across handlers.

Treat it as a bootstrap, not a dependency. Because the package is unmaintained-thin, isolate it: one bootstrap file, one Db wrapper, zero package-specific calls anywhere else. When it eventually breaks on a PHP upgrade, you delete one file and keep the rest of the application untouched.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle