Skip to content

Commit 3d14230

Browse files
committed
Enable using a custom Firestore database on instance creation
1 parent 11659d7 commit 3d14230

File tree

8 files changed

+159
-87
lines changed

8 files changed

+159
-87
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ Please read about the future of the Firebase Admin PHP SDK on the
77

88
## [Unreleased]
99

10+
### Added
11+
12+
* You can now save on method call by passing a custom Firestore database name to
13+
`Kreait\Firebase\Factory::createFirestore($databaseName)` instead of having to chain
14+
``::withFirestoreDatabase($databaseName)->createFirestore()``
15+
16+
### Deprecated
17+
18+
* `Kreait\Firebase\Factory::withFirestoreDatabase()`
19+
1020
## [7.18.0] - 2025-03-08
1121

1222
### Added

docs/cloud-firestore.rst

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,18 @@ Use another Firestore Database
7272

7373
If you don't specify a database, the Firestore Client will connect to the ``(default)`` database.
7474

75-
If you want to connect to another database, you can specify its name with the factory. You can work with multiple
76-
Firestore Databases simultaneously.
75+
If you want to connect to another database, you can specify its name when creating a new instance. This enables you
76+
to work with multiple Firestore Databases simultaneously.
7777

7878
.. code-block:: php
7979
8080
use Kreait\Firebase\Factory;
8181
8282
$factory = new Factory();
8383
84-
$defaultDatabase = $factory
85-
->createFirestore()
86-
->database();
87-
88-
$otherDatabase = $factory
89-
->withFirestoreDatabase('another-database')
90-
->createFirestore()
91-
->database();
92-
93-
$thirdDatabase = $factory
94-
->withFirestoreDatabase('third-database')
95-
->createFirestore()
96-
->database();
84+
$default = $factory->createFirestore();
85+
$explicitDefault = $factory->createFirestore('(default)');
86+
$custom = $factory->createFirestore('custom');
9787
9888
***********************************
9989
Add Firestore configuration options
@@ -113,15 +103,3 @@ You can add additional configuration options for the Firestore Client used by th
113103
114104
You can find all configuration options in the source code of the ``FirestoreClient`` class of the
115105
`official Google Firestore PHP library <https://github.com/googleapis/google-cloud-php-firestore/blob/4186f2a2f2a8bdaedf19376a35ccb0ffad17f4e1/src/FirestoreClient.php#L138>`_.
116-
117-
In fact, the ``withFirestoreDatabase()`` method is a shortcut for the ``withFirestoreClientConfig()`` method:
118-
119-
.. code-block:: php
120-
121-
use Kreait\Firebase\Factory;
122-
123-
$factory = new Factory();
124-
125-
$firestore = $factory->->withFirestoreDatabase('another-database');
126-
// is a shortcut for
127-
$firestore = $factory->withFirestoreClientConfig(['database' => 'another-database']);

src/Firebase/Factory.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Google\Auth\Middleware\AuthTokenMiddleware;
1818
use Google\Auth\ProjectIdProviderInterface;
1919
use Google\Auth\SignBlobInterface;
20-
use Google\Cloud\Firestore\FirestoreClient;
2120
use Google\Cloud\Storage\StorageClient;
2221
use GuzzleHttp\Client;
2322
use GuzzleHttp\HandlerStack;
@@ -229,6 +228,9 @@ public function withDatabaseAuthVariableOverride(?array $override): self
229228
}
230229

231230
/**
231+
* @deprecated 7.19.0 Use `createFirestore($database)` instead
232+
* @see createFirestore()
233+
*
232234
* @param non-empty-string $database
233235
*/
234236
public function withFirestoreDatabase(string $database): self
@@ -464,17 +466,18 @@ public function createDynamicLinksService($defaultDynamicLinksDomain = null): Co
464466
return DynamicLinks::withApiClient($apiClient);
465467
}
466468

467-
public function createFirestore(): Contract\Firestore
469+
/**
470+
* @param non-empty-string|null $databaseName
471+
*/
472+
public function createFirestore(?string $databaseName = null): Contract\Firestore
468473
{
469474
$config = $this->googleCloudClientConfig() + $this->firestoreClientConfig;
470475

471-
try {
472-
$firestoreClient = new FirestoreClient($config);
473-
} catch (Throwable $e) {
474-
throw new RuntimeException('Unable to create a FirestoreClient: '.$e->getMessage(), $e->getCode(), $e);
476+
if ($databaseName !== null) {
477+
$config['database'] = $databaseName;
475478
}
476479

477-
return Firestore::withFirestoreClient($firestoreClient);
480+
return Firestore::fromConfig($config);
478481
}
479482

480483
public function createStorage(): Contract\Storage

src/Firebase/Firestore.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace Kreait\Firebase;
66

77
use Google\Cloud\Firestore\FirestoreClient;
8+
use Kreait\Firebase\Exception\RuntimeException;
9+
use Throwable;
810

911
/**
1012
* @internal
@@ -15,9 +17,16 @@ private function __construct(private readonly FirestoreClient $client)
1517
{
1618
}
1719

18-
public static function withFirestoreClient(FirestoreClient $firestoreClient): self
20+
/**
21+
* @param array<non-empty-string, mixed> $config
22+
*/
23+
public static function fromConfig(array $config): Contract\Firestore
1924
{
20-
return new self($firestoreClient);
25+
try {
26+
return new self(new FirestoreClient($config));
27+
} catch (Throwable $e) {
28+
throw new RuntimeException('Unable to create a FirestoreClient: '.$e->getMessage(), $e->getCode(), $e);
29+
}
2130
}
2231

2332
public function database(): FirestoreClient

tests/.env.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
GOOGLE_APPLICATION_CREDENTIALS=
22
FIREBASE_TENANT_ID=
33
TEST_FIREBASE_APP_ID=
4+
# You can find the URI of your Realtime Database at https://console.firebase.google.com/u/0/project/_/database
45
TEST_FIREBASE_RTDB_URI=
56
TEST_FIREBASE_TENANT_ID=
67
TEST_REGISTRATION_TOKENS=
8+
# Add a custom Firestore Database at https://console.firebase.google.com/u/0/project/_/firestore/ first
9+
TEST_FIRESTORE_CUSTOM_DB_NAME=
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kreait\Firebase\Tests\Integration\Factory;
6+
7+
use Google\Cloud\Core\Exception\NotFoundException;
8+
use Kreait\Firebase\Tests\IntegrationTestCase;
9+
use Kreait\Firebase\Util;
10+
use PHPUnit\Framework\Attributes\Test;
11+
12+
/**
13+
* @internal
14+
*/
15+
final class FirestoreTest extends IntegrationTestCase
16+
{
17+
/**
18+
* If we write a document into the instance created without an explicit database name,
19+
* we should be able to read it from the instance created with an explicit database name.
20+
*/
21+
#[Test]
22+
public function itUsesTheDefaultDatabaseByDefault(): void
23+
{
24+
$collection = __FUNCTION__;
25+
$documentName = __FUNCTION__.self::randomString();
26+
27+
$default = self::$factory->createFirestore()->database()->collection($collection);
28+
$explicit = self::$factory->createFirestore('(default)')->database()->collection($collection);
29+
30+
try {
31+
$default->document($documentName)->create(['field' => 'value']);
32+
33+
$this->assertTrue($explicit->document($documentName)->snapshot()->exists());
34+
$this->assertSame(['field' => 'value'], $explicit->document($documentName)->snapshot()->data());
35+
} finally {
36+
$default->document($documentName)->delete();
37+
}
38+
}
39+
40+
#[Test]
41+
public function testItCannotConnectToAnUnknownDatabase(): void
42+
{
43+
$name = self::randomString();
44+
45+
$database = self::$factory->createFirestore($name)->database();
46+
47+
$this->expectException(NotFoundException::class);
48+
// No need to deserialize the returned JSON
49+
$this->expectExceptionMessageMatches("/$name/");
50+
51+
$database->collection('foo')->document(__FUNCTION__)->create();
52+
}
53+
54+
#[Test]
55+
public function itCanConnectToACustomDatabase(): void
56+
{
57+
$collection = __FUNCTION__;
58+
$documentName = __FUNCTION__.self::randomString();
59+
60+
$database = self::$factory->createFirestore($this->customDBName())->database();
61+
62+
try {
63+
$database->collection($collection)->document($documentName)->create();
64+
$this->assertTrue($database->collection($collection)->document($documentName)->snapshot()->exists());
65+
} finally {
66+
$database->collection($collection)->document($documentName)->delete();
67+
}
68+
}
69+
70+
/**
71+
* @deprecated 7.19.0
72+
*/
73+
#[Test]
74+
public function itSupportsOverridingTheDefaultFirestoreDatabase(): void
75+
{
76+
$collection = __FUNCTION__;
77+
$documentName = __FUNCTION__.self::randomString();
78+
79+
$database = self::$factory->withFirestoreDatabase($this->customDBName())->createFirestore()->database();
80+
81+
try {
82+
$database->collection($collection)->document($documentName)->create();
83+
$this->assertTrue($database->collection($collection)->document($documentName)->snapshot()->exists());
84+
} finally {
85+
$database->collection($collection)->document($documentName)->delete();
86+
}
87+
}
88+
89+
#[Test]
90+
public function itSupportsAdditionalFirestoreConfig(): void
91+
{
92+
$collection = __FUNCTION__;
93+
$documentName = __FUNCTION__.self::randomString();
94+
95+
$database = self::$factory
96+
->withFirestoreClientConfig(['database' => $this->customDBName()])
97+
->createFirestore()->database();
98+
99+
try {
100+
$database->collection($collection)->document($documentName)->create();
101+
$this->assertTrue($database->collection($collection)->document($documentName)->snapshot()->exists());
102+
} finally {
103+
$database->collection($collection)->document($documentName)->delete();
104+
}
105+
}
106+
107+
/**
108+
* @return non-empty-string
109+
*/
110+
private function customDBName(): string
111+
{
112+
$customDBName = Util::getenv('TEST_FIRESTORE_CUSTOM_DB_NAME');
113+
114+
if ($customDBName == null) {
115+
$this->markTestSkipped('No custom Firestore DB name set via the environment variable `TEST_FIRESTORE_CUSTOM_DB_NAME`');
116+
}
117+
118+
return $customDBName;
119+
}
120+
}

tests/Integration/FactoryTest.php

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -76,30 +76,4 @@ public function itSupportsAddingAdditionalHttpClientMiddlewares(): void
7676

7777
$this->assertTrue($check);
7878
}
79-
80-
#[Test]
81-
public function itSupportsOverridingTheDefaultFirestoreDatabase(): void
82-
{
83-
$firestore = self::$factory
84-
->withFirestoreDatabase(__FUNCTION__)
85-
->createFirestore();
86-
87-
$db = $firestore->database();
88-
$name = $db->collection('irrelevant')->name();
89-
90-
$this->assertStringContainsString(__FUNCTION__, $name);
91-
}
92-
93-
#[Test]
94-
public function itSupportsAdditionalFirestoreConfig(): void
95-
{
96-
$firestore = self::$factory
97-
->withFirestoreClientConfig(['database' => __FUNCTION__])
98-
->createFirestore();
99-
100-
$db = $firestore->database();
101-
$name = $db->collection('irrelevant')->name();
102-
103-
$this->assertStringContainsString(__FUNCTION__, $name);
104-
}
10579
}

tests/Unit/FirestoreTest.php

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)