google/cloud-firestore
Idiomatic PHP client for Google Cloud Firestore. Install via Composer and use the generated gRPC-based API to read/write documents, run queries, and manage data at scale. Part of the googleapis/google-cloud-php project.
Installation:
composer require google/cloud-firestore
Ensure the gRPC extension is installed and enabled.
Authentication: Configure credentials via environment variables (recommended) or service account JSON:
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json');
See Authentication Guide.
First Query:
use Google\Cloud\Firestore\FirestoreClient;
$firestore = new FirestoreClient();
$docRef = $firestore->collection('users')->document('user123');
$snapshot = $docRef->snapshot();
$data = $snapshot->data();
// Create
$docRef->set(['name' => 'John Doe', 'email' => 'john@example.com']);
// Read
$doc = $docRef->snapshot()->data();
// Update
$docRef->update(['email' => 'new@example.com']);
// Delete
$docRef->delete();
Key Starting Points:
Wrap Firestore operations in a Laravel repository to abstract away Firestore-specific logic:
class FirestoreUserRepository
{
protected $firestore;
public function __construct(FirestoreClient $firestore)
{
$this->firestore = $firestore;
}
public function findById(string $id)
{
return $this->firestore->collection('users')
->document($id)
->snapshot()
->data();
}
}
Register in AppServiceProvider:
$this->app->singleton(FirestoreUserRepository::class, function ($app) {
return new FirestoreUserRepository(new FirestoreClient());
});
Leverage Firestore’s real-time capabilities for live UI updates:
use Google\Cloud\Firestore\DocumentSnapshot;
$collection = $firestore->collection('chat_messages');
$listener = $collection->listen(function (DocumentSnapshot $snapshot) {
// Handle real-time updates (e.g., broadcast via Laravel Echo)
broadcast(new MessageUpdated($snapshot->data()));
});
Cleanup:
$listener->cancel();
Use transactions for multi-document updates:
$firestore->runTransaction(function ($transaction) {
$docRef = $firestore->collection('users')->document('user123');
$snapshot = $docRef->snapshot();
$data = $snapshot->data();
$data['balance'] -= 100;
$transaction->update($docRef, $data);
// Update another document
$otherDoc = $firestore->collection('orders')->document('order456');
$transaction->update($otherDoc, ['status' => 'paid']);
});
For batch writes (e.g., imports):
$batch = $firestore->batch();
$batch->create($firestore->collection('users')->document(), ['name' => 'Alice']);
$batch->create($firestore->collection('users')->document(), ['name' => 'Bob']);
$batch->commit();
$collection = $firestore->collection('products');
$query = $collection->where('price', '>', 100)
->where('category', '==', 'electronics')
->orderBy('name')
->limit(10);
foreach ($query->documents() as $doc) {
// Process results
}
Use Firestore’s offline persistence for PWAs or mobile apps:
$firestore->enablePersistence();
Define Firestore security rules in firestore.rules and validate in Laravel:
// Example: Check if user can access a document
$docRef = $firestore->collection('users')->document($userId);
$snapshot = $docRef->snapshot();
if (!$snapshot->exists() || $snapshot->data()['owner'] !== auth()->id()) {
abort(403);
}
Use Firestore triggers (Cloud Functions) for serverless workflows and listen in Laravel via:
$lastDoc = null;
do {
$query = $firestore->collection('posts');
if ($lastDoc) {
$query->startAfter($lastDoc);
}
$query->limit(10);
$docs = $query->documents();
foreach ($docs as $doc) {
// Process
$lastDoc = $doc;
}
} while ($docs->count() > 0);
Use FirestoreTestCase or mock the client:
use Google\Cloud\Firestore\FirestoreClient;
use Google\Cloud\Firestore\Testing\FirestoreTestCase;
class UserRepositoryTest extends FirestoreTestCase
{
public function testFindById()
{
$firestore = $this->createFirestoreClient();
$firestore->collection('users')->document('test')->set(['name' => 'Test']);
$this->assertEquals('Test', $firestore->collection('users')->document('test')->snapshot()->data()['name']);
}
}
keyFile: Use GOOGLE_APPLICATION_CREDENTIALS env var or ApplicationDefaultCredentials instead.
// ❌ Deprecated
$firestore = new FirestoreClient(['keyFile' => 'path/to/key.json']);
// ✅ Recommended
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json');
$firestore = new FirestoreClient();
roles/datastore.user or higher.IN, array-contains) require composite indexes. Use the Index Manager to check coverage.user_name in posts) to avoid GET loops.FirestoreTimestamp for server-side time:
use Google\Cloud\Firestore\FirestoreTimestamp;
$docRef->set(['created_at' => FirestoreTimestamp::now()]);
destroy() or beforeDestroy():
public function destroy()
{
$this->listener->cancel();
parent::destroy();
}
$attempts = 0;
while ($attempts < 3) {
try {
$firestore->runTransaction($transaction);
break;
} catch (Exception $e) {
$attempts++;
sleep(2 ** $attempts); // Exponential backoff
}
}
$firestore = new FirestoreClient([
'logger' => new \Monolog\Logger('firestore', [
new \Monolog\Handler\StreamHandler('php://stderr', \Monolog\Logger::DEBUG),
]),
]);
x-goog-request-params for debugging (e.g., curl -v).$this->app->
How can I help you explore Laravel packages today?