从PHP发布ArrayValue到Firestore不起作用

时间:2018-02-22 15:51:12

标签: php google-cloud-firestore php-7.1

我正在开发一个使用Google Firestore版本1 beta 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

1 个答案:

答案 0 :(得分:1)

使用@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) {