Я работаю над проектом, который использует Google Firestore версии 1 бета 1.
Однако для него не было предоставлено PHP SDK, поэтому я должен использовать REST API.
Я нашел это руководство онлайн, которое объясняет, как именно это сделать:
https://engineering.flosports.tv/google-cloud-firestore-document-crud-with-php-1df1c084e45b
Пройдя руководство, я смог сделать вывод, что пример сработал так, как я ожидал.
Однако мне нужно использовать ArrayValues, и я получаю следующую ошибку при попытке:
string(612) "{
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unknown name \"array_value\" at 'document.fields[1].value': Proto field is not repeating, cannot start list.",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "document.fields[1].value",
"description": "Invalid JSON payload received. Unknown name \"array_value\" at 'document.fields[1].value': Proto field is not repeating, cannot start list."}
]
}
]
}
}
"
Я запускаю образец файла из командной строки, как это:
php index.php
Вот index.php
<?php
include("firestore.php");
use PHPFireStore\FireStoreApiClient;
use PHPFireStore\FireStoreDocument;
$firestore = new FireStoreApiClient(
'XXXXXX', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
);
$document = new FireStoreDocument();
$document->setString('person', 'Jason'); // this works fine
$document->setArray('my-array', array("cats","dogs","birds")); // this does not work
$firestore->addDocument('people', $document);
Вот firestore.php
<?php
namespace PHPFireStore {
class FireStoreDocument {
private $fields = [];
private $name = null;
private $createTime = null;
private $updateTime = null;
/**
Example:
{
"name": "projects/{project_id}/databases/(default)/documents/{collectionName}/{docu
"fields": {
"hello": {
"doubleValue": 3
}
},
"createTime": "2017-10-18T21:27:33.186235Z",
"updateTime": "2017-10-18T21:27:33.186235Z"}
*/
public function __construct($json=null) {
if ($json !== null) {
$data = json_decode($json, true, 16);
// Meta properties
$this->name = $data['name'];
$this->createTime = $data['createTime'];
$this->updateTime = $data['updateTime'];
// Fields
foreach ($data['fields'] as $fieldName => $value) {
$this->fields[$fieldName] = $value;
}
}
}
public function getName() {
return $this->name;
}
public function setString($fieldName, $value) {
$this->fields[$fieldName] = [
'stringValue' => $value
];
}
public function setDouble($fieldName, $value) {
$this->fields[$fieldName] = [
'doubleValue' => floatval($value)
];
}
public function setArray($fieldName, $value) {
$this->fields[$fieldName] = [
'arrayValue' => $value
];
}
public function setBoolean($fieldName, $value) {
$this->fields[$fieldName] = [
'booleanValue' => !!$value
];
}
public function setInteger($fieldName, $value) {
$this->fields[$fieldName] = [
'integerValue' => intval($value)
];
}
public function setGeopoint($fieldName, $value) {
$this->fields[$fieldName] = [
'geoPointValue' => array(
'latitude' => (float)41.3819409,
'longitude' => (float)-73.5299525
)
];
}
public function get($fieldName) {
if (array_key_exists($fieldName, $this->fields)) {
return reset($this->fields);
}
throw new Exception('No such field');
}
public function toJson() {
return json_encode([
'fields' => $this->fields
]);
}
}
class FireStoreApiClient {
private $apiRoot = 'https://firestore.googleapis.com/v1beta1/';
private $project;
private $apiKey;
function __construct($project, $apiKey) {
$this->project = $project;
$this->apiKey = $apiKey;
}
private function constructUrl($method, $params=null) {
$params = is_array($params) ? $params : [];
return (
$this->apiRoot . 'projects/' . $this->project . '/' .
'databases/(default)/' . $method . '?key=' . $this->apiKey . '&' . h
);
}
private function get($method, $params=null) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $this->constructUrl($method, $params),
CURLOPT_USERAGENT => 'cURL'
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
private function post($method, $params, $postBody) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => $this->constructUrl($method, $params),
CURLOPT_HTTPHEADER => array('Content-Type: application/json','Content-Le
CURLOPT_USERAGENT => 'cURL',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postBody
));
$response = curl_exec($curl);
var_dump($response);
curl_close($curl);
return $response;
}
private function put($method, $params, $postBody) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => array('Content-Type: application/json','Content-Le
CURLOPT_URL => $this->constructUrl($method, $params),
CURLOPT_USERAGENT => 'cURL',
CURLOPT_POSTFIELDS => $postBody
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
private function patch($method, $params, $postBody) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => array('Content-Type: application/json','Content-Le
CURLOPT_URL => $this->constructUrl($method, $params),
CURLOPT_USERAGENT => 'cURL',
CURLOPT_POSTFIELDS => $postBody
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
private function delete($method, $params) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_URL => $this->constructUrl($method, $params),
CURLOPT_USERAGENT => 'cURL'
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
public function getDocument($collectionName, $documentId) {
if ($response = $this->get("documents/$collectionName/$documentId")) {
return new FireStoreDocument($response);
}
}
/**
This does not work
*/
public function setDocument($collectionName, $documentId, $document) {
return $this->put(
"documents/$collectionName/$documentId",
[ ],
$document->toJson()
);
}
public function updateDocument($collectionName, $documentId, $document, $documentExi
$params = [];
if ($documentExists !== null) {
$params['currentDocument.exists'] = !!$documentExists;
}
return $this->patch(
"documents/$collectionName/$documentId",
$params,
$document->toJson()
);
}
public function deleteDocument($collectionName, $documentId) {
return $this->delete(
"documents/$collectionName/$documentId", []
);
}
public function addDocument($collectionName, $document) {
return $this->post(
"documents/$collectionName",
[],
$document->toJson()
);
}
}
}
Кроме того, это версия PHP, которую я использую:
php -v
PHP 7.1.10-1+ubuntu14.04.1+deb.sury.org+1 (cli) (built: Sep 29 2017 17:33:22) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.1.10-1+ubuntu14.04.1+deb.sury.org+1, Copyright (c)
1999-2017, by Zend Technologies
Используя ссылку, предоставленную @JRLtechwriting, я заставил это работать.
Вот ссылка: http://googlecloudplatform.github.io/google-cloud-php/#/docs/google-cloud/v0.53.0/firestore/firestoreclient
Из командной строки на Ubuntu 14.04 я должен был сделать это:
sudo apt-get install php7.1-dev php-pear phpunit libz-dev
sudo pecl install protobuf
sudo pecl install grpc
sudo composer require google/cloud
# append BOTH apache2 php.ini AND command line php.ini with the following:
# extension=protobuf.so
# extension=grpc.so
sudo apachectl graceful
Затем я написал этот код:
<?php
require "vendor/autoload.php"; // composer
$path = "/xxx/firebase_auth.json"; // this file is provided by google
$config = array(
"projectId" => "xxx",
"keyFile" => json_decode(file_get_contents($path), true)
);
$firestore = new FirestoreClient($config);
$collection = $firestore->collection('people');
$person = $collection->add([
'person_id' => '3'
]);
$document = $firestore->document('people/'.$person->id());
$firestore->runTransaction(function (Transaction $transaction) use ($document) {
$transaction->update($document, [
['path' => 'person', 'value' => 'Jason'],
['path' => 'my-array', 'value' =>array(
"cats",
"dogs",
"birds",
)
],
]);
});
И это сработало, как и ожидалось.
Кроме того, если вы используете платформу со встроенным классом Transaction, вам нужно будет принять специальные меры при использовании Google Firestore SDK:
use \Google\Cloud\Firestore\Transaction as FirestoreTransaction;
И эта строка будет переписана как:
$firestore->runTransaction(function (FirestoreTransaction $transaction) use ($document) {
Других решений пока нет …