google/cloud-firestore
Idiomatic PHP client for Google Cloud Firestore. Install via Composer, authenticate with Google Cloud credentials, and use the generated FirestoreClient (gRPC required) to read/write documents and collections with robust error handling and API docs support.
Installation:
composer require google/cloud-firestore
Ensure the grpc PHP extension is enabled (see gRPC guide).
Authentication: Configure credentials via environment variables (recommended) or service account JSON:
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json');
Or use the credentials option in the client constructor:
$firestore = new FirestoreClient(['credentials' => $serviceAccount]);
First Query:
use Google\Cloud\Firestore\FirestoreClient;
$firestore = new FirestoreClient();
$document = $firestore->document('projects/{PROJECT_ID}/databases/(default)/docs/users/123');
$snapshot = $document->snapshot();
$data = $snapshot->data();
// Create
$document->create(['name' => 'John', 'age' => 30]);
// Read
$snapshot = $document->snapshot();
$data = $snapshot->exists() ? $snapshot->data() : null;
// Update
$document->update(['age' => 31]);
// Delete
$document->delete();
Key Files to Reference:
Wrap Firestore operations in a Laravel repository to abstract away Firestore-specific logic:
class UserRepository
{
protected $firestore;
public function __construct(FirestoreClient $firestore)
{
$this->firestore = $firestore;
}
public function findById(string $id): ?array
{
$doc = $this->firestore->document("users/{$id}");
$snapshot = $doc->snapshot();
return $snapshot->exists() ? $snapshot->data() : null;
}
public function create(array $data): string
{
$doc = $this->firestore->collection('users')->document();
$doc->set($data);
return $doc->id();
}
}
Use Firestore’s listeners for live updates (e.g., chat messages, notifications):
use Google\Cloud\Firestore\DocumentSnapshot;
$collection = $firestore->collection('messages');
$listener = $collection->listen(function (DocumentSnapshot $snapshot) {
if ($snapshot->exists()) {
$data = $snapshot->data();
// Broadcast or process update (e.g., via Laravel Echo)
}
});
// Unsubscribe later: $listener->cancel();
Handle concurrent writes with transactions:
$firestore->runTransaction(function ($transaction) {
$doc = $firestore->document('users/123');
$snapshot = $transaction->get($doc);
$data = $snapshot->data();
$data['balance'] -= 100;
$transaction->set($doc, $data);
});
Optimize performance with batch writes:
$batch = $firestore->batch();
$batch->set($firestore->document('users/1'), ['name' => 'Alice']);
$batch->set($firestore->document('users/2'), ['name' => 'Bob']);
$batch->commit();
Use composite queries for complex filtering:
$query = $firestore->collection('products')
->where('category', '==', 'electronics')
->where('price', '>', 100)
->orderBy('price')
->limit(10);
$snapshot = $query->documents();
Enable offline persistence for mobile/web apps (requires client-side setup):
$firestore->setSettings([
'isPersistenceEnabled' => true,
'cacheSizeBytes' => FirestoreClient::CACHE_SIZE_UNLIMITED,
]);
Register Firestore as a Laravel singleton:
// app/Providers/FirestoreServiceProvider.php
public function register()
{
$this->app->singleton(FirestoreClient::class, function ($app) {
return new FirestoreClient([
'projectId' => config('services.firestore.project_id'),
]);
});
}
keyFile/keyFilePath: Use credentials option or environment variables instead (see #8617).roles/datastore.user).GOOGLE_APPLICATION_CREDENTIALS for simplicity:
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/key.json"
batch() for >1 write to reduce latency.limit() + startAfter() for large datasets:
$lastDoc = $query->limit(10)->documents()[0];
$nextQuery = $query->limit(10)->startAfter($lastDoc);
$logger = new Monolog\Logger('firestore');
$firestore = new FirestoreClient(['logger' => $logger]);
google/rpc/code 5 or 14):
try {
$snapshot = $document->snapshot();
} catch (ApiException $e) {
if ($e->getStatusCode() === 5 || $e->getStatusCode() === 14) {
// Retry with exponential backoff
}
}
$firestore->setSettings(['defaultDeadline' => 120]); // 2 minutes
users/{uid}/orders).$cacheKey = "firestore:products:electronics";
return cache()->remember($cacheKey, now()->addMinutes(5), function () {
return $query->documents();
});
$listener->listen(function (DocumentSnapshot $snapshot) {
event(new UserUpdated($snapshot->id(), $snapshot->data()));
});
$index = $firestore->index('projects/{PROJECT_ID}/locations/{LOCATION}/databases/(default)/indexes/vector_index');
$backup = $firestore->backup('projects/{PROJECT_ID}/databases/(default)');
$backup->create(['location' => 'us-central1']);
| Error | Cause | Solution |
|---|---|---|
INVALID_ARGUMENT: No document |
Document path malformed | Use projects/{PROJECT_ID}/databases/(default)/docs/{COLLECTION}/{ID} |
PERMISSION_DENIED |
Missing IAM permissions | Grant roles/datastore.user to service account |
UNAVAILABLE |
gRPC connection issues | Check grpc extension and network policies |
How can I help you explore Laravel packages today?