roddy / firestore-eloquent
Firestore Eloquent, an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using Eloquent, each firestore collection has a corresponding \"Model\"/\"Class\" that is used to interact with that collection. In addition to retrieving records from the firestore col
Fund package maintenance!
Requires
- php: >= 8.1
- google/auth: ^1.37
- google/cloud-storage: 1.*
- illuminate/config: 9.* || 10.* || 11.* || 12.* || 13.*
- illuminate/contracts: 9.* || 10.* || 11.* || 12.* || 13.*
- illuminate/filesystem: 9.* || 10.* || 11.* || 12.* || 13.*
- illuminate/http: 9.* || 10.* || 11.* || 12.* || 13.*
- illuminate/pagination: 9.* || 10.* || 11.* || 12.* || 13.*
- illuminate/session: 9.* || 10.* || 11.* || 12.* || 13.*
- illuminate/support: 9.* || 10.* || 11.* || 12.* || 13.*
- nesbot/carbon: 2.* || 3.*
Requires (Dev)
- illuminate/container: 9.* || 10.* || 11.* || 12.* || 13.*
- phpunit/phpunit: ^10.5 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v4.0
- v3.0.17
- v3.0.16
- v3.0.15
- v3.0.14
- v3.0.13
- v3.0.12
- v3.0.11
- v3.0.10
- v3.0.9
- v3.0.8
- v3.0.7
- v3.0.6
- v3.0.5
- v3.0.4
- v3.0.3
- v3.0.2
- v3.0.1
- v3.0.0
- v2.1.1
- v2.1.0
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.1.31
- v1.1.4
- v1.1.3
- v1.1.2
- 1.1.1
- v1.1.0
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.11
- dev-Freddywhest-patch-1
- dev-version-1.x
- dev-develop
This package is auto-updated.
Last update: 2026-10-28 16:42:45 UTC
README
Laravel Firestore Eloquent
This package is a customized version of Laravel Eloquent designed for seamless integration with Google Firestore within Laravel applications. Firestore boasts exceptional scalability and speed, but it provides a more limited feature set compared to conventional SQL databases.
Table of Contents
Requirements
- PHP >= 8.1
- Laravel >= 9 (Recommeded Latest Laravel)
- Composer
Installation
-
Install this package using composer
composer require roddy/firestore-eloquent
-
Configure the project and server credentials. Firestore requests are authenticated by default.
FIREBASE_PROJECT_ID=your-project-id FIREBASE_CREDENTIALS=/absolute/path/to/service-account.json GOOGLE_CLOUD_STORAGE_BUCKET=your-project.appspot.com
Application Default Credentials are also supported when
FIREBASE_CREDENTIALSis omitted. Only projects that intentionally use public Firestore rules should setFIREBASE_ALLOW_UNAUTHENTICATED=true. -
Publish the package configuration using Artisan
php artisan vendor:publish --provider="Roddy\FirestoreEloquent\Providers\FModelProvider" --forceYou can locate the configuration file in
config/firebase.php.
Documentation
Visit Laravel Firestore Eloquent for documentation.
OR
Use this link https://firestore-eloquent.netlify.app/
FS query builder
Use the FS facade when you want Laravel DB::table()-style access without creating an FModel:
use Roddy\FirestoreEloquent\Facade\FS; $rides = FS::collection('rides') ->where('status', '=', 'completed') ->orderByDesc('created_at') ->cursorPaginate(20); // table() is an alias for collection(). $ride = FS::table('rides')->find('ride-123');
The builder supports retrieval, filters, ordering, selection, pagination, aggregates, exists(), value(), pluck(), inserts, batch-backed query updates, and batch-backed query deletes.
$id = FS::collection('rides')->insertGetId([ 'status' => 'pending', 'driver_id' => 'driver-123', ]); FS::collection('rides') ->where('status', 'pending') ->update(['status' => 'expired']);
Unlike model writes, raw FS writes do not apply $fillable, $required, $default, $hidden, or $fieldTypes. Validate and authorize raw data before writing it.
Transactions
Use FS::transaction() when writes depend on values read from Firestore:
use Roddy\FirestoreEloquent\Firestore\FirestoreTransaction; use RuntimeException; $newBalance = FS::transaction(function (FirestoreTransaction $transaction) { $account = $transaction->collection('accounts')->findOrFail('account-1'); $newBalance = $account->balance - 50; if ($newBalance < 0) { throw new RuntimeException('Insufficient balance.'); } $transaction->update('accounts', 'account-1', [ 'balance' => $newBalance, ]); $transaction->create('ledger_entries', [ 'account_id' => 'account-1', 'amount' => -50, ]); return $newBalance; });
All transaction reads must run before any write is queued. The callback is rolled back on exceptions and automatically retried when Firestore reports ABORTED contention, so it may execute more than once. Keep external side effects out of the callback.
Manual Laravel-style control is also available. Model reads and writes created after beginTransaction() automatically join the active transaction:
try { FS::beginTransaction(); $ride = Ride::findOrFail('ride-1'); $ride->update(['status' => 'completed']); FS::commit(); } catch (\Throwable $exception) { FS::rollback(); throw $exception; }
Manual transactions do not automatically replay the surrounding code after contention. Prefer FS::transaction() when automatic retries are required.
Fast pagination
The pagination methods now use Laravel's native paginator classes, so links(), named paginator state, JSON resources, and Livewire pagination work the same way as Laravel's query builder.
Use cursor pagination for large collections. Unlike page-number pagination, it does not scan documents from earlier pages and it does not execute a count query.
$page = Post::orderBy('created_at', 'desc')->cursorPaginate(20); $items = $page->items(); $nextCursor = $page->nextCursor()?->encode(); $previousCursor = $page->previousCursor()?->encode(); // Blade and Livewire can render the native paginator directly. echo $page->links();
Use simplePaginate() when page numbers are required but the total count is not. Use paginate() only when an exact total is required; Firestore offsets become progressively slower on deep pages.
For large background jobs, lazy() and chunk() use cursor pagination internally and keep memory usage bounded:
Post::orderBy('created_at')->chunk(200, function ($posts) { foreach ($posts as $post) { // Process one bounded page. } });
Bulk updates use Firestore commits, reducing hundreds of HTTP requests to one request per 500 documents:
Post::updateMany([ ['id' => 'post-1', 'status' => 'published'], ['id' => 'post-2', 'status' => 'published'], ]);
Every group of at most 500 updates is atomic. Documents must include the model's primary key, and updated fields must be fillable.
Avoid relationship N+1 queries
Load relationships in batches with with(). Firestore IN limits are handled automatically by chunking parent keys into groups.
$posts = Post::with(['comments', 'author']) ->orderBy('created_at', 'desc') ->get(); $posts = Post::with([ 'comments.author', 'comments' => fn ($query) => $query->orderBy('created_at', 'desc'), ])->get();
Without with(), accessing a relationship property still performs a lazy query for that individual model.
Laravel authentication
Register the Firestore user provider in the application's config/auth.php:
'providers' => [ 'users' => [ 'driver' => 'firestore', 'model' => App\FModels\User::class, ], ],
The normal session guard can then use Firestore through Laravel's standard API:
Auth::attempt(['email' => $email, 'password' => $password], remember: true); Auth::user(); Auth::id(); Auth::check(); Auth::loginUsingId($id); Auth::logout();
The model should include password in its fillable fields if automatic password rehashing is desired. The remember token is persisted separately and does not need to be fillable. The older FAuth helper remains available for backward compatibility.
Limitations
Limitations for documentation.
TODO
Todo for documentation.
License
The MIT License (MIT). Please see License File for more information.
Acknowledgments
Contributors
Code Contributors
This project exists thanks to all the people who contribute. [Contribute].
Financial Contributors
Become a financial contributor and help us sustain our community.
