{"action":"created","comment":{"url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/comments/111843529","pull_request_review_id":33094706,"id":111843529,"diff_hunk":"@@ -0,0 +1,1313 @@\n+<?php\n+/**\n+ * Copyright 2016 Google Inc.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+namespace Google\\Cloud\\Spanner;\n+\n+use Google\\Cloud\\Core\\Exception\\AbortedException;\n+use Google\\Cloud\\Core\\Exception\\NotFoundException;\n+use Google\\Cloud\\Core\\Iam\\Iam;\n+use Google\\Cloud\\Core\\LongRunning\\LongRunningOperation;\n+use Google\\Cloud\\Core\\LongRunning\\LROTrait;\n+use Google\\Cloud\\Core\\LongRunning\\LongRunningConnectionInterface;\n+use Google\\Cloud\\Core\\Retry;\n+use Google\\Cloud\\Spanner\\Connection\\ConnectionInterface;\n+use Google\\Cloud\\Spanner\\Connection\\IamDatabase;\n+use Google\\Cloud\\Spanner\\Session\\Session;\n+use Google\\Cloud\\Spanner\\Session\\SessionPoolInterface;\n+use Google\\Cloud\\Spanner\\V1\\SpannerClient as GrpcSpannerClient;\n+\n+/**\n+ * Represents a Google Cloud Spanner Database.\n+ *\n+ * Example:\n+ * ```\n+ * use Google\\Cloud\\Spanner\\SpannerClient;\n+ *\n+ * $spanner = new SpannerClient();\n+ *\n+ * $database = $spanner->connect('my-instance', 'my-database');\n+ * ```\n+ *\n+ * ```\n+ * // Databases can also be connected to via an Instance.\n+ * use Google\\Cloud\\Spanner\\SpannerClient;\n+ *\n+ * $spanner = new SpannerClient();\n+ *\n+ * $instance = $spanner->instance('my-instance');\n+ * $database = $instance->database('my-database');\n+ * ```\n+ */\n+class Database\n+{\n+    use LROTrait;\n+    use TransactionConfigurationTrait;\n+\n+    const MAX_RETRIES = 3;\n+\n+    /**\n+     * @var ConnectionInterface\n+     */\n+    private $connection;\n+\n+    /**\n+     * @var Instance\n+     */\n+    private $instance;\n+\n+    /**\n+     * @var LongRunningConnectionInterface\n+     */\n+    private $lroConnection;\n+\n+    /**\n+     * @var Operation\n+     */\n+    private $operation;\n+\n+    /**\n+     * @var string\n+     */\n+    private $projectId;\n+\n+    /**\n+     * @var string\n+     */\n+    private $name;\n+\n+    /**\n+     * @var Iam\n+     */\n+    private $iam;\n+\n+    /**\n+     * @var Session|null\n+     */\n+    private $session;\n+\n+    /**\n+     * @var SessionPoolInterface|null\n+     */\n+    private $sessionPool;\n+\n+    /**\n+     * Create an object representing a Database.\n+     *\n+     * @param ConnectionInterface $connection The connection to the\n+     *        Google Cloud Spanner Admin API.\n+     * @param Instance $instance The instance in which the database exists.\n+     * @param LongRunningConnectionInterface $lroConnection An implementation\n+     *        mapping to methods which handle LRO resolution in the service.\n+     * @param string $projectId The project ID.\n+     * @param string $name The database name.\n+     * @param SessionPoolInterface $sessionPool [optional] The session pool\n+     *        implementation.\n+     * @param bool $returnInt64AsObject [optional If true, 64 bit integers will\n+     *        be returned as a {@see Google\\Cloud\\Core\\Int64} object for 32 bit\n+     *        platform compatibility. **Defaults to** false.\n+     */\n+    public function __construct(\n+        ConnectionInterface $connection,\n+        Instance $instance,\n+        LongRunningConnectionInterface $lroConnection,\n+        array $lroCallables,\n+        $projectId,\n+        $name,\n+        SessionPoolInterface $sessionPool = null,\n+        $returnInt64AsObject = false\n+    ) {\n+        $this->connection = $connection;\n+        $this->instance = $instance;\n+        $this->lroConnection = $lroConnection;\n+        $this->lroCallables = $lroCallables;\n+        $this->projectId = $projectId;\n+        $this->name = $name;\n+        $this->sessionPool = $sessionPool;\n+        $this->operation = new Operation($connection, $returnInt64AsObject);\n+\n+        if ($this->sessionPool) {\n+            $this->sessionPool->setDatabase($this);\n+        }\n+    }\n+\n+    /**\n+     * Return the simple database name.\n+     *\n+     * Example:\n+     * ```\n+     * $name = $database->name();\n+     * ```\n+     *\n+     * @return string\n+     */\n+    public function name()\n+    {\n+        return $this->name;\n+    }\n+\n+    /**\n+     * Check if the database exists.\n+     *\n+     * This method sends a service request.\n+     *\n+     * **NOTE**: Requires `https://www.googleapis.com/auth/spanner.admin` scope.\n+     *\n+     * Example:\n+     * ```\n+     * if ($database->exists()) {\n+     *     echo 'Database exists!';\n+     * }\n+     * ```\n+     *\n+     * @param array $options [optional] Configuration options.\n+     * @return bool\n+     */\n+    public function exists(array $options = [])\n+    {\n+        try {\n+            $this->ddl($options);\n+        } catch (NotFoundException $e) {\n+            return false;\n+        }\n+\n+        return true;\n+    }\n+\n+    /**\n+     * Update the Database schema by running a SQL statement.\n+     *\n+     * **NOTE**: Requires `https://www.googleapis.com/auth/spanner.admin` scope.\n+     *\n+     * Example:\n+     * ```\n+     * $database->updateDdl(\n+     *     'CREATE TABLE Users (\n+     *         id INT64 NOT NULL,\n+     *         name STRING(100) NOT NULL\n+     *         password STRING(100) NOT NULL\n+     *     )'\n+     * );\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/docs/data-definition-language Data Definition Language\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.UpdateDatabaseDdlRequest UpdateDDLRequest\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param string $statement A DDL statements to run against a database.\n+     * @param array $options [optional] Configuration options.\n+     * @return LongRunningOperation\n+     */\n+    public function updateDdl($statement, array $options = [])\n+    {\n+        return $this->updateDdlBatch([$statement], $options);\n+    }\n+\n+    /**\n+     * Update the Database schema by running a set of SQL statements.\n+     *\n+     * **NOTE**: Requires `https://www.googleapis.com/auth/spanner.admin` scope.\n+     *\n+     * Example:\n+     * ```\n+     * $database->updateDdlBatch([\n+     *     'CREATE TABLE Users (\n+     *         id INT64 NOT NULL,\n+     *         name STRING(100) NOT NULL,\n+     *         password STRING(100) NOT NULL\n+     *     ) PRIMARY KEY (id)',\n+     *     'CREATE TABLE Posts (\n+     *         id INT64 NOT NULL,\n+     *         title STRING(100) NOT NULL,\n+     *         content STRING(MAX) NOT NULL\n+     *     ) PRIMARY KEY(id)'\n+     * ]);\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/docs/data-definition-language Data Definition Language\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.UpdateDatabaseDdlRequest UpdateDDLRequest\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param string[] $statements A list of DDL statements to run against a database.\n+     * @param array $options [optional] Configuration options.\n+     * @return LongRunningOperation\n+     */\n+    public function updateDdlBatch(array $statements, array $options = [])\n+    {\n+        $operation = $this->connection->updateDatabase($options + [\n+            'name' => $this->fullyQualifiedDatabaseName(),\n+            'statements' => $statements,\n+        ]);\n+\n+        return $this->lro($this->lroConnection, $operation['name'], $this->lroCallables);\n+    }\n+\n+    /**\n+     * Drop the database.\n+     *\n+     * **NOTE**: Requires `https://www.googleapis.com/auth/spanner.admin` scope.\n+     *\n+     * Example:\n+     * ```\n+     * $database->drop();\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DropDatabaseRequest DropDatabaseRequest\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param array $options [optional] Configuration options.\n+     * @return void\n+     */\n+    public function drop(array $options = [])\n+    {\n+        $this->connection->dropDatabase($options + [\n+            'name' => $this->fullyQualifiedDatabaseName()\n+        ]);\n+    }\n+\n+    /**\n+     * Get a list of all database DDL statements.\n+     *\n+     * **NOTE**: Requires `https://www.googleapis.com/auth/spanner.admin` scope.\n+     *\n+     * Example:\n+     * ```\n+     * $statements = $database->ddl();\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#getdatabaseddlrequest GetDatabaseDdlRequest\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param array $options [optional] Configuration options.\n+     * @return array\n+     */\n+    public function ddl(array $options = [])\n+    {\n+        $ddl = $this->connection->getDatabaseDDL($options + [\n+            'name' => $this->fullyQualifiedDatabaseName()\n+        ]);\n+\n+        if (isset($ddl['statements'])) {\n+            return $ddl['statements'];\n+        }\n+\n+        return [];\n+    }\n+\n+    /**\n+     * Manage the database IAM policy\n+     *\n+     * Example:\n+     * ```\n+     * $iam = $database->iam();\n+     * ```\n+     *\n+     * @return Iam\n+     */\n+    public function iam()\n+    {\n+        if (!$this->iam) {\n+            $this->iam = new Iam(\n+                new IamDatabase($this->connection),\n+                $this->fullyQualifiedDatabaseName()\n+            );\n+        }\n+\n+        return $this->iam;\n+    }\n+\n+    /**\n+     * Create a snapshot to read from a database at a point in time.\n+     *\n+     * If no configuration options are provided, transaction will be opened with\n+     * strong consistency.\n+     *\n+     * Snapshots are executed behind the scenes using a Read-Only Transaction.\n+     *\n+     * Example:\n+     * ```\n+     * $snapshot = $database->snapshot();\n+     * ```\n+     *\n+     * ```\n+     * // Take a shapshot with a returned timestamp.\n+     * $snapshot = $database->snapshot([\n+     *     'returnReadTimestamp' => true\n+     * ]);\n+     *\n+     * $timestamp = $snapshot->readTimestamp();\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.BeginTransactionRequest BeginTransactionRequest\n+     * @see https://cloud.google.com/spanner/docs/transactions Transactions\n+     *\n+     * @param array $options [optional] {\n+     *     Configuration Options\n+     *\n+     *     See [ReadOnly](https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions.ReadOnly)\n+     *     for detailed description of available options.\n+     *\n+     *     Please note that only one of `$strong`, `$readTimestamp` or\n+     *     `$exactStaleness` may be set in a request.\n+     *\n+     *     @type bool $returnReadTimestamp If true, the Cloud Spanner-selected\n+     *           read timestamp is included in the Transaction message that\n+     *           describes the transaction.\n+     *     @type bool $strong Read at a timestamp where all previously committed\n+     *           transactions are visible.\n+     *     @type Timestamp $readTimestamp Executes all reads at the given\n+     *           timestamp.\n+     *     @type Duration $exactStaleness Represents a number of seconds. Executes\n+     *           all reads at a timestamp that is $exactStaleness old.\n+     * }\n+     * @return Snapshot\n+     * @codingStandardsIgnoreEnd\n+     */\n+    public function snapshot(array $options = [])\n+    {\n+        // These are only available in single-use transactions.\n+        if (isset($options['maxStaleness']) || isset($options['minReadTimestamp'])) {\n+            throw new \\BadMethodCallException(\n+                'maxStaleness and minReadTimestamp are only available in single-use transactions.'\n+            );\n+        }\n+\n+        $transactionOptions = $this->configureSnapshotOptions($options);\n+\n+        $session = $this->selectSession(SessionPoolInterface::CONTEXT_READ);\n+\n+        try {\n+            return $this->operation->snapshot($session, $transactionOptions);\n+        } finally {\n+            $session->setExpiration();\n+        }\n+    }\n+\n+    /**\n+     * Execute Read/Write operations inside a Transaction.\n+     *\n+     * Using this method and providing a callable operation provides certain\n+     * benefits including automatic retry when a transaction fails. In case of a\n+     * failure, all transaction operations, including reads, are re-applied in a\n+     * new transaction.\n+     *\n+     * If a transaction exceeds the maximum number of retries,\n+     * {@see Google\\Cloud\\Core\\Exception\\AbortedException} will be thrown. Any other\n+     * exception types will immediately bubble up and will interrupt the retry\n+     * operation.\n+     *\n+     * Please note that once a transaction reads data, it will lock the read\n+     * data, preventing other users from modifying that data. For this reason,\n+     * it is important that every transaction commits or rolls back as early as\n+     * possible. Do not hold transactions open longer than necessary.\n+     *\n+     * If you have an active transaction which was obtained from elsewhere, you\n+     * can provide it to this method and gain the benefits of managed retry by\n+     * setting `$options.transaction` to your {@see Google\\Cloud\\Spanner\\Transaction}\n+     * instance. Please note that in this case, it is important that ALL reads\n+     * and mutations MUST be performed within the runTransaction callable.\n+     *\n+     * Example:\n+     * ```\n+     * $transaction = $database->runTransaction(function (Transaction $t) use ($username, $password) {\n+     *     $rows = $t->execute('SELECT * FROM Users WHERE Name = @name and PasswordHash = @password', [\n+     *         'parameters' => [\n+     *             'name' => $username,\n+     *             'password' => password_hash($password, PASSWORD_DEFAULT)\n+     *         ]\n+     *     ])->rows();\n+     *     $user = $rows->current();\n+     *\n+     *     if ($user) {\n+     *         // Do something here to grant the user access.\n+     *         // Maybe set a cookie?\n+     *\n+     *         $user['loginCount'] = $user['loginCount'] + 1;\n+     *         $t->update('Users', $user);\n+     *\n+     *         $t->commit();\n+     *     } else {\n+     *         $t->rollback();\n+     *     }\n+     * });\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.BeginTransactionRequest BeginTransactionRequest\n+     * @see https://cloud.google.com/spanner/docs/transactions Transactions\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param callable $operation The operations to run in the transaction.\n+     *        **Signature:** `function (Transaction $transaction)`.\n+     * @param array $options [optional] {\n+     *     Configuration Options\n+     *\n+     *     @type int $maxRetries The number of times to attempt to apply the\n+     *           operation before failing. **Defaults to ** `3`.\n+     *     @type Transaction $transaction If provided, the transaction will be\n+     *           passed to the callable instead of attempting to begin a new\n+     *           transaction.\n+     * }\n+     * @return mixed The return value of `$operation`.\n+     */\n+    public function runTransaction(callable $operation, array $options = [])\n+    {\n+        $options += [\n+            'maxRetries' => self::MAX_RETRIES,\n+            'transaction' => null\n+        ];\n+\n+        // There isn't anything configurable here.\n+        $options['transactionOptions'] = $this->configureTransactionOptions();\n+\n+        $session = $this->selectSession(SessionPoolInterface::CONTEXT_READWRITE);\n+\n+        $attempt = 0;\n+        $startTransactionFn = function ($session, $options) use (&$attempt) {\n+            if ($attempt === 0 && $options['transaction'] instanceof Transaction) {\n+                $transaction = $options['transaction'];\n+            } elseif ($attempt === 0 && $options['transaction']) {\n+                throw new \\InvalidArgumentException('Given transaction must be an instance of Transaction.');\n+            } else {\n+                $transaction = $this->operation->transaction($session, $options);\n+            }\n+\n+            $attempt++;\n+            return $transaction;\n+        };\n+\n+        $delayFn = function (\\Exception $e) {\n+            if (!($e instanceof AbortedException)) {\n+                throw $e;\n+            }\n+\n+            $delay = $e->getRetryDelay();\n+            time_nanosleep($delay['seconds'], $delay['nanos']);\n+        };\n+\n+        $commitFn = function ($operation, $session, $options) use ($startTransactionFn) {\n+            $transaction = call_user_func_array($startTransactionFn, [\n+                $session,\n+                $options\n+            ]);\n+\n+            return call_user_func($operation, $transaction);\n+        };\n+\n+        $retry = new Retry($options['maxRetries'], $delayFn);\n+\n+        try {\n+            return $retry->execute($commitFn, [$operation, $session, $options]);\n+        } finally {\n+            $session->setExpiration();\n+        }\n+    }\n+\n+    /**\n+     * Create and return a new read/write Transaction.\n+     *\n+     * When manually using a Transaction, it is advised that retry logic be\n+     * implemented to reapply all operations when an instance of\n+     * {@see Google\\Cloud\\Core\\Exception\\AbortedException} is thrown.\n+     *\n+     * If you wish Google Cloud PHP to handle retry logic for you (recommended\n+     * for most cases), use {@see Google\\Cloud\\Spanner\\Database::runTransaction()}.\n+     *\n+     * Please note that once a transaction reads data, it will lock the read\n+     * data, preventing other users from modifying that data. For this reason,\n+     * it is important that every transaction commits or rolls back as early as\n+     * possible. Do not hold transactions open longer than necessary.\n+     *\n+     * Example:\n+     * ```\n+     * $transaction = $database->transaction();\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.BeginTransactionRequest BeginTransactionRequest\n+     * @see https://cloud.google.com/spanner/docs/transactions Transactions\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param array $options [optional] Configuration Options.\n+     * @return Transaction\n+     */\n+    public function transaction(array $options = [])\n+    {\n+        // There isn't anything configurable here.\n+        $options['transactionOptions'] = [\n+            'readWrite' => []\n+        ];\n+\n+        $session = $this->selectSession(SessionPoolInterface::CONTEXT_READWRITE);\n+\n+        try {\n+            return $this->operation->transaction($session, $options);\n+        } finally {\n+            $session->setExpiration();\n+        }\n+    }\n+\n+    /**\n+     * Insert a row.\n+     *\n+     * Mutations are committed in a single-use transaction.\n+     *\n+     * Example:\n+     * ```\n+     * $database->insert('Posts', [\n+     *     'ID' => 1337,\n+     *     'postTitle' => 'Hello World!',\n+     *     'postContent' => 'Welcome to our site.'\n+     * ]);\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.CommitRequest CommitRequest\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param string $table The table to mutate.\n+     * @param array $data The row data to insert.\n+     * @param array $options [optional] Configuration options.\n+     * @return Timestamp The commit Timestamp.\n+     */\n+    public function insert($table, array $data, array $options = [])\n+    {\n+        return $this->insertBatch($table, [$data], $options);\n+    }\n+\n+    /**\n+     * Insert multiple rows.\n+     *\n+     * Mutations are committed in a single-use transaction.\n+     *\n+     * Example:\n+     * ```\n+     * $database->insertBatch('Posts', [\n+     *     [\n+     *         'ID' => 1337,\n+     *         'postTitle' => 'Hello World!',\n+     *         'postContent' => 'Welcome to our site.'\n+     *     ], [\n+     *         'ID' => 1338,\n+     *         'postTitle' => 'Our History',\n+     *         'postContent' => 'Lots of people ask about where we got started.'\n+     *     ]\n+     * ]);\n+     * ```\n+     *\n+     * @codingStandardsIgnoreStart\n+     * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.CommitRequest CommitRequest\n+     * @codingStandardsIgnoreEnd\n+     *\n+     * @param string $table The table to mutate.\n+     * @param array $dataSet The row data to insert.\n+     * @param array $options [optional] Configuration options.\n+     * @return Timestamp The commit Timestamp.\n+     */\n+    public function insertBatch($table, array $dataSet, array $options = [])\n+    {\n+        $mutations = [];\n+        foreach ($dataSet as $data) {\n+            $mutations[] = $this->operation->mutation(Operation::OP_INSERT, $table, $data);\n+        }\n+\n+        $session = $this->selectSession(SessionPoolInterface::CONTEXT_READWRITE);\n+\n+        $options['singleUseTransaction'] = $this->configureTransactionOptions();\n+\n+        try {\n+            return $this->operation->commit($session, $mutations, $options);\n+        } finally {\n+            $session->setExpiration();\n+        }\n+    }\n+\n+    /**\n+     * Update a row.\n+     *\n+     * Only data which you wish to update need be included. You must provide","path":"src/Spanner/Database.php","position":646,"original_position":646,"commit_id":"5d53c5653ca9ec3a3ece5194ed8cc7794a67ab24","original_commit_id":"5d53c5653ca9ec3a3ece5194ed8cc7794a67ab24","user":{"login":"vkedia","id":20405887,"avatar_url":"https://avatars0.githubusercontent.com/u/20405887?v=3","gravatar_id":"","url":"https://api.github.com/users/vkedia","html_url":"https://github.com/vkedia","followers_url":"https://api.github.com/users/vkedia/followers","following_url":"https://api.github.com/users/vkedia/following{/other_user}","gists_url":"https://api.github.com/users/vkedia/gists{/gist_id}","starred_url":"https://api.github.com/users/vkedia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vkedia/subscriptions","organizations_url":"https://api.github.com/users/vkedia/orgs","repos_url":"https://api.github.com/users/vkedia/repos","events_url":"https://api.github.com/users/vkedia/events{/privacy}","received_events_url":"https://api.github.com/users/vkedia/received_events","type":"User","site_admin":false},"body":"Why not just use the text in the [rpc](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Mutation.Write):\r\n\r\n\"The list of columns must contain enough columns to allow Cloud Spanner to derive values for all primary key columns in the row(s) to be modified.\"","created_at":"2017-04-17T23:26:31Z","updated_at":"2017-04-17T23:33:49Z","html_url":"https://github.com/GoogleCloudPlatform/google-cloud-php/pull/438#discussion_r111843529","pull_request_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438","_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/comments/111843529"},"html":{"href":"https://github.com/GoogleCloudPlatform/google-cloud-php/pull/438#discussion_r111843529"},"pull_request":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438"}}},"pull_request":{"url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438","id":114864076,"html_url":"https://github.com/GoogleCloudPlatform/google-cloud-php/pull/438","diff_url":"https://github.com/GoogleCloudPlatform/google-cloud-php/pull/438.diff","patch_url":"https://github.com/GoogleCloudPlatform/google-cloud-php/pull/438.patch","issue_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues/438","number":438,"state":"open","locked":false,"title":"Introduce Google Cloud Spanner","user":{"login":"dwsupplee","id":2079879,"avatar_url":"https://avatars1.githubusercontent.com/u/2079879?v=3","gravatar_id":"","url":"https://api.github.com/users/dwsupplee","html_url":"https://github.com/dwsupplee","followers_url":"https://api.github.com/users/dwsupplee/followers","following_url":"https://api.github.com/users/dwsupplee/following{/other_user}","gists_url":"https://api.github.com/users/dwsupplee/gists{/gist_id}","starred_url":"https://api.github.com/users/dwsupplee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dwsupplee/subscriptions","organizations_url":"https://api.github.com/users/dwsupplee/orgs","repos_url":"https://api.github.com/users/dwsupplee/repos","events_url":"https://api.github.com/users/dwsupplee/events{/privacy}","received_events_url":"https://api.github.com/users/dwsupplee/received_events","type":"User","site_admin":false},"body":"Introducing.... Google Cloud Spanner support for PHP!\r\n\r\nThis PR is ready for review and feedback with a small caveat, there are a small handful of tests which need to be updated yet.\r\n\r\nA few items worth noting for discussion:\r\n- A request from the Spanner team for the session pool was to prime transactions - we have left this out of our current cache based session pool implementation. For every transaction we expend we would need to immediately replace it with a fresh one - given that the pool is managed by each request flowing through the code this wouldn't provide any optimizations unfortunately. Ideally, in time, we will add other session pool implementations that can run as a process alongside the application code and gain the benefits of priming the transactions.\r\n- The cache based session pool relies on a locking mechanism in order to prevent concurrent requests from colliding. Symfony just recently introduced a [lock component](https://github.com/symfony/lock) which covers the use cases we were already attempting to implement. As locking can can be complex, it seems sensible to use a component which has had lots of eyes on it and serious consideration taken into it's design and testing. The downside here, is that the component requires PHP > 5.5.9 (where we currently require > 5.5) and it will not be officially released until [May](http://symfony.com/roadmap?version=3.3#checker). I am okay with bumping our required version of PHP up slightly, as it is highly unlikely any users are running versions between 5.5 and 5.5.9.. Thoughts are certainly appreciated, however.\r\n\r\n/cc @vkedia @tmatsuo \r\n\r\nhttps://github.com/dwsupplee/gcloud-php/tree/spanner/src/Spanner\r\n","created_at":"2017-04-07T17:32:23Z","updated_at":"2017-04-17T23:33:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"aeaadedd7bc341a174fc7d843c9143065c7a7aed","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438/commits","review_comments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438/comments","review_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/comments{/number}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues/438/comments","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/statuses/5d53c5653ca9ec3a3ece5194ed8cc7794a67ab24","head":{"label":"dwsupplee:spanner","ref":"spanner","sha":"5d53c5653ca9ec3a3ece5194ed8cc7794a67ab24","user":{"login":"dwsupplee","id":2079879,"avatar_url":"https://avatars1.githubusercontent.com/u/2079879?v=3","gravatar_id":"","url":"https://api.github.com/users/dwsupplee","html_url":"https://github.com/dwsupplee","followers_url":"https://api.github.com/users/dwsupplee/followers","following_url":"https://api.github.com/users/dwsupplee/following{/other_user}","gists_url":"https://api.github.com/users/dwsupplee/gists{/gist_id}","starred_url":"https://api.github.com/users/dwsupplee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dwsupplee/subscriptions","organizations_url":"https://api.github.com/users/dwsupplee/orgs","repos_url":"https://api.github.com/users/dwsupplee/repos","events_url":"https://api.github.com/users/dwsupplee/events{/privacy}","received_events_url":"https://api.github.com/users/dwsupplee/received_events","type":"User","site_admin":false},"repo":{"id":43695469,"name":"gcloud-php","full_name":"dwsupplee/gcloud-php","owner":{"login":"dwsupplee","id":2079879,"avatar_url":"https://avatars1.githubusercontent.com/u/2079879?v=3","gravatar_id":"","url":"https://api.github.com/users/dwsupplee","html_url":"https://github.com/dwsupplee","followers_url":"https://api.github.com/users/dwsupplee/followers","following_url":"https://api.github.com/users/dwsupplee/following{/other_user}","gists_url":"https://api.github.com/users/dwsupplee/gists{/gist_id}","starred_url":"https://api.github.com/users/dwsupplee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dwsupplee/subscriptions","organizations_url":"https://api.github.com/users/dwsupplee/orgs","repos_url":"https://api.github.com/users/dwsupplee/repos","events_url":"https://api.github.com/users/dwsupplee/events{/privacy}","received_events_url":"https://api.github.com/users/dwsupplee/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dwsupplee/gcloud-php","description":"Google Cloud Client Library for PHP","fork":true,"url":"https://api.github.com/repos/dwsupplee/gcloud-php","forks_url":"https://api.github.com/repos/dwsupplee/gcloud-php/forks","keys_url":"https://api.github.com/repos/dwsupplee/gcloud-php/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dwsupplee/gcloud-php/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dwsupplee/gcloud-php/teams","hooks_url":"https://api.github.com/repos/dwsupplee/gcloud-php/hooks","issue_events_url":"https://api.github.com/repos/dwsupplee/gcloud-php/issues/events{/number}","events_url":"https://api.github.com/repos/dwsupplee/gcloud-php/events","assignees_url":"https://api.github.com/repos/dwsupplee/gcloud-php/assignees{/user}","branches_url":"https://api.github.com/repos/dwsupplee/gcloud-php/branches{/branch}","tags_url":"https://api.github.com/repos/dwsupplee/gcloud-php/tags","blobs_url":"https://api.github.com/repos/dwsupplee/gcloud-php/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dwsupplee/gcloud-php/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dwsupplee/gcloud-php/git/refs{/sha}","trees_url":"https://api.github.com/repos/dwsupplee/gcloud-php/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dwsupplee/gcloud-php/statuses/{sha}","languages_url":"https://api.github.com/repos/dwsupplee/gcloud-php/languages","stargazers_url":"https://api.github.com/repos/dwsupplee/gcloud-php/stargazers","contributors_url":"https://api.github.com/repos/dwsupplee/gcloud-php/contributors","subscribers_url":"https://api.github.com/repos/dwsupplee/gcloud-php/subscribers","subscription_url":"https://api.github.com/repos/dwsupplee/gcloud-php/subscription","commits_url":"https://api.github.com/repos/dwsupplee/gcloud-php/commits{/sha}","git_commits_url":"https://api.github.com/repos/dwsupplee/gcloud-php/git/commits{/sha}","comments_url":"https://api.github.com/repos/dwsupplee/gcloud-php/comments{/number}","issue_comment_url":"https://api.github.com/repos/dwsupplee/gcloud-php/issues/comments{/number}","contents_url":"https://api.github.com/repos/dwsupplee/gcloud-php/contents/{+path}","compare_url":"https://api.github.com/repos/dwsupplee/gcloud-php/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dwsupplee/gcloud-php/merges","archive_url":"https://api.github.com/repos/dwsupplee/gcloud-php/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dwsupplee/gcloud-php/downloads","issues_url":"https://api.github.com/repos/dwsupplee/gcloud-php/issues{/number}","pulls_url":"https://api.github.com/repos/dwsupplee/gcloud-php/pulls{/number}","milestones_url":"https://api.github.com/repos/dwsupplee/gcloud-php/milestones{/number}","notifications_url":"https://api.github.com/repos/dwsupplee/gcloud-php/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dwsupplee/gcloud-php/labels{/name}","releases_url":"https://api.github.com/repos/dwsupplee/gcloud-php/releases{/id}","deployments_url":"https://api.github.com/repos/dwsupplee/gcloud-php/deployments","created_at":"2015-10-05T15:45:33Z","updated_at":"2016-05-22T22:27:43Z","pushed_at":"2017-04-14T21:07:16Z","git_url":"git://github.com/dwsupplee/gcloud-php.git","ssh_url":"git@github.com:dwsupplee/gcloud-php.git","clone_url":"https://github.com/dwsupplee/gcloud-php.git","svn_url":"https://github.com/dwsupplee/gcloud-php","homepage":null,"size":3535,"stargazers_count":1,"watchers_count":1,"language":"PHP","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"GoogleCloudPlatform:master","ref":"master","sha":"2b848207b70fd096e1cdb21ab7716bfba549769f","user":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars3.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"repo":{"id":43642389,"name":"google-cloud-php","full_name":"GoogleCloudPlatform/google-cloud-php","owner":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars3.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/GoogleCloudPlatform/google-cloud-php","description":"Google Cloud Client Library for PHP","fork":false,"url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php","forks_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/forks","keys_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/teams","hooks_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/hooks","issue_events_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues/events{/number}","events_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/events","assignees_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/assignees{/user}","branches_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/branches{/branch}","tags_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/tags","blobs_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/git/refs{/sha}","trees_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/statuses/{sha}","languages_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/languages","stargazers_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/stargazers","contributors_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/contributors","subscribers_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/subscribers","subscription_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/subscription","commits_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/commits{/sha}","git_commits_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/git/commits{/sha}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/comments{/number}","issue_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues/comments{/number}","contents_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/contents/{+path}","compare_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/merges","archive_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/downloads","issues_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues{/number}","pulls_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls{/number}","milestones_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/milestones{/number}","notifications_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/labels{/name}","releases_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/releases{/id}","deployments_url":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/deployments","created_at":"2015-10-04T16:09:46Z","updated_at":"2017-04-12T20:26:33Z","pushed_at":"2017-04-17T22:07:57Z","git_url":"git://github.com/GoogleCloudPlatform/google-cloud-php.git","ssh_url":"git@github.com:GoogleCloudPlatform/google-cloud-php.git","clone_url":"https://github.com/GoogleCloudPlatform/google-cloud-php.git","svn_url":"https://github.com/GoogleCloudPlatform/google-cloud-php","homepage":"https://googlecloudplatform.github.io/google-cloud-php","size":3590,"stargazers_count":122,"watchers_count":122,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":71,"mirror_url":null,"open_issues_count":37,"forks":71,"open_issues":37,"watchers":122,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438"},"html":{"href":"https://github.com/GoogleCloudPlatform/google-cloud-php/pull/438"},"issue":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues/438"},"comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/issues/438/comments"},"review_comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438/comments"},"review_comment":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/pulls/438/commits"},"statuses":{"href":"https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/statuses/5d53c5653ca9ec3a3ece5194ed8cc7794a67ab24"}}}}
{"actor":{"display_login":"vkedia"}}