likesistemas/eloquent-external
Eloquent External bridges Laravel's Eloquent ORM with external data sources, letting you define models and relationships against remote APIs or legacy databases using familiar query syntax. It handles the integration layer so external records behave like local Eloquent models.
likesistemas/eloquent-external extends Eloquent so a model can read/write against an external data source instead of (or alongside) your app's default connection. It's a small, single-maintainer package — the practical path is: install, read the source, then build one model against one external source before committing to it broadly.
composer require likesistemas/eloquent-external
Where to look first, in order:
src/ — the service provider and the model base class/trait are the whole contract. Read them end-to-end (usually a few hundred lines). You need to know exactly which Eloquent methods are intercepted and which fall through to the normal query builder.php artisan vendor:publish --provider="Likesistemas\...\ServiceProvider" and inspect the resulting file for connection/credential keys.First use case to validate against: a read-only reporting model pointed at an external database or endpoint. Define one model, run a where() + get(), then run a create() to confirm whether writes are supported. That single experiment tells you more than the docs about whether the package fits your workload.
If you use barryvdh/laravel-ide-helper, install >=2.1.1 — see Gotchas, this release exists specifically to unblock that workflow.
Wrap the package behind your own layer. Because the package owns the model's persistence behaviour, don't let it leak into your domain code. Give each external source a repository/interface implemented by the package model, so swapping to a hand-rolled HTTP client or a second DB connection later is a one-file change:
interface ProductRepository { public function find(int $id): ?ProductData; }
class ExternalProductRepository implements ProductRepository { /* uses the package model */ }
One model class per external source. Connection/endpoint details usually live on the model or its parent. Do not try to multiplex a single model across tenants or environments — subclass or use distinct model classes, and bind the concrete class in a service provider per environment.
Keep credentials in config/. Never on the model. Reference config('services.external.…') / env() only inside config files, and remember php artisan config:cache in deploy — stale config after an env change is a classic first-day bug here.
Test around the boundary, not through it. In tests, either bind a fake implementation of your repository interface, or point the package at a local SQLite/HTTP fake. Asserting on the package's own internals is brittle; assert on your repository's contract.
Use it in queued jobs, not in request paths, for bulk work. External sources are slower and less predictable than a local connection. Sync jobs with ShouldQueue, retries and backoff() are the natural home for large imports/exports, and they isolate timeouts from user-facing requests.
Regenerate IDE metadata in CI or on a pre-commit hook. With >=2.1.1 you can run php artisan ide-helper:models --write against your external models and commit the generated docblocks (or generate into a _ide_helper_models.php you exclude from git and build at bootstrap). Treat it like a build artefact.
php artisan ide-helper:models errored out when the package's models were scanned. If you already run laravel-ide-helper, pin likesistemas/eloquent-external:^2.1.1 — otherwise your model-generation step (and anything gated on it, like static analysis baselines) breaks. If you don't use ide-helper, this release is a no-op for you: no API changes, no breaking changes, safe to take on a patch bump._ide_helper_models.php and re-run ide-helper:models --write, otherwise you'll keep the incomplete/stale docblocks that the bug produced.@property block written by hand or a PHPStan stub.DB::listen() when the external source is a SQL connection; for HTTP-backed sources, log the outgoing request and response body. Set Model::preventLazyLoading() and preventAccessingMissingAttributes() in non-production to surface N+1s and silent nulls early — external round-trips make both much more expensive.whereHas, withCount, chunking and upsert may or may not be implemented; verify each one you rely on rather than assuming Eloquent parity. Builder methods that fall through to the base query builder are where the surprising failures live.newEloquentBuilder() / newQuery() and (if present) the package's connection resolver. Overriding the builder is the cleanest place to add caching, logging, or retry logic without forking.How can I help you explore Laravel packages today?