Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 78aad07

Browse files
committed
v2.0.0 released. See CHANGELOG for updates.
1 parent 2dba695 commit 78aad07

29 files changed

+1480
-411
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
All notable changes to `Firestore PHP` will be documented in this file.
44

5+
## 2.0.0 - 2019-02-XX
6+
- Added Firebase Authentication
7+
- All files prefixed changed from `FireStore` to `Firestore`
8+
- Added `Bytes` support.
9+
- Exception handling support added.
10+
- Support added to list all documents, batch listing with query parameter.
11+
- Pagination support for bulk and document listing.
12+
- Improved naming convention throughout the package.
13+
- Many more..
14+
515
## 1.0.1 - 2019-01-16
616
- Add method for casting floating point values
717
- Document ID flipped on `getDocument` method

README.md

+86-26
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,21 @@ You can install the package via composer:
2020
composer require ahsankhatri/firestore-php
2121
```
2222

23+
or install it by adding it to `composer.json` then run `composer update`
24+
25+
```javascript
26+
"require": {
27+
"ahsankhatri/ahsankhatri/firestore-php": "^2.0",
28+
}
29+
```
30+
2331
## Dependencies
2432

2533
The bindings require the following extensions in order to work properly:
2634

2735
- [`curl`](https://secure.php.net/manual/en/book.curl.php)
2836
- [`json`](https://secure.php.net/manual/en/book.json.php)
37+
- [`guzzlehttp/guzzle`](https://packagist.org/packages/guzzlehttp/guzzle)
2938

3039
If you use Composer, these dependencies should be handled automatically. If you install manually, you'll want to make sure that these extensions are available.
3140

@@ -34,7 +43,7 @@ If you use Composer, these dependencies should be handled automatically. If you
3443
#### Initialization
3544

3645
```php
37-
$firestoreClient = new FireStoreApiClient('project-id', 'AIzaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [
46+
$firestoreClient = new FirestoreApiClient('project-id', 'AIzaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [
3847
'database' => '(default)',
3948
]);
4049
```
@@ -51,32 +60,35 @@ $firestoreClient->addDocument($collection, [
5160
'arrayRaw' => [
5261
'string' => 'abc123',
5362
],
54-
'array' => new FireStoreArray([
63+
'bytes' => new FirestoreBytes('bytesdata'),
64+
'array' => new FirestoreArray([
5565
'string' => 'abc123',
5666
]),
57-
'reference' => new FireStoreReference('/users/23'),
58-
'object' => new FireStoreObject(['nested1' => new FireStoreObject(['nested2' => new FireStoreObject(['nested3' => 'test'])])]),
59-
'timestamp' => new FireStoreTimestamp,
60-
'geopoint' => new FireStoreGeoPoint(1,1),
67+
'reference' => new FirestoreReference('/users/23'),
68+
'object' => new FirestoreObject(['nested1' => new FirestoreObject(['nested2' => new FirestoreObject(['nested3' => 'test'])])]),
69+
'timestamp' => new FirestoreTimestamp,
70+
'geopoint' => new FirestoreGeoPoint(1,1),
6171
]);
6272
```
6373

64-
**NOTE:** Pass third argument if you want your custom _document id_ to set else auto-id will generate it for you.
74+
**NOTE:** Pass third argument if you want your custom **document id** to set else auto-id will generate it for you.
6575

6676
Or
6777

6878
```php
69-
$document = new FireStoreDocument;
70-
$document->setObject('sdf', new FireStoreObject(['nested1' => new FireStoreObject(['nested2' => new FireStoreObject(['nested3' => 'test'])])]));
79+
$document = new FirestoreDocument;
80+
$document->setObject('sdf', new FirestoreObject(['nested1' => new FirestoreObject(['nested2' => new FirestoreObject(['nested3' => 'test'])])]));
7181
$document->setBoolean('booleanTrue', true);
7282
$document->setBoolean('booleanFalse', false);
7383
$document->setNull('null', null);
7484
$document->setString('string', 'abc123');
7585
$document->setInteger('integer', 123456);
7686
$document->setArray('arrayRaw', ['string'=>'abc123']);
77-
$document->setArray('arrayObject', new FireStoreArray(['string' => 'abc123']));
78-
$document->setTimestamp('timestamp', new FireStoreTimestamp);
79-
$document->setGeoPoint('geopoint', new FireStoreGeoPoint(1.11,1.11));
87+
$document->setBytes('bytes', 'bytesdata');
88+
$document->setArray('arrayObject', new FirestoreArray(['string' => 'abc123']));
89+
$document->setTimestamp('timestamp', new FirestoreTimestamp);
90+
$document->setGeoPoint('geopoint', new FirestoreGeoPoint(1.11,1.11));
91+
8092
$firestoreClient->addDocument($collection, $document, 'customDocumentId');
8193
```
8294

@@ -89,25 +101,36 @@ $document->fillValues([
89101
]);
90102
```
91103

92-
#### Updating a document
104+
#### Inserting/Updating a document
93105

94-
- Update existing document
106+
- Update (Merge) or Insert document
107+
108+
Following will merge document (if exist) else insert the data.
95109

96110
```php
97-
$firestoreClient->updateDocument($collection, $documentId, [
98-
'newFieldToAdd' => new FireStoreTimestamp(new DateTime('2018-04-20 15:00:00')),
99-
'existingFieldToRemove' => new FireStoreDeleteAttribute
100-
], true);
111+
$firestoreClient->updateDocument($documentRoot, [
112+
'newFieldToAdd' => new FirestoreTimestamp(new DateTime('2018-04-20 15:00:00')),
113+
'existingFieldToRemove' => new FirestoreDeleteAttribute
114+
]);
101115
```
102116

103-
**NOTE:** Passing 3rd argument as a boolean _true_ will indicate that document must exist and vice-versa.
117+
**NOTE:** Passing 3rd argument as a boolean _true_ will force check that document must exist and vice-versa in order to perform update operation.
118+
119+
For example: If you want to update document only if exist else `MrShan0\PHPFirestore\Exceptions\Client\NotFound` (Exception) will be thrown.
104120

105-
- Overwrite existing document
121+
```php
122+
$firestoreClient->updateDocument($documentPath, [
123+
'newFieldToAdd' => new FirestoreTimestamp(new DateTime('2018-04-20 15:00:00')),
124+
'existingFieldToRemove' => new FirestoreDeleteAttribute
125+
], true);
126+
```
127+
128+
- Overwirte or Insert document
106129

107130
```php
108131
$firestoreClient->setDocument($collection, $documentId, [
109-
'newFieldToAdd' => new FireStoreTimestamp(new DateTime('2018-04-20 15:00:00')),
110-
'existingFieldToRemove' => new FireStoreDeleteAttribute
132+
'newFieldToAdd' => new FirestoreTimestamp(new DateTime('2018-04-20 15:00:00')),
133+
'existingFieldToRemove' => new FirestoreDeleteAttribute
111134
], [
112135
'exists' => true, // Indicate document must exist
113136
]);
@@ -120,12 +143,49 @@ $collection = 'collection/document/innerCollection';
120143
$firestoreClient->deleteDocument($collection, $documentId);
121144
```
122145

146+
#### List documents with pagination (or custom parameters)
147+
148+
```php
149+
$collections = $firestoreClient->listDocuments('users', [
150+
'pageSize' => 1,
151+
'pageToken' => 'nextpagetoken'
152+
]);
153+
```
154+
155+
**Note:** You can pass custom parameters as supported by [firestore list document](https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents/list#query-parameters)
156+
157+
### Firebase Authentication
158+
159+
#### Sign in with Email and Password.
160+
161+
```php
162+
$firestoreClient
163+
->authenticator()
164+
->signInEmailPassword('testuser@example.com', 'abc123');
165+
```
166+
167+
#### Sign in Anonymously.
168+
169+
```php
170+
$firestoreClient
171+
->authenticator()
172+
->signInAnonymously();
173+
```
174+
175+
### Retrieve Auth Token
176+
177+
```php
178+
$authToken = $firestoreClient->authenticator()->getAuthToken();
179+
```
180+
123181
### TODO
124182
- [x] Added delete attribute support.
125-
- [x] Add Support for Object, Boolean, Null, String, Integer, Array, Timestamp, GeoPoint
126-
- [ ] Add Exception Handling.
127-
- [ ] List all documents and collections.
128-
- [ ] Filters and pagination support.
183+
- [x] Add Support for Object, Boolean, Null, String, Integer, Array, Timestamp, GeoPoint, Bytes
184+
- [x] Add Exception Handling.
185+
- [x] List all documents.
186+
- [ ] List all collections.
187+
- [x] Filters and pagination support.
188+
- [ ] Structured Query support.
129189
- [ ] Transaction support.
130190
- [ ] Indexes support.
131191
- [ ] Entire collection delete support.

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
],
2020
"require": {
2121
"php": ">=5.6.6",
22+
"guzzlehttp/guzzle": "~6.0|~5.0|~4.0",
2223
"ext-curl": "*",
2324
"ext-json": "*"
2425
},

src/Attributes/FireStoreDeleteAttribute.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace MrShan0\PHPFirestore\Attributes;
44

5-
class FireStoreDeleteAttribute
5+
class FirestoreDeleteAttribute
66
{
77
//
88
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<?php
2+
namespace MrShan0\PHPFirestore\Authentication;
3+
4+
use Exception;
5+
use GuzzleHttp\Exception\BadResponseException;
6+
use MrShan0\PHPFirestore\Exceptions\Client\BadRequest;
7+
use MrShan0\PHPFirestore\FirestoreClient;
8+
use MrShan0\PHPFirestore\Handlers\RequestErrorHandler;
9+
use MrShan0\PHPFirestore\Helpers\FirestoreHelper;
10+
11+
class FirestoreAuthentication
12+
{
13+
/**
14+
* Firestore REST API Base URL
15+
*
16+
* @var string
17+
*/
18+
private $authRoot = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/';
19+
20+
/**
21+
* Firestore Client object
22+
*
23+
* @var \MrShan0\PHPFirestore\FirestoreClient
24+
*/
25+
private $client;
26+
27+
public function __construct(FirestoreClient $client)
28+
{
29+
$this->client = $client;
30+
}
31+
32+
/**
33+
* Return absolute url to make request
34+
*
35+
* @param string $resource
36+
*
37+
* @return string
38+
*/
39+
private function constructUrl($resource)
40+
{
41+
return $this->authRoot . $resource . '?key=' . $this->client->getApiKey();
42+
}
43+
44+
/**
45+
* You can call this method and set token if you've already generate token
46+
*
47+
* @param string $token
48+
*
49+
* @return array
50+
*/
51+
public function setCustomToken($token)
52+
{
53+
return $this->client->setOption('headers', [
54+
'Authorization' => 'Bearer ' . $token,
55+
]);
56+
}
57+
58+
/**
59+
* Extract auth token from client
60+
*
61+
* @return null|string
62+
*/
63+
public function getAuthToken()
64+
{
65+
$authHeader = $this->client->getOption('headers');
66+
67+
if (!$authHeader) {
68+
return null;
69+
}
70+
71+
return substr(reset($authHeader), 7);
72+
}
73+
74+
/**
75+
* Login with email and password into Firebase Authentication
76+
*
77+
* @param string $email
78+
* @param string $password
79+
* @param boolean $setToken
80+
*
81+
* @return object
82+
*/
83+
public function signInEmailPassword($email, $password, $setToken = true)
84+
{
85+
$response = $this->authRequest('POST', 'verifyPassword', [
86+
'form_params' => [
87+
'email' => $email,
88+
'password' => $password,
89+
'returnSecureToken' => 'true',
90+
]
91+
]);
92+
93+
if ($setToken) {
94+
if (!array_key_exists('idToken', $response)) {
95+
throw new BadRequest('idToken not found!');
96+
}
97+
98+
$this->setCustomToken($response['idToken']);
99+
}
100+
101+
return $response;
102+
}
103+
104+
/**
105+
* Login with anonymously into Firebase Authentication
106+
*
107+
* @param boolean $setToken
108+
*
109+
* @return object
110+
*/
111+
public function signInAnonymously($setToken = true)
112+
{
113+
$response = $this->authRequest('POST', 'signupNewUser', [
114+
'form_params' => [
115+
'returnSecureToken' => 'true',
116+
]
117+
]);
118+
119+
if ($setToken) {
120+
if (!array_key_exists('idToken', $response)) {
121+
throw new BadRequest('idToken not found!');
122+
}
123+
124+
$this->setCustomToken($response['idToken']);
125+
}
126+
127+
return $response;
128+
}
129+
130+
/**
131+
* Responsible to make request to firebase authentication mechanism (rest-api)
132+
*
133+
* @param string $method
134+
* @param string $resource
135+
* @param array $options
136+
*
137+
* @return object
138+
*/
139+
private function authRequest($method, $resource, array $options = [])
140+
{
141+
try {
142+
$options = array_merge($this->client->getOptions(), $options);
143+
144+
// Unset authorization if set mistakenly
145+
if (isset($options['headers']['Authorization'])) {
146+
unset($options['headers']['Authorization']);
147+
}
148+
149+
$this->client->setLastResponse(
150+
$this->client->getHttpClient()->request($method, $this->constructUrl($resource), $options)
151+
);
152+
153+
return FirestoreHelper::decode((string) $this->client->getLastResponse()->getBody());
154+
} catch (BadResponseException $exception) {
155+
$this->handleError($exception);
156+
}
157+
}
158+
159+
/**
160+
* Throw our own custom handler for errors.
161+
*
162+
* @param BadResponseException $exception
163+
*
164+
* @throws \MrShan0\PHPFirestore\Exceptions\Client\BadRequest
165+
* @throws \MrShan0\PHPFirestore\Exceptions\Client\Unauthorized
166+
* @throws \MrShan0\PHPFirestore\Exceptions\Client\Forbidden
167+
* @throws \MrShan0\PHPFirestore\Exceptions\Client\NotFound
168+
* @throws \MrShan0\PHPFirestore\Exceptions\Client\Conflict
169+
* @throws \MrShan0\PHPFirestore\Exceptions\Server\InternalServerError
170+
* @throws \MrShan0\PHPFirestore\Exceptions\UnhandledRequestError
171+
*/
172+
private function handleError(Exception $exception)
173+
{
174+
$handler = new RequestErrorHandler($exception);
175+
$handler->handleError();
176+
}
177+
}

src/Contracts/FireStoreDataTypeContract.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace MrShan0\PHPFirestore\Contracts;
44

5-
interface FireStoreDataTypeContract
5+
interface FirestoreDataTypeContract
66
{
77
/**
88
* Set data into variable which will be processed later

0 commit comments

Comments
 (0)