From 04cb899a59199d5e10cc8aaf2eef0e065fa63cf4 Mon Sep 17 00:00:00 2001 From: Richard Smedley Date: Wed, 3 Jun 2026 13:58:47 +0100 Subject: [PATCH 1/3] DOC-14413 Moved samples to devguide module --- .../examples/collections-concept.php | 27 - .../examples/documents-concept.php | 67 --- .../concept-docs/examples/n1ql-concept.php | 89 --- modules/concept-docs/pages/transactions.adoc | 8 +- modules/hello-world/examples/cloud.php | 51 -- modules/hello-world/examples/start-using.php | 47 -- .../hello-world/pages/start-using-sdk.adoc | 6 +- modules/howtos/examples/analytics.php | 81 --- modules/howtos/examples/auth.php | 32 -- modules/howtos/examples/batch.php | 52 -- .../howtos/examples/collection-manager.php | 88 --- modules/howtos/examples/connections.php | 8 - modules/howtos/examples/customer123.json | 24 - modules/howtos/examples/durability.php | 20 - modules/howtos/examples/errors.php | 83 --- modules/howtos/examples/kv-counter.php | 61 -- modules/howtos/examples/kv-crud.php | 144 ----- modules/howtos/examples/kv-expiry.php | 66 --- modules/howtos/examples/logging.php | 19 - .../howtos/examples/managing-connections.php | 36 -- modules/howtos/examples/orphan-logging.php | 62 -- .../provisioning-resources-buckets.php | 69 --- .../examples/provisioning-resources-users.php | 104 ---- .../howtos/examples/query-index-manager.php | 113 ---- modules/howtos/examples/query.php | 123 ---- modules/howtos/examples/search-facets.php | 205 ------- modules/howtos/examples/search.php | 193 ------- modules/howtos/examples/subdoc-concurrent.php | 46 -- modules/howtos/examples/subdoc-counters.php | 32 -- modules/howtos/examples/subdoc-lookupin.php | 62 -- .../examples/subdoc-mutatein-arrays.php | 84 --- .../examples/subdoc-mutatein-durability.php | 22 - modules/howtos/examples/subdoc-mutatein.php | 52 -- modules/howtos/examples/threshold-logging.php | 65 --- .../howtos/examples/transactions-example.php | 535 ------------------ modules/howtos/examples/transcoding.php | 113 ---- modules/howtos/examples/using-cas.php | 66 --- modules/howtos/pages/analytics-using-sdk.adoc | 12 +- .../collecting-information-and-logging.adoc | 2 +- .../howtos/pages/concurrent-async-apis.adoc | 4 +- .../pages/concurrent-document-mutations.adoc | 4 +- ...ibuted-acid-transactions-from-the-sdk.adoc | 32 +- modules/howtos/pages/error-handling.adoc | 16 +- .../pages/full-text-searching-with-sdk.adoc | 14 +- modules/howtos/pages/kv-operations.adoc | 40 +- .../howtos/pages/managing-connections.adoc | 10 +- .../howtos/pages/n1ql-queries-with-sdk.adoc | 14 +- .../pages/provisioning-cluster-resources.adoc | 20 +- modules/howtos/pages/sdk-authentication.adoc | 6 +- .../pages/sdk-user-management-example.adoc | 6 +- .../howtos/pages/slow-operations-logging.adoc | 10 +- .../howtos/pages/subdocument-operations.adoc | 46 +- modules/howtos/pages/transcoders-nonjson.adoc | 6 +- .../pages/vector-searching-with-sdk.adoc | 14 +- 54 files changed, 135 insertions(+), 3076 deletions(-) delete mode 100644 modules/concept-docs/examples/collections-concept.php delete mode 100644 modules/concept-docs/examples/documents-concept.php delete mode 100644 modules/concept-docs/examples/n1ql-concept.php delete mode 100644 modules/hello-world/examples/cloud.php delete mode 100644 modules/hello-world/examples/start-using.php delete mode 100644 modules/howtos/examples/analytics.php delete mode 100644 modules/howtos/examples/auth.php delete mode 100644 modules/howtos/examples/batch.php delete mode 100644 modules/howtos/examples/collection-manager.php delete mode 100644 modules/howtos/examples/connections.php delete mode 100644 modules/howtos/examples/customer123.json delete mode 100644 modules/howtos/examples/durability.php delete mode 100644 modules/howtos/examples/errors.php delete mode 100644 modules/howtos/examples/kv-counter.php delete mode 100644 modules/howtos/examples/kv-crud.php delete mode 100644 modules/howtos/examples/kv-expiry.php delete mode 100644 modules/howtos/examples/logging.php delete mode 100644 modules/howtos/examples/managing-connections.php delete mode 100644 modules/howtos/examples/orphan-logging.php delete mode 100644 modules/howtos/examples/provisioning-resources-buckets.php delete mode 100644 modules/howtos/examples/provisioning-resources-users.php delete mode 100644 modules/howtos/examples/query-index-manager.php delete mode 100644 modules/howtos/examples/query.php delete mode 100644 modules/howtos/examples/search-facets.php delete mode 100644 modules/howtos/examples/search.php delete mode 100644 modules/howtos/examples/subdoc-concurrent.php delete mode 100644 modules/howtos/examples/subdoc-counters.php delete mode 100644 modules/howtos/examples/subdoc-lookupin.php delete mode 100644 modules/howtos/examples/subdoc-mutatein-arrays.php delete mode 100644 modules/howtos/examples/subdoc-mutatein-durability.php delete mode 100644 modules/howtos/examples/subdoc-mutatein.php delete mode 100644 modules/howtos/examples/threshold-logging.php delete mode 100644 modules/howtos/examples/transactions-example.php delete mode 100644 modules/howtos/examples/transcoding.php delete mode 100644 modules/howtos/examples/using-cas.php diff --git a/modules/concept-docs/examples/collections-concept.php b/modules/concept-docs/examples/collections-concept.php deleted file mode 100644 index be781758..00000000 --- a/modules/concept-docs/examples/collections-concept.php +++ /dev/null @@ -1,27 +0,0 @@ -credentials('Administrator', 'password'); - -$cluster = new Cluster($connectionString, $options); -$bucket = $cluster->bucket('travel-sample'); - -$collectionMgr = $bucket->collections(); - -$spec = new CollectionSpec(); -$spec->setName('bookings'); -$spec->setScopeName('_default'); - -$collectionMgr->createCollection($spec); - -// tag::collections_1[] -$bucket->scope('_default')->collection('bookings'); -// end::collections_1[] - -// tag::collections_2[] -$bucket->scope('tenant_agent_00')->collection('bookings'); -// end::collections_2[] diff --git a/modules/concept-docs/examples/documents-concept.php b/modules/concept-docs/examples/documents-concept.php deleted file mode 100644 index 4413b742..00000000 --- a/modules/concept-docs/examples/documents-concept.php +++ /dev/null @@ -1,67 +0,0 @@ -credentials('Administrator', 'password'); - -$cluster = new Cluster($connectionString, $clusterOpts); -$bucket = $cluster->bucket('travel-sample'); -$collection = $bucket->scope('inventory')->collection('airline'); - -print("Example - [mutate-in]\n"); -// tag::mutate-in[] -$result = $collection->mutateIn('airline_10', [ - new MutateUpsertSpec('msrp', 18.00) -]); -// end::mutate-in[] - -print("Example - [lookup-in]\n"); -// tag::lookup-in[] -$usersCollection = $bucket->scope('tenant_agent_00')->collection('users'); -$usersCollection->lookupIn('1', [ - new LookupGetSpec('credit_cards[0].type'), - new LookupGetSpec('credit_cards[0].expiration') -]); -// end::lookup-in[] - -print("Example - [counters]\n"); -// tag::counters[] -$counterDocId = 'counter-doc'; -$decrementOpts = new DecrementOptions(); -$incrementOpts = new IncrementOptions(); -// Increment by 1, creating doc if needed. -// By using `initial(1)` we set the starting count(non-negative) to 1 if the document needs to be created. -// If it already exists, the count will increase by 1. -$collection->binary()->increment($counterDocId, $incrementOpts->initial(1)); -// Decrement by 1 -$collection->binary()->decrement($counterDocId); -// Decrement by 5 -$collection->binary()->decrement($counterDocId, $decrementOpts->delta(5)); -// end::counters[] - -print("Example - [counter-increment]\n"); -// tag::counter-increment[] -$result = $collection->get('counter-doc'); -$value = $result->content(); -$incrementAmnt = 5; - -if (shouldIncrementValue($value)) { - $opts = new ReplaceOptions(); - $opts->cas($result->cas()); - $collection->replace('counter-doc', $value + $incrementAmnt, $opts); -} -// end::counter-increment[] -printf("RESULT: %d", $value + $incrementAmnt); - -function shouldIncrementValue($value): bool { - printf("Current value: %d\n", $value); - return $value == 0; -} diff --git a/modules/concept-docs/examples/n1ql-concept.php b/modules/concept-docs/examples/n1ql-concept.php deleted file mode 100644 index 6a830cd0..00000000 --- a/modules/concept-docs/examples/n1ql-concept.php +++ /dev/null @@ -1,89 +0,0 @@ -credentials('Administrator', 'password'); - -$cluster = new Cluster($connectionString, $clusterOpts); -$bucket = $cluster->bucket('travel-sample'); -$collection = $bucket->scope('inventory')->collection('airline'); - -print("Example - [prepared-statement]\n"); -// tag::prepared-statement[] -$query = "SELECT count(*) FROM `travel-sample`.inventory.airport where country = $1"; -$opts = new QueryOptions(); -$opts->adhoc(false); -$opts->positionalParameters(['France']); - -$result = $cluster->query($query, $opts); -foreach ($result->rows() as $row) { - // do something -} -// end::prepared-statement[] - -print("Example - [create-index]\n"); -// tag::create-index[] -$mgr = $cluster->queryIndexes(); - -$mgr->createPrimaryIndex('travel-sample'); -$mgr->createIndex('travel-sample', 'ix_name', ['name']); -$mgr->createIndex('travel-sample', 'ix_email', ['email']); -// end::create-index[] - -dropIndexes($mgr); - -print("Example - [deferred-index]\n"); -// tag::deferred-index[] -$indexOpts = new CreateQueryIndexOptions(); -$primaryIndexOpts = new CreateQueryPrimaryIndexOptions(); - -$mgr->createPrimaryIndex('travel-sample', $primaryIndexOpts->deferred(true)); -$mgr->createIndex('travel-sample', 'ix_name', ['name'], $indexOpts->deferred(true)); -$mgr->createIndex('travel-sample', 'ix_email', ['email'], $indexOpts->deferred(true)); - -$indexesToBuild = $mgr->buildDeferredIndexes('travel-sample'); -$mgr->watchIndexes('travel-sample', $indexesToBuild, 2); -// end::deferred-index[] - -dropIndexes($mgr); - -print("Example - [index-consistency]\n"); -// tag::index-consistency[] -$random = rand(0, 10000000); -$userDoc = [ - 'name' => 'Brass Doorknob', - 'email' => 'brass.doorknob@juno.com', - 'random' => $random -]; - -$collection->upsert(sprintf("user:%d", $random), $userDoc); -$queryOpts = new QueryOptions(); -$cluster->query( - "SELECT name, email, random, META().id FROM `travel-sample`.inventory.airport WHERE $1 IN name", - $queryOpts->positionalParameters(['Brass']) -); -// end::index-consistency[] - -print("Example - [index-consistency-request-plus]\n"); -// tag::index-consistency-request-plus[] -$queryOpts->scanConsistency(QueryScanConsistency::REQUEST_PLUS); -$queryOpts->positionalParameters(['Brass']); -$cluster->query( - "SELECT name, email, random, META().id FROM `travel-sample`.inventory.airport WHERE $1 IN name", - $queryOpts, -); -// end::index-consistency-request-plus[] - -function dropIndexes($mgr) { - print("Dropping indexes...\n"); - $mgr->dropPrimaryIndex('travel-sample'); - $mgr->dropIndex('travel-sample', 'ix_name'); - $mgr->dropIndex('travel-sample', 'ix_email'); -} \ No newline at end of file diff --git a/modules/concept-docs/pages/transactions.adoc b/modules/concept-docs/pages/transactions.adoc index 1e83a962..45448f4b 100644 --- a/modules/concept-docs/pages/transactions.adoc +++ b/modules/concept-docs/pages/transactions.adoc @@ -20,7 +20,7 @@ include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tags=intro] [source,php] ---- -include::howtos:example$transactions-example.php[tag=create-simple,indent=0] +include::devguide:example$php/transactions-example.php[tag=create-simple,indent=0] ---- include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tags=mechanics;!library-cleanup-process] @@ -36,7 +36,7 @@ The application can use this to signal why it triggered a rollback, as so: [source,php] ---- -include::howtos:example$transactions-example.php[tag=rollback-cause,indent=0] +include::devguide:example$php/transactions-example.php[tag=rollback-cause,indent=0] ---- After a transaction is rolled back, it cannot be committed, no further operations are allowed on it, and the system will not try to automatically commit it at the end of the code block. @@ -56,14 +56,14 @@ include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tag=concurre // //[source,python] //---- -//include::howtos:example$transactions_example.py[tag=custom_metadata,indent=0] +//include::devguide:example$php/transactions_example.py[tag=custom_metadata,indent=0] //---- // //or at an individual transaction level with: // //[source,java] //---- -//include::howtos:example$transactions_example.py[tag=custom_metadata_per,indent=0] +//include::devguide:example$php/transactions_example.py[tag=custom_metadata_per,indent=0] //---- // //include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tag=integrated-sdk-custom-metadata-2] \ No newline at end of file diff --git a/modules/hello-world/examples/cloud.php b/modules/hello-world/examples/cloud.php deleted file mode 100644 index c41ea2ba..00000000 --- a/modules/hello-world/examples/cloud.php +++ /dev/null @@ -1,51 +0,0 @@ -.cloud.couchbase.com"; -$options = new ClusterOptions(); - -$options->credentials("username", "Password!123"); -// Sets a pre-configured profile called "wan_development" to help avoid latency issues -// when accessing Capella from a different Wide Area Network -// or Availability Zone (e.g. your laptop). -$options->applyProfile("wan_development"); -$cluster = new Cluster($connectionString, $options); -// end::connect[] - -// tag::bucket[] -// get a bucket reference -$bucket = $cluster->bucket("travel-sample"); -// end::bucket[] - -// tag::collection[] -// get a user-defined collection reference -$scope = $bucket->scope("tenant_agent_00"); -$collection = $scope->collection("users"); -// end::collection[] - -// tag::upsert-get[] -$upsertResult = $collection->upsert("my-document-key", ["name" => "Ted", "Age" => 31]); - -$getResult = $collection->get("my-document-key"); - -print_r($getResult->content()); -// end::upsert-get[] - -// tag::n1ql-query[] -$inventoryScope = $bucket->scope("inventory"); -$queryResult = $inventoryScope->query("SELECT * FROM airline WHERE id = 10"); - -// Print result data to the terminal. -foreach ($queryResult->rows() as $row) { - print_r($row); -} -// end::n1ql-query[] diff --git a/modules/hello-world/examples/start-using.php b/modules/hello-world/examples/start-using.php deleted file mode 100644 index 93854327..00000000 --- a/modules/hello-world/examples/start-using.php +++ /dev/null @@ -1,47 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster($connectionString, $options); -// end::connect[] - -// tag::bucket[] -// get a bucket reference -$bucket = $cluster->bucket("travel-sample"); -// end::bucket[] - -// tag::collection[] -// get a user-defined collection reference -$scope = $bucket->scope("tenant_agent_00"); -$collection = $scope->collection("users"); -// end::collection[] - -// tag::upsert-get[] -$upsertResult = $collection->upsert("my-document-key", ["name" => "Ted", "Age" => 31]); - -$getResult = $collection->get("my-document-key"); - -print_r($getResult->content()); -// end::upsert-get[] - -// tag::n1ql-query[] -$inventoryScope = $bucket->scope("inventory"); -$queryResult = $inventoryScope->query("SELECT * FROM airline WHERE id = 10"); - -// Print result data to the terminal. -foreach ($queryResult->rows() as $row) { - print_r($row); -} -// end::n1ql-query[] diff --git a/modules/hello-world/pages/start-using-sdk.adoc b/modules/hello-world/pages/start-using-sdk.adoc index 5a4a1dce..d17b4824 100644 --- a/modules/hello-world/pages/start-using-sdk.adoc +++ b/modules/hello-world/pages/start-using-sdk.adoc @@ -33,7 +33,7 @@ If you are connecting to https://docs.couchbase.com/cloud/index.html[Couchbase C [source,php] ---- -include::hello-world:example$cloud.php[tags=**] +include::devguide:example$php/cloud.php[tags=**] ---- The Couchbase Capella free tier version comes with the Travel Sample Bucket, and its Query indexes, loaded and ready. @@ -44,7 +44,7 @@ Local Couchbase Server:: -- [source,php] ---- -include::hello-world:example$start-using.php[tags=**] +include::devguide:example$php/start-using.php[tags=**] ---- As well as the PHP SDK (see below), and a running instance of Couchbase Server, you will need to load up the Travel Sample Bucket @@ -164,7 +164,7 @@ Firstly, you will need to have a few `import` statements at the top of your PHP [#imports] [source,php] ---- -include::hello-world:example$start-using.php[tag=imports] +include::devguide:example$php/start-using.php[tag=imports] ---- === Connect diff --git a/modules/howtos/examples/analytics.php b/modules/howtos/examples/analytics.php deleted file mode 100644 index 6d1c0f80..00000000 --- a/modules/howtos/examples/analytics.php +++ /dev/null @@ -1,81 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new \Couchbase\Cluster($connectionString, $options); - -$bucket = $cluster->bucket("travel-sample"); - -// #tag::query[] -$options = new \Couchbase\AnalyticsOptions(); -$result = $cluster->analyticsQuery('SELECT "hello" as greeting;', $options); - -foreach ($result->rows() as $row) { - printf("result: %s\n", $row["greeting"]); -} -// #end::query[] - -// #tag::simple[] -$options = new \Couchbase\AnalyticsOptions(); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); -// #end::simple[] - -// #tag::positional[] -$options = new \Couchbase\AnalyticsOptions(); -$options->positionalParameters(["France"]); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = $1;', $options); -// #end::positional[] - -// #tag::named[] -$options = new \Couchbase\AnalyticsOptions(); -$options->namedParameters(['$country' => "France"]); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = $country;', $options); -// #end::named[] - -// #tag::options[] -$options = new \Couchbase\AnalyticsOptions(); -$options->timeout(100); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); -// #end::options[] - -// #tag::results[] -$options = new \Couchbase\AnalyticsOptions(); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); - -foreach ($result->rows() as $row) { - printf("Name: %s, Country: %s\n", $row["airportname"], $row["country"]); -} -// #end::results[] - -// #tag::metadata[] -$options = new \Couchbase\AnalyticsOptions(); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); - -$metadata = $result->metadata(); -$metrics = $metadata->metrics(); -printf("Elapsed time: %d\n", $metrics["elapsedTime"]); -printf("Execution time: %d\n", $metrics["executionTime"]); -printf("Result count: %d\n", $metrics["resultCount"]); -// #tag::metadata[] - -// tag::handle-collection[] -$options = new \Couchbase\AnalyticsOptions(); -$result = $cluster->analyticsQuery( - 'SELECT airportname, country FROM `travel-sample`.inventory.airport WHERE country = "France" LIMIT 3;', - $options -); - -foreach ($result->rows() as $row) { - printf("Name: %s, Country: %s\n", $row["airportname"], $row["country"]); -} -// end::handle-collection[] - -// tag::handle-scope[] -$scope = $bucket->scope("inventory"); -$options = new \Couchbase\AnalyticsOptions(); -$result = $cluster->analyticsQuery('SELECT airportname, country FROM `airports` WHERE country = "France" LIMIT 2;', $options); - -foreach ($result->rows() as $row) { - printf("Name: %s, Country: %s\n", $row["airportname"], $row["country"]); -} -// end::handle-scope[] diff --git a/modules/howtos/examples/auth.php b/modules/howtos/examples/auth.php deleted file mode 100644 index 4632e265..00000000 --- a/modules/howtos/examples/auth.php +++ /dev/null @@ -1,32 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $options); -$bucket = $cluster->bucket("travel-sample"); -// end::auth1[] - -// tag::auth2[] -$options = new ClusterOptions(); -$options->credentials("Administrator", "password"); - -# authentication with TLS client certificate -$connectionString = "couchbases://localhost?" . - "truststorepath=/path/to/ca/certificates.pem&" . - "certpath=/path/to/client/certificate.pem&" . - "keypath=/path/to/client/key.pem"; - -$cluster = new Cluster($connectionString, $options); -$bucket = $cluster->bucket("travel-sample"); -// end::auth2[] - -// tag::auth3[] -$options = new ClusterOptions(); -$options->credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost?sasl_mech_force=PLAIN", $options); -$bucket = $cluster->bucket("travel-sample"); -// end::auth3[] diff --git a/modules/howtos/examples/batch.php b/modules/howtos/examples/batch.php deleted file mode 100644 index 16b3f91f..00000000 --- a/modules/howtos/examples/batch.php +++ /dev/null @@ -1,52 +0,0 @@ -credentials("Administrator", "password"); - $cluster = new Cluster("couchbase://localhost", $options); - $collection = $cluster->bucket("travel-sample")->scope("inventory")->collection("airport"); - foreach ($batch as $path) { - $collection->upsert($path, json_decode(file_get_contents($path))); - } -} -// #end::batching[] diff --git a/modules/howtos/examples/collection-manager.php b/modules/howtos/examples/collection-manager.php deleted file mode 100644 index 89a10b9e..00000000 --- a/modules/howtos/examples/collection-manager.php +++ /dev/null @@ -1,88 +0,0 @@ -credentials("Administrator", "password"); - $cluster = new \Couchbase\Cluster($connectionString, $options); - - $bucket = $cluster->bucket("travel-sample"); - - - print "scopeAdmin\n"; - // tag::scopeAdmin[] - $users = $cluster->users(); - - $user = new \Couchbase\User(); - $user->setUsername("scopeAdmin"); - $user->setDisplayName("Manage Scopes [travel-sample]"); - $user->setPassword("password"); - $user->setRoles([ - (new \Couchbase\Role)->setName("scope_admin")->setBucket("travel-sample"), - (new \Couchbase\Role)->setName("data_reader")->setBucket("travel-sample") - ]); - - $users->upsertUser($user); - // end::scopeAdmin[] - - print "create-collection-manager\n"; - - // tag::create-collection-manager[] - $options = new \Couchbase\ClusterOptions(); - $options->credentials("scopeAdmin", "password"); - $cluster = new \Couchbase\Cluster("localhost", $options); - $bucket = $cluster->bucket("travel-sample"); - - $collections = $bucket->collections(); - // end::create-collection-manager[] - - print "create-scope\n"; - // tag::create-scope[] - try { - $collections->createScope("example-scope"); - } - catch (Exception $e) { - print $e; - } - // end::create-scope[] - - print "create-collection\n"; - // tag::create-collection[] - $collection = new \Couchbase\CollectionSpec(); - $collection->setName("example-collection"); - $collection->setScopeName("example-scope"); - - try { - $collections->createCollection($collection); - } - catch (Exception $e) { - print $e; - } - // end::create-collection[] - - print "listing-scope-collection\n"; - // tag::listing-scope-collection[] - $scopes = $collections->getAllScopes(); - foreach ($scopes as $scope) { - print "Scope {$scope->name()}\n"; - - foreach ($scope->collections() as $collection) { - print " - {$collection->name()}\n"; - } - } - // end::listing-scope-collection[] - - print "drop-collection\n"; - // tag::drop-collection[] - $collections->dropCollection($collection); - // end::drop-collection[] - - print "drop-scope\n"; - // tag::drop-scope[] - $collections->dropScope("example-scope"); - // end::drop-scope[] - -} - -main(); - diff --git a/modules/howtos/examples/connections.php b/modules/howtos/examples/connections.php deleted file mode 100644 index e9b745f5..00000000 --- a/modules/howtos/examples/connections.php +++ /dev/null @@ -1,8 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new \Couchbase\Cluster($connectionString, $opts); -// end::rbac[] diff --git a/modules/howtos/examples/customer123.json b/modules/howtos/examples/customer123.json deleted file mode 100644 index 1d7c72e8..00000000 --- a/modules/howtos/examples/customer123.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "Douglas Reynholm", - "email": "douglas@reynholmindustries.com", - "addresses": { - "billing": { - "line1": "123 Any Street", - "line2": "Anytown", - "country": "United Kingdom" - }, - "delivery": { - "line1": "123 Any Street", - "line2": "Anytown", - "country": "United Kingdom" - } - }, - "purchases": { - "complete": [ - 339, 976, 442, 666 - ], - "abandoned": [ - 157, 42, 999 - ] - } -} diff --git a/modules/howtos/examples/durability.php b/modules/howtos/examples/durability.php deleted file mode 100644 index 55b1e7f9..00000000 --- a/modules/howtos/examples/durability.php +++ /dev/null @@ -1,20 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("inventory")->collection("airport"); - -// #tag::enhanced[] -$document = ["foo" => "bar", "bar" => "foo"]; -// Upsert with Durability level Majority -$opts = new UpsertOptions(); -$opts->durabilityLevel(DurabilityLevel::MAJORITY); -$res = $collection->upsert("durable-key", $document, $opts); -printf("Successfully created document \"durable-key\". CAS=\"%s\"\n", $res->cas()); -// #end::enhanced[] diff --git a/modules/howtos/examples/errors.php b/modules/howtos/examples/errors.php deleted file mode 100644 index c17e3249..00000000 --- a/modules/howtos/examples/errors.php +++ /dev/null @@ -1,83 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("inventory")->collection("airport"); - - -// tag::document-not-found-exception[] -try { - $collection->get("foo"); -} catch (\Couchbase\Exception\DocumentNotFoundException $ex) { - printf("Document does not exist, creating. \n"); - $collection->upsert("foo", ["bar" => 42]); -} -// end::document-not-found-exception[] - - -// tag::key-exists-exception[] -try { - $collection->insert("foo", ["bar" => 43]); -} catch (\Couchbase\KeyExistsException $ex) { - printf("Document already exists. \n"); -} -// end::key-exists-exception[] - -$max_size = 1024 * 1024 * 20; # 20MB -$big_object = str_repeat(' ', $max_size + 1); - -// tag::value-too-big-exception[] -try { - $collection->insert("big", $big_object); -} catch (\Couchbase\ValueTooBigException $ex) { - printf("Document is bigger than maximum size (20MB). \n"); -} -// end::value-too-big-exception[] - - -// tag::cas-mismatch-exception[] -$result1 = $collection->get("foo"); -$original_cas = $result1->cas(); - -$opts = new \Couchbase\ReplaceOptions(); - -$result2 = $collection->replace("foo", - ["bar" => 44], - $opts->cas($original_cas)); -$updated_cas = $result2->cas(); - -try { - $collection->replace("foo", - ["bar" => 45], - $opts->cas($original_cas)); - # oops, we should have used $updated_cas! -} catch (\Couchbase\Exception\CasMismatchException $ex) { - printf("CAS mismatch error. \n"); -} -// end::cas-mismatch-exception[] - - -// tag::retry[] -$max_attempts = 5; -for ($attempt = 1; $attempt <= $max_attempts; $attempt++) { - printf("Attempt $attempt. \n"); - try { - $result = $collection->get("expected-document"); - break; - } - catch (\Couchbase\Exception\DocumentNotFoundException $ex) { - printf("Document still not created. \n"); - usleep(100); - continue; - } - catch (\Couchbase\NetworkException $ex) { - printf("An unrecoverable network exception happened! \n"); - break; - } -} -// end::retry[] diff --git a/modules/howtos/examples/kv-counter.php b/modules/howtos/examples/kv-counter.php deleted file mode 100644 index 221f0595..00000000 --- a/modules/howtos/examples/kv-counter.php +++ /dev/null @@ -1,61 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->defaultCollection(); - -$collection->upsert("foo", 0); -// tag::increment[] -// increment binary value by 1 (default) -$binaryCollection = $collection->binary(); -$res = $binaryCollection->increment("foo"); -// end::increment[] - -// tag::decrement[] -// decremtnt binary value by 1 (default) -$res = $binaryCollection->decrement("foo"); -// end::decrement[] - -// Increment & Decrement are considered part of the 'binary' API -// and as such may still be a subject to change - -// tag::incrementwithoptions[] -// Create a document and assign it to 10 -- counter works atomically -// by first creating a document if it doesn't exist. If it exists, -// the same method will increment/decrement per the "delta" parameter -$key = "phpDevguideExampleCounter"; -$opts = new IncrementOptions(); -$opts->initial(10)->delta(2); - -$res = $binaryCollection->increment($key, $opts); -// Should print 10 -printf("Initialized Counter: %d\n", $res->content()); -// end::incrementwithoptions[] - -// Issue the same operation, increment value by 2 to 12 -$res = $binaryCollection->increment($key, $opts); -// Should print 12 -printf("Incremented Counter: %d\n", $res->content()); - -// tag::decrementwithoptions[] -$opts = new DecrementOptions(); -$opts->initial(10)->delta(4); -// Decrement value by 4 to 8 -$res = $binaryCollection->decrement($key, $opts); -// Should print 8 -printf("Decremented Counter: %d\n", $res->content()); -// end::decrementwithoptions[] - -// Output: -// -// Initialized Counter: 10 -// Incremented Counter: 12 -// Decremented Counter: 8 diff --git a/modules/howtos/examples/kv-crud.php b/modules/howtos/examples/kv-crud.php deleted file mode 100644 index 53ebf71c..00000000 --- a/modules/howtos/examples/kv-crud.php +++ /dev/null @@ -1,144 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->defaultCollection(); - -// tag::insert[] -$document = ["foo" => "bar", "bar" => "foo"]; -$res = $collection->insert("document-key-new", $document); -printf("document \"document-key-new\" has been created with CAS \"%s\"\n", $res->cas()); -// end::insert[] - -// Insert document with options -// tag::insertwithoptions[] -$document = ["foo" => "bar", "bar" => "foo"]; -$opts = new InsertOptions(); -$opts->timeout(300000 /* milliseconds */); -$res = $collection->insert("document-key", $document, $opts); -printf("document \"document-key\" has been created with CAS \"%s\"\n", $res->cas()); -// end::insertwithoptions[] - -// tag::replacewithcas[] -// Replace document with incorrect CAS -$opts = new ReplaceOptions(); -$opts->timeout(300000 /* milliseconds */); -$invalidCas = "776t3gAAAAA="; -$opts->cas($invalidCas); -try { - $collection->replace("document-key", $document, $opts); -} catch (\Couchbase\Exception\CasMismatchException $ex) { - printf("document \"document-key\" cannot be replaced with CAS \"%s\"\n", $invalidCas); -} - -// Get and Replace document with CAS -$res = $collection->get("document-key"); -$doc = $res->content(); -$doc["bar"] = "moo"; - -$opts = new ReplaceOptions(); -$oldCas = $res->cas(); -$opts->cas($oldCas); -$res = $collection->replace("document-key", $doc, $opts); -printf("document \"document-key\" \"%s\" been replaced successfully. New CAS \"%s\"\n", $oldCas, $res->cas()); -// end::replacewithcas[] - -// tag::removewithoptions[] -$opts = new RemoveOptions(); -$opts->timeout(5000); // 5 seconds -$result = $collection->remove("document-key", $opts); -printf("document \"document-key\" \"%s\" been removed successfully.\n", $res->cas()); -// end::removewithoptions[] - -// tag::upsertwithexpiry[] -$document = ["foo" => "bar", "bar" => "foo"]; -$opts = new UpsertOptions(); -$opts->expiry(60 * 1000 /* 60 seconds */); -$res = $collection->upsert("document-key", $document, $opts); -printf("document \"document-key\" has been created with CAS \"%s\"\n", $res->cas()); -// end::upsertwithexpiry[] - -// Get -// tag::get[] -$res = $collection->get("document-key"); -$doc = $res->content(); -printf("document \"document-key\" has content: \"%s\" CAS \"%s\"\n", json_encode($doc), $res->cas()); -// end::get[] - -// tag::getwithoptions[] -$opts = new GetOptions(); -$opts->timeout(3000 /* milliseconds */); -$res = $collection->get("document-key", $opts); -$doc = $res->content(); -printf("document \"document-key\" has content: \"%s\" CAS \"%s\"\n", json_encode($doc), $res->cas()); -// end::getwithoptions[] - -// tag::upsertwithdurability[] -// Upsert with Durability -$opts = new UpsertOptions(); -$opts->timeout(3000 /* milliseconds */); -$opts->durabilityLevel(DurabilityLevel::MAJORITY); -$res = $collection->upsert("document-key2", $opts); -printf("document \"document-key2\" has been created with CAS \"%s\"\n", $res->cas()); -// end::upsertwithdurability[] - -// tag::namedcollectionupsert[] -$document = ["name" => "John Doe", "preferred_email" => "johndoe111@test123.test"]; -$opts = new UpsertOptions(); - -$agentScope = $bucket->scope("tenant_agent_00"); -$usersCollection = $agentScope->collection("users"); - -$res = $usersCollection->upsert("user-key", $document, $opts); -printf("document \"user-key\" has been created with CAS \"%s\"\n", $res->cas()); -// end::namedcollectionupsert[] - -// Cleanup example data to avoid errors when running locally (mainly for inserts). -$opts = new RemoveOptions(); -$collection->remove("document-key-new", $opts); -$collection->remove("document-key", $opts); - -// tag::rangescanalldocuments[] -$results = $collection->scan(RangeScan::build()); -foreach ($results as $result) { - printf("\n ID: %s, content:\n ", $result->id()); - print_r($result->content()); -} -// end::rangescanalldocuments[] -// tag::rangescanalldocumentids[] -$results = $collection->scan(RangeScan::build(), ScanOptions::build()->idsOnly(true)); -foreach ($results as $result) { - printf("ID: %s \n", $result->id()); -} -// end::rangescanalldocumentids[] -// tag::rangescanprefix[] -$results = $collection->scan(PrefixScan::build("alice::")); -foreach ($results as $result) { - printf("\n ID: %s, content:\n ", $result->id()); - print_r($result->content()); -} - -// end::rangescanprefix[] - -// tag::rangescansample[] -$results = $collection->scan(SamplingScan::build(100)); -foreach ($results as $result) { - printf("\n ID: %s, content:\n ", $result->id()); - print_r($result->content()); -} -// end::rangescansample[] diff --git a/modules/howtos/examples/kv-expiry.php b/modules/howtos/examples/kv-expiry.php deleted file mode 100644 index 3ee0e590..00000000 --- a/modules/howtos/examples/kv-expiry.php +++ /dev/null @@ -1,66 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->defaultCollection(); - -$document = [ - "foo" => "bar", - "bar" => "foo", -]; - -$key = "document-key"; - -// Upsert with Expiry -$opts = new UpsertOptions(); -$opts->expiry(60 /* seconds */); -$res = $collection->upsert($key, $document, $opts); - -// Retrieve the document immediately, must be exist -$res = $collection->get($key); -printf("[get] document content: %s\n", var_export($res->content(), true)); - -// Touch the document to adjust expiration time -// tag::touch[] -$collection->touch($key, 60 /* seconds */); -// end::touch[] - -// Touch the document to adjust expiration time -// tag::touchwithoptions[] -$opts = new TouchOptions(); -$opts->timeout(500000 /* microseconds */); -$collection->touch($key, 60 /* seconds */); -// end::touchwithoptions[] - -// Get and touch retrieves the document and adjusting expiration time -// tag::getandtouch[] -$res = $collection->getAndTouch($key, 1 /* seconds */); -printf("[getAndTouch] document content: %s\n", var_export($res->content(), true)); - -sleep(2); // wait until the document will expire - -try { - $collection->get($key); -} catch (Couchbase\Exception\DocumentNotFoundException $ex) { - printf("The document does not exist\n"); -} -// end::getandtouch[] - -// Output: -// -// [get] document content: array ( -// 'foo' => 'bar', -// 'bar' => 'foo', -// ) -// [getAndTouch] document content: array ( -// 'foo' => 'bar', -// 'bar' => 'foo', -// ) -// The document does not exist diff --git a/modules/howtos/examples/logging.php b/modules/howtos/examples/logging.php deleted file mode 100644 index ed975807..00000000 --- a/modules/howtos/examples/logging.php +++ /dev/null @@ -1,19 +0,0 @@ -credentials("Administrator", "password"); - -$cluster = new Cluster('couchbase://localhost', $options); -$bucket = $cluster->bucket('travel-sample'); - -$collection = $bucket->scope('inventory')->collection('airline'); -$getResult = $collection->get('airline_10'); - -print_r($getResult->content()); -// end::logging[] diff --git a/modules/howtos/examples/managing-connections.php b/modules/howtos/examples/managing-connections.php deleted file mode 100644 index 2d124b5b..00000000 --- a/modules/howtos/examples/managing-connections.php +++ /dev/null @@ -1,36 +0,0 @@ -credentials("Administrator", "password"); - -$connectionString = "couchbase://10.112.210.101,10.112.210.102"; -$cluster = new Cluster($connectionString, $opts); -// end::multiplenodes[] - -// tag::customPorts[] -$opts = new ClusterOptions(); -$opts->credentials("Administrator", "password"); - -$connectionString = "couchbase://192.168.42.101:12000,192.168.42.102:12002"; -$cluster = new Cluster($connectionString, $opts); -// end::customPorts[] - -// tag::tls[] -$opts = new ClusterOptions(); -$opts->credentials("Administrator", "password"); - -$connectionString = "couchbases://localhost?trust_certificate=/path/to/ca/certificates.pem"; -$cluster = new Cluster($connectionString, $opts); -// end::tls[] - -// tag::dnssrv[] -$opts = new ClusterOptions(); -$opts->credentials("Administrator", "password"); - -$connectionString = "couchbase://couchbase.example.com"; -$cluster = new Cluster($connectionString, $opts); -// end::dnssrv[] diff --git a/modules/howtos/examples/orphan-logging.php b/modules/howtos/examples/orphan-logging.php deleted file mode 100644 index 813e3c8b..00000000 --- a/modules/howtos/examples/orphan-logging.php +++ /dev/null @@ -1,62 +0,0 @@ -credentials("Administrator", "password"); - -// tag::orphanLogging[] -$connectionString = "couchbase://127.0.0.1?" . - "tracing_orphaned_queue_flush_interval=5&"; /* every 5 seconds */ - -$cluster = new Cluster($connectionString, $options); -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->scope("inventory")->collection("airport"); -// end::orphanLogging[] - -// tag::orphanTimeout[] -/* - * Create a new document - */ -$document = ["answer" => 42, "updated_at" => date("r")]; -$collection->upsert("foo", $document); - -/* - * Replace the document with a big body and very small deadline which should trigger a - * client-side timeout, in which case the server response will be reported as orphan - */ -$options = new UpsertOptions(); -$options->timeout(1); -/* - * Generate a document with 10M payload, that should be unfriendly to the compressing function - * and longer to process on the server side - */ -$document = ["noise" => base64_encode(random_bytes(15_000_000))]; -$numberOfTimeouts = 0; -while (true) { - try { - $collection->upsert("foo", $document, $options); - } catch (TimeoutException $e) { - $numberOfTimeouts++; - if ($numberOfTimeouts > 3) { - break; - } - } -} -// end::orphanTimeout[] - -/* - * Messages like one below will appear in the log for the orphaned response - * - * [cb,WARN] (tracer L:147 I:2929787644) Orphan responses observed: {"count":2,"service":"kv","top":[{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x11","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":0,"total_us":34904},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0xb","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":0,"total_us":32195}]} - */ diff --git a/modules/howtos/examples/provisioning-resources-buckets.php b/modules/howtos/examples/provisioning-resources-buckets.php deleted file mode 100644 index 95ee5c1f..00000000 --- a/modules/howtos/examples/provisioning-resources-buckets.php +++ /dev/null @@ -1,69 +0,0 @@ -credentials("Administrator", "password"); - $cluster = new Cluster($connectionString, $options); - - $bucketMgr = $cluster->buckets(); - // end::creating-bucket-mgr[] - - createBucket($bucketMgr); - updateBucket($bucketMgr); - // The examples can run quite fast, wait a few seconds before flushing. - sleep(5); - flushBucket($bucketMgr); - removeBucket($bucketMgr); -} - -function createBucket($bucketMgr) -{ - // tag::create-bucket[] - $settings = new BucketSettings("hello"); - $settings->enableFlush(false); - $settings->enableReplicaIndexes(false); - $settings->setRamQuotaMb(150); - $settings->setNumReplicas(1); - $settings->setBucketType(BucketType::COUCHBASE); - $settings->conflictResolutionType(ConflictResolutionType::SEQUENCE_NUMBER); - - $bucketMgr->createBucket($settings); - // end::create-bucket[] -} - -function updateBucket($bucketMgr) -{ - // tag::update-bucket[] - $settings = $bucketMgr->getBucket("hello"); - $settings->enableFlush(true); - - $bucketMgr->updateBucket($settings); - // end::update-bucket[] -} - -function flushBucket($bucketMgr) -{ - // tag::flush-bucket[] - $bucketMgr->flush("hello"); - // end::flush-bucket[] -} - -function removeBucket($bucketMgr) -{ - // tag::remove-bucket[] - $bucketMgr->dropBucket("hello"); - // end::remove-bucket[] -} - -main(); diff --git a/modules/howtos/examples/provisioning-resources-users.php b/modules/howtos/examples/provisioning-resources-users.php deleted file mode 100644 index c2c4e071..00000000 --- a/modules/howtos/examples/provisioning-resources-users.php +++ /dev/null @@ -1,104 +0,0 @@ -credentials("Administrator", "password"); - $adminCluster = new Cluster("couchbase://localhost", $options); - - $userMgr = $adminCluster->users(); - - createUser($userMgr); - sleep(2); // Give user creation some time to settle before getAllUsers() call. - getAllUsers($userMgr); - userOperations(); -} - -function createUser($userMgr) -{ - // tag::create-user[] - $roles = [ - // Roles required for reading data from bucket - Role::build()->setName("data_reader")->setBucket("*"), - Role::build()->setName("query_select")->setBucket("*"), - // Roles required for writing data to bucket - Role::build()->setName("data_writer")->setBucket("travel-sample"), - Role::build()->setName("query_insert")->setBucket("travel-sample"), - Role::build()->setName("query_delete")->setBucket("travel-sample"), - // Roles required for idx creation on bucket - Role::build()->setName("query_manage_index")->setBucket("travel-sample"), - ]; - - $user = new User(); - $user->setUsername("test-user"); - $user->setDisplayName("Test User"); - $user->setRoles($roles); - $user->setPassword("test-passw0rd!"); - - $userMgr->upsertUser($user); - // end::create-user[] -} - -function getAllUsers($userMgr) -{ - // tag::get-all-users[] - $userMetadata = $userMgr->getAllUsers(); - foreach ($userMetadata as &$u) { - printf("User's display name: %s\n", $u->user()->displayName()); - - $userRoles = $u->user()->roles(); - foreach ($userRoles as &$role) { - printf("\tUser has role %s, applicable to bucket %s\n", $role->name(), $role->bucket()); - } - } - // end::get-all-users[] -} - -function userOperations() -{ - # tag::user-operations[] - $options = new ClusterOptions(); - $options->credentials("test-user", "test-passw0rd!"); - $userCluster = new Cluster("couchbase://localhost", $options); - - # For Server versions 6.5 or later you do not need to open a bucket here - $userBucket = $userCluster->bucket("travel-sample"); - $collection = $userBucket->defaultCollection(); - - # create primary idx for testing purposes - $createPrimaryQueryIndexOpts = new CreateQueryPrimaryIndexOptions(); - $createPrimaryQueryIndexOpts->ignoreIfExists(true); - - $userCluster->queryIndexes()->createPrimaryIndex("travel-sample", $createPrimaryQueryIndexOpts); - - # test k/v operations - $airline10 = $collection->get("airline_10"); - printf("Airline 10: %s", $airline10->contentAs(RawJsonTranscoder::getInstance())); - - $airline11 = [ - "callsign" => "MILE-AIR", - "iata" => "Q5", "id" => 11, - "name" => "40-Mile Air", - "type" => "airline" - ]; - $collection->upsert("airline11", $airline11); - - # test query operations - $queryResult = $userCluster->query("SELECT * FROM `travel-sample` LIMIT 5;"); - foreach ($queryResult->rows() as &$row) { - print("\nQuery Row:\n"); - print_r($row); - } - # end::user-operations[] -} - -main(); diff --git a/modules/howtos/examples/query-index-manager.php b/modules/howtos/examples/query-index-manager.php deleted file mode 100644 index 34fde0ad..00000000 --- a/modules/howtos/examples/query-index-manager.php +++ /dev/null @@ -1,113 +0,0 @@ -credentials("Administrator", "password"); - $cluster = new Cluster("couchbase://localhost", $options); - - $queryIndexMgr = $cluster->queryIndexes(); - // end::creating-index-mgr[] - - primaryIndex($queryIndexMgr); - secondaryIndex($queryIndexMgr); - deferAndWatchIndex($queryIndexMgr); - dropPrimaryIndex($queryIndexMgr); -} - -function primaryIndex($queryIndexMgr) -{ - print "Example - [primary]\n"; - // tag::primary[] - $options = new CreateQueryPrimaryIndexOptions(); - $options->scopeName("tenant_agent_01"); - $options->collectionName("users"); - // Set this if you wish to use a custom name - // $options->indexName("custom_name"); - $options->ignoreIfExists(true); - - $queryIndexMgr->createPrimaryIndex("travel-sample", $options); - // end::primary[] -} - -function secondaryIndex($queryIndexMgr) -{ - print "\nExample - [secondary]\n"; - try { - // tag::secondary[] - $options = new CreateQueryIndexOptions(); - $options->scopeName("tenant_agent_01"); - $options->collectionName("users"); - - $queryIndexMgr->createIndex("travel-sample", "tenant_agent_01_users_email", ["preferred_email"], $options); - // end::secondary[] - } catch (Couchbase\Exception\IndexExistsException) { - print "Index already exists\n"; - } -} - -function deferAndWatchIndex($queryIndexMgr) -{ - print "\nExample - [defer-indexes]\n"; - try { - // tag::defer-indexes[] - // Create a deferred index - $createOpts = new CreateQueryIndexOptions(); - $createOpts->scopeName("tenant_agent_01"); - $createOpts->collectionName("users"); - $createOpts->deferred(true); - - $queryIndexMgr->createIndex("travel-sample", "tenant_agent_01_users_phone", ["preferred_phone"], $createOpts); - - // Build any deferred indexes within `travel-sample`.tenant_agent_01.users - $deferredOpts = new BuildQueryIndexesOptions(); - $deferredOpts->scopeName("tenant_agent_01"); - $deferredOpts->collectionName("users"); - - $queryIndexMgr->buildDeferredIndexes("travel-sample", $deferredOpts); - - // Wait for indexes to come online - $watchOpts = new WatchQueryIndexesOptions(); - $watchOpts->scopeName("tenant_agent_01"); - $watchOpts->collectionName("users"); - - $queryIndexMgr->watchIndexes("travel-sample", ["tenant_agent_01_users_phone"], 30000, $watchOpts); - // end::defer-indexes[] - } catch (Couchbase\Exception\IndexExistsException) { - print "Index already exists\n"; - } -} - -function dropPrimaryIndex($queryIndexMgr) -{ - print "\nExample - [drop-primary-or-secondary-index]\n"; - // tag::drop-primary-or-secondary-index[] - // Drop a primary index - $options = new DropQueryPrimaryIndexOptions(); - $options->scopeName("tenant_agent_01"); - $options->collectionName("users"); - - $queryIndexMgr->dropPrimaryIndex("travel-sample", $options); - - // Drop a secondary index - $options = new DropQueryIndexOptions(); - $options->scopeName("tenant_agent_01"); - $options->collectionName("users"); - - $queryIndexMgr->dropIndex("travel-sample", "tenant_agent_01_users_email", $options); - // end::drop-primary-or-secondary-index[] -} - -main(); diff --git a/modules/howtos/examples/query.php b/modules/howtos/examples/query.php deleted file mode 100644 index 9ffc8c83..00000000 --- a/modules/howtos/examples/query.php +++ /dev/null @@ -1,123 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $options); - -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->scope("inventory")->collection("hotel"); - -// tag::positionalParams[] -$options = new QueryOptions(); -$options->positionalParameters(["France"]); -// NOTE: string is single-quoted to avoid PHP variable substitutions and pass '$1' as is -$result = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`=$1 LIMIT 10;', $options); -// end::positionalParams[] - -// tag::namedParams[] -$options = new QueryOptions(); -$options->namedParameters(['country' => "France"]); -$result = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`=$country LIMIT 10;', $options); -// end::namedParams[] - -// tag::results[] -$options = new QueryOptions(); -$options->positionalParameters(["France"]); -$result = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`=$1 LIMIT 10;', $options); - -foreach ($result->rows() as $row) { - printf("Name: %s, Address: %s, Description: %s\n", $row["name"], $row["address"], $row["description"]); -} -// end::results[] - -// tag::scan[] -$query = 'SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`="France" LIMIT 10'; -$opts = new QueryOptions(); -$opts->scanConsistency(QueryScanConsistency::REQUEST_PLUS); -$res = $cluster->query($query, $opts); -// end::scan[] -$idx = 1; -foreach ($res->rows() as $row) { - printf("%d. %s, \"%s\"\n", $idx++, $row['country'], $row['name']); -} -// tag::metrics[] -printf("Execution Time: %d\n", $res->metaData()->metrics()['executionTime']); -// end::metrics[] - -// NOTE: This currently fails with Couchbase Internal Server error. -// Server issue tracked here: https://issues.couchbase.com/browse/MB-46876 -// Add back in once Couchbase Server 7.0.1 is available, which will fix this issue. -// tag::consistentWith[] -// create/update document (mutation) -//$res = $collection->upsert("id", ["name" => "somehotel", "type" => "hotel"]); -// -//// create mutation state from mutation results -//$state = new MutationState(); -//$state->add($res); -// -//// use mutation state with query optionss -//$opts = new QueryOptions(); -//$opts->consistentWith($state); -//$res = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`="United States" AND x.city LIKE "%pool%" LIMIT 10', $opts); -//// end::consistentWith[] -//$idx = 1; -//foreach ($res->rows() as $row) { -// printf("%d. %s\n", $idx++, $row['name']); -//} -// -//printf("Execution Time: %d\n", $res->metaData()->metrics()['executionTime']); - -// tag::scope-level-query[] -$opts = new QueryOptions(); -$opts->namedParameters(['country' => "France"]); - -$scope = $bucket->scope("inventory"); -$result = $scope->query('SELECT x.* FROM `airline` x WHERE x.`country`=$country LIMIT 10;', $opts); - -foreach ($result->rows() as $row) { - printf("Name: %s, Callsign: %s, Country: %s\n", $row["name"], $row["callsign"], $row["country"]); -} -// end::scope-level-query[] - -// tag::VectorSearchWithQueryHyperscaleIndex[] -$res = $cluster->query( - "SELECT d.id, d.question, d.wanted_similar_color_from_search, - ARRAY_CONCAT( - d.couchbase_search_query.knn[0].vector[0:4], - ['...'] - ) AS vector - FROM `vector-sample`.`color`.`rgb-questions` AS d - WHERE d.id = '#87CEEB';", - QueryOptions::build()->metrics(true) -); -foreach ($res->rows() as $row) { - print("\nFound match:\n"); - print_r($row); -} -// end::VectorSearchWithQueryHyperscaleIndex[] - -// tag::VectorSearchWithQueryParameterized[] -$result = $cluster->query( - "SELECT d.id, d.question, d.wanted_similar_color_from_search, - ARRAY_CONCAT( - d.couchbase_search_query.knn[0].vector[0:4], - ['...'] - ) AS vector - FROM `vector-sample`.`color`.`rgb-questions` AS d - WHERE d.id = \$id;", - QueryOptions::build()->namedParameters(["id" => "#87CEEB"]) -); -foreach ($res->rows() as $row) { - print("\nFound match:\n"); - print_r($row); -} - - - -// end::VectorSearchWithQueryParameterized[] diff --git a/modules/howtos/examples/search-facets.php b/modules/howtos/examples/search-facets.php deleted file mode 100644 index d74f1bbc..00000000 --- a/modules/howtos/examples/search-facets.php +++ /dev/null @@ -1,205 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://192.168.1.101", $opts); - -// tag::iteratingfacets[] -$query = (new TermSearchQuery("beer"))->field("type"); -$options = new SearchOptions(); -$options->facets([ - "foo" => new TermSearchFacet("name", 3), - "bar" => (new DateRangeSearchFacet("updated", 1)) - ->addRange("old", NULL, mktime(0, 0, 0, 1, 1, 2014)), // "2014-01-01T00:00:00" also acceptable - "baz" => (new NumericRangeSearchFacet("abv", 2)) - ->addRange("strong", 4.9, NULL) - ->addRange("light", NULL, 4.89) -]); -$res = $cluster->searchQuery("beer-search", $query, $options); - -$facet = $res->facets()["foo"]; -printf("Term facet \"foo\" on field \"%s\". Total: %d, missing: %d: other: %d\n", - $facet["field"], $facet["total"], $facet["missing"], $facet["other"]); -foreach ($facet["terms"] as $term) { - printf(" * %-5s ... %d\n", $term["term"], $term["count"]); -} - -$facet = $res->facets()["bar"]; -printf("Date range facet \"bar\" on field \"%s\". Total: %d, missing: %d: other: %d\n", - $facet["field"], $facet["total"], $facet["missing"], $facet["other"]); -foreach ($facet["date_ranges"] as $range) { - printf(" * %-20s ... %d\n", $range["end"], $range["count"]); -} - -$facet = $res->facets()["baz"]; -printf("Numeric range facet \"baz\" on field \"%s\". Total: %d, missing: %d: other: %d\n", - $facet["field"], $facet["total"], $facet["missing"], $facet["other"]); -foreach ($facet["numeric_ranges"] as $range) { - if (isset($range["max"])) { - printf(" * max %-4s ... %d\n", $range["max"], $range["count"]); - } else { - printf(" * min %-4s ... %d\n", $range["min"], $range["count"]); - } -} -// end::iteratingfacets[] - -// Output -// -// Term facet "foo" on field "name". Total: 15260, missing: 0: other: 13000 -// * ale ... 1421 -// * stout ... 432 -// * pale ... 407 -// Date range facet "bar" on field "updated". Total: 5891, missing: 0: other: 0 -// * 2014-01-01T00:00:00Z ... 5891 -// Numeric range facet "baz" on field "abv". Total: 5891, missing: 0: other: 0 -// * max 4.89 ... 3386 -// * min 4.9 ... 2505 - - -/* - * index definition -{ - "type": "fulltext-index", - "name": "beer-search", - "uuid": "5f58f6e660a5ebea", - "sourceType": "couchbase", - "sourceName": "beer-sample", - "sourceUUID": "37838ef14de076784cc5b49b17682e0d", - "planParams": { - "maxPartitionsPerPIndex": 171, - "indexPartitions": 6 - }, - "params": { - "doc_config": { - "docid_prefix_delim": "", - "docid_regexp": "", - "mode": "type_field", - "type_field": "type" - }, - "mapping": { - "analysis": {}, - "default_analyzer": "standard", - "default_datetime_parser": "dateTimeOptional", - "default_field": "_all", - "default_mapping": { - "dynamic": true, - "enabled": true - }, - "default_type": "_default", - "docvalues_dynamic": true, - "index_dynamic": true, - "store_dynamic": false, - "type_field": "_type", - "types": { - "beer": { - "dynamic": true, - "enabled": true, - "properties": { - "abv": { - "dynamic": false, - "enabled": true, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "abv", - "store": true, - "type": "number" - } - ] - }, - "category": { - "dynamic": false, - "enabled": true, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "category", - "store": true, - "type": "text" - } - ] - }, - "description": { - "dynamic": false, - "enabled": true, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "description", - "store": true, - "type": "text" - } - ] - }, - "name": { - "dynamic": false, - "enabled": true, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "name", - "store": true, - "type": "text" - } - ] - }, - "style": { - "dynamic": false, - "enabled": true, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "style", - "store": true, - "type": "text" - } - ] - }, - "updated": { - "dynamic": false, - "enabled": true, - "fields": [ - { - "docvalues": true, - "include_in_all": true, - "include_term_vectors": true, - "index": true, - "name": "updated", - "store": true, - "type": "datetime" - } - ] - } - } - } - } - }, - "store": { - "indexType": "scorch" - } - }, - "sourceParams": {} -} - */ diff --git a/modules/howtos/examples/search.php b/modules/howtos/examples/search.php deleted file mode 100644 index 2c2e6e6c..00000000 --- a/modules/howtos/examples/search.php +++ /dev/null @@ -1,193 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -// #tag::matchquery[] -$matchQuery = new MatchSearchQuery("swanky"); -$matchQuery->field("reviews.content"); -$opts = new SearchOptions(); -$opts->limit(10); -$res = $cluster->searchQuery("travel-sample-index", $matchQuery, $opts); -printf("Match query: \"swanky\":\n"); -foreach ($res->rows() as $row) { - printf("id: %s, score: %f\n", $row['id'], $row['score']); -} -// #end::matchquery[] - -// #tag::numrangequery[] -$numericRangeQuery = new NumericRangeSearchQuery(); -$numericRangeQuery->field("reviews.ratings.Cleanliness")->min(5); -$opts = new SearchOptions(); -$opts->limit(10); -$res = $cluster->searchQuery("travel-sample-index", $numericRangeQuery, $opts); -printf("Cleanliness 5+:\n"); -foreach ($res->rows() as $row) { - printf("id: %s, score: %f\n", $row['id'], $row['score']); -} -// #end::numrangequery[] - -// #tag::conjunctionquery[] -$conjunction = new ConjunctionSearchQuery([$matchQuery, $numericRangeQuery]); -$opts = new SearchOptions(); -$opts->limit(10); -$res = $cluster->searchQuery("travel-sample-index", $conjunction, $opts); -printf("Swanky and with cleanliness 5+:\n"); -foreach ($res->rows() as $row) { - printf("id: %s, score: %f\n", $row['id'], $row['score']); -} -// #end::conjunctionquery[] - - -// #tag::consistency[] -// Create new hotel document and demonstrate query with consistency requirement -$scope = $cluster->bucket('travel-sample')->scope('inventory'); -$collection = $scope->collection('hotel'); -$hotel = [ - "name" => "super hotel", - "reviews" => [ - [ - "content" => "Super swanky hotel!", - "ratings" => [ - "Cleanliness" => 6 - ] - ] - ] -]; -$res = $collection->upsert("a-new-hotel", $hotel); -$mutationState = new MutationState(); -$mutationState->add($res); -$opts = new SearchOptions(); -$opts->limit(10); -$opts->consistentWith("travel-sample-index", $mutationState); -$res = $cluster->searchQuery("travel-sample-index", $matchQuery, $opts); -printf("Match query: \"swanky\":\n"); -foreach ($res->rows() as $row) { - printf("id: %s, score: %f\n", $row['id'], $row['score']); -} -// #end::consistency[] - -// this should come from an external source, such as an embeddings API -$vectorQuery = []; -$anotherVectorQuery = []; - -// #tag::singlevectorquery[] -$request = SearchRequest::build(VectorSearch::build([ - VectorQuery::build("vector_field", $vectorQuery) -])); - -$result = $scope->search("vector-index", $request); -// #end::singlevectorquery[] - -// #tag::multiplevectorqueries[] -$request = SearchRequest::build(VectorSearch::build([ - VectorQuery::build("vector_field", $vectorQuery)->numCandidates(2)->boost(0.3), - VectorQuery::build("vector_field", $anotherVectorQuery)->numCandidates(5)->boost(0.7) -])); - -$result = $scope->search("vector-index", $request); -// #end::multiplevectorqueries[] - -// #tag::combinedvectorquery[] -$request = SearchRequest::build(MatchAllSearchQuery::build()); -$request->vectorSearch(VectorSearch::build([ - VectorQuery::build("vector_field", $vectorQuery) -])); - -$result = $scope->search("vector-and-fts-index", $request); -// #end::combinedvectorquery[] - -// #tag::traditionalftsquery[] -$request = SearchRequest::build(MatchAllSearchQuery::build()); - -$result = $scope->search("travel-sample-index", $request); -// #end::traditionalftsquery[] - -// Output -// -// Match query: "swanky": -// id: hotel_25794, score: 0.541554 -// id: hotel_25800, score: 0.511521 -// id: hotel_25598, score: 0.510087 -// id: hotel_16350, score: 0.480130 -// id: hotel_25301, score: 0.418002 -// Cleanliness 5+: -// id: hotel_5335, score: 1.220367 -// id: hotel_21673, score: 1.220367 -// id: hotel_26139, score: 1.220367 -// id: hotel_635, score: 1.220367 -// id: hotel_21665, score: 1.220367 -// id: hotel_21679, score: 1.220367 -// id: hotel_15978, score: 1.220367 -// id: hotel_35667, score: 1.220367 -// id: hotel_4397, score: 1.220367 -// id: hotel_2241, score: 1.220367 -// Swanky and with cleanliness 5+: -// id: hotel_16350, score: 1.005243 -// id: hotel_25800, score: 0.900247 -// id: hotel_25301, score: 0.792935 -// id: hotel_25794, score: 0.534181 -// Match query: "swanky": -// id: a-new-hotel, score: 4.884002 -// id: hotel_25794, score: 0.541554 -// id: hotel_25800, score: 0.511521 -// id: hotel_25598, score: 0.510087 -// id: hotel_16350, score: 0.480130 -// id: hotel_25301, score: 0.418002 - diff --git a/modules/howtos/examples/subdoc-concurrent.php b/modules/howtos/examples/subdoc-concurrent.php deleted file mode 100644 index 4db21552..00000000 --- a/modules/howtos/examples/subdoc-concurrent.php +++ /dev/null @@ -1,46 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); -$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - -printf("Creating customer123 document\n"); -$customer123 = json_decode(file_get_contents("customer123.json")); -$collection->upsert("customer123", $customer123); -printf("Created customer123 document\n"); - -// #tag::mutateInConcurrent[] -$operations = [new \Couchbase\MutateArrayAppendSpec("purchases.complete", [999]), new \Couchbase\MutateArrayAppendSpec("purchases.complete", [998])]; -$pids = []; - -for ($i = 0; $i < count($operations); $i++) { - $pid = pcntl_fork(); - if ($pid == -1) { - die("unable to spawn child process"); - } else if ($pid == 0) { - // Child process - concurrent_mutatein($operations[$i]); - exit(0); - } else { - array_push($pids, $pid); - } -} - -foreach ($pids as $child) { - pcntl_waitpid($child, $status); -} - -function concurrent_mutatein($op) { - $opts = new ClusterOptions(); - $opts->credentials("Administrator", "password"); - $cluster = new Cluster("couchbase://localhost", $opts); - $collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - - $result = $collection->mutateIn("customer123", [ - $op - ]); -} -// #end::mutateInConcurrent[] diff --git a/modules/howtos/examples/subdoc-counters.php b/modules/howtos/examples/subdoc-counters.php deleted file mode 100644 index e9451600..00000000 --- a/modules/howtos/examples/subdoc-counters.php +++ /dev/null @@ -1,32 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - -printf("Creating customer123 document\n"); -$customer123 = json_decode(file_get_contents("customer123.json")); -$collection->upsert("customer123", $customer123); -printf("Created customer123 document\n"); - -// #tag::mutateInIncrement[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateCounterSpec("logins", 1) -]); - -printf("%d\n", $result->content(0)); // 1 -// #end::mutateInIncrement[] - -// #tag::mutateInDecrement[] -$result = $collection->upsert("player432", ["gold" => 1000]); - -$result = $collection->mutateIn("player432", [ - new \Couchbase\MutateCounterSpec("gold", -150) -]); -printf("player 432 now has %d gold remaining\n", $result->content(0)); -// => player 432 now has 850 gold remaining -// #end::mutateInDecrement[] \ No newline at end of file diff --git a/modules/howtos/examples/subdoc-lookupin.php b/modules/howtos/examples/subdoc-lookupin.php deleted file mode 100644 index 642982e1..00000000 --- a/modules/howtos/examples/subdoc-lookupin.php +++ /dev/null @@ -1,62 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - -printf("Creating customer123 document\n"); -$customer123 = json_decode(file_get_contents("customer123.json")); -$collection->upsert("customer123", $customer123); -printf("Created customer123 document\n"); - -// #tag::lookupInGet[] -$result = $collection->lookupIn("customer123", [ - new \Couchbase\LookupGetSpec("addresses.delivery.country") -]); -$country = $result->content(0); -printf("%s\n", $country); -// "United Kingdom" -// #end::lookupInGet[] - -// #tag::lookupInExists[] -$result = $collection->lookupIn("customer123", [ - new \Couchbase\LookupExistsSpec("purchases.pending[-1]") -]); -printf("Path exists? %s\n", $result->exists(0) ? "true" : "false"); -// Path exists? false -// #end::lookupInExists[] - -// #tag::lookupInMulti[] -$result = $collection->lookupIn("customer123", [ - new \Couchbase\LookupGetSpec("addresses.delivery.country"), - new \Couchbase\LookupExistsSpec("purchases.pending[-1]") -]); -printf("%s\n", $result->content(0)); -printf("Path exists? %s\n", $result->exists(1) ? "true" : "false"); -// United Kingdom -// Path exists? false -// #end::lookupInMulti[] -// #tag::lookupinanyreplica[] -$result = $collection->lookupInAnyReplica("customer123", [ - new \Couchbase\LookupGetSpec("addresses.delivery.country") -]); -printf("%s\n", $result->content(0)); -// United Kingdom -printf("Is replica? %s", $result->isReplica() ? "true" : "false"); -// Is replica?: false|true -// #end::lookupinanyreplica[] -// #tag::lookupinallreplicas[] -$results = $collection->lookupInAllReplicas("customer123", [ - new \Couchbase\LookupGetSpec("addresses.delivery.country") -]); -foreach ($results as $result) { - printf("%s\n", $result->content(0)); - // United Kingdom - printf("Is replica? %s\n", $result->isReplica() ? "true" : "false"); - // Is replica? false|true -} -// #end::lookupinallreplicas[] diff --git a/modules/howtos/examples/subdoc-mutatein-arrays.php b/modules/howtos/examples/subdoc-mutatein-arrays.php deleted file mode 100644 index a2beeada..00000000 --- a/modules/howtos/examples/subdoc-mutatein-arrays.php +++ /dev/null @@ -1,84 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - -printf("Creating customer123 document\n"); -$customer123 = json_decode(file_get_contents("customer123.json")); -$collection->upsert("customer123", $customer123); -printf("Created customer123 document\n"); - - -// #tag::mutateInArrayAppend[] -$result = $collection->MutateIn("customer123", [ - new \Couchbase\MutateArrayAppendSpec("purchases.complete", [777]) -]); -// purchases.complete is now [339, 976, 442, 666, 777] -// #end::mutateInArrayAppend[] - -// #tag::mutateInArrayPrepend[] -$result = $collection->MutateIn("customer123", [ - new \Couchbase\MutateArrayPrependSpec("purchases.abandoned", [18]) -]); -// purchases.abandoned is now [18, 157, 49, 999] -// #end::mutateInArrayPrepend[] - -// #tag::mutateInArrayDoc[] -$result = $collection->upsert("my_array", []); -$result = $collection->mutateIn("my_array", [ - new \Couchbase\MutateArrayAppendSpec("", ["some element"]) -]); -// the document my_array is now ["some element"] -// #end::mutateInArrayDoc[] - -// #tag::mutateInArrayDocMulti[] -$result = $collection->mutateIn("my_array", [ - new \Couchbase\MutateArrayAppendSpec("", ["elem1", "elem2", "elem3"]) -]); -// the document my_array is now ["some_element", "elem1", "elem2", "elem3"] -// #end::mutateInArrayDocMulti[] - -// #tag::mutateInArrayDocMultiSingle[] -$result = $collection->mutateIn("my_array", [ - new \Couchbase\MutateArrayAppendSpec("", [["elem1", "elem2", "elem3"]]) -]); -// the document my_array is now ["some_element", ["elem1", "elem2", "elem3"]] -// #end::mutateInArrayDocMultiSingle[] - -// #tag::mutateInArrayAppendMulti[] -$result = $collection->mutateIn("my_array", [ - new \Couchbase\MutateArrayAppendSpec("", ["elem1"]), - new \Couchbase\MutateArrayAppendSpec("", ["elem2"]), - new \Couchbase\MutateArrayAppendSpec("", ["elem3"]), -]); -// #end::mutateInArrayAppendMulti[] - -// #tag::mutateInArrayAppendCreatePath[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateArrayAppendSpec("some.array", ["Hello", "World"], false, true) - ]); -// #end::mutateInArrayAppendCreatePath[] - -// #tag::mutateInArrayAddUnique[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateArrayAddUniqueSpec("purchases.complete", 95) -]); -// => Success - -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateArrayAddUniqueSpec("purchases.complete", 95) -]); -// => SubdocPathExists exception! -// #end::mutateInArrayAddUnique[] - -// #tag::mutateInArrayInsert[] -$result = $collection->upsert("array", ["Hello", "world"]); -$result = $collection->mutateIn("array", [ - new \Couchbase\MutateArrayInsertSpec("[1]", ["cruel"]) -]); -// #end::mutateInArrayInsert[] \ No newline at end of file diff --git a/modules/howtos/examples/subdoc-mutatein-durability.php b/modules/howtos/examples/subdoc-mutatein-durability.php deleted file mode 100644 index e101a8ed..00000000 --- a/modules/howtos/examples/subdoc-mutatein-durability.php +++ /dev/null @@ -1,22 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - -printf("Creating customer123 document\n"); -$customer123 = json_decode(file_get_contents("customer123.json")); -$collection->upsert("customer123", $customer123); -printf("Created customer123 document\n"); - -// #tag::mutateInDurableWrites[] -$options = new \Couchbase\MutateInOptions(); -$options->durabilityLevel(\Couchbase\DurabilityLevel::MAJORITY); -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateUpsertSpec("name", "dave") -], $options); -// #end::mutateInDurableWrites[] diff --git a/modules/howtos/examples/subdoc-mutatein.php b/modules/howtos/examples/subdoc-mutatein.php deleted file mode 100644 index 768c70de..00000000 --- a/modules/howtos/examples/subdoc-mutatein.php +++ /dev/null @@ -1,52 +0,0 @@ -credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); - -printf("Creating customer123 document\n"); -$customer123 = json_decode(file_get_contents("customer123.json")); -$collection->upsert("customer123", $customer123); -printf("Created customer123 document\n"); - -// #tag::mutateInUpsert[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateUpsertSpec("fax", "311-555-0151") -]); -// #end::mutateInUpsert[] - -// #tag::mutateInInsert[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateInsertSpec("purchases.complete", [42, true, "None"]) -]); -// SubdocPathExistsError -// #end::mutateInInsert[] - -// #tag::mutateInMulti[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateRemoveSpec("addresses.billing"), - new \Couchbase\MutateReplaceSpec("email", "dougr96@hotmail.com") -]); -// #end::mutateInMulti[] - -// #tag::mutateInCreatePath[] -$result = $collection->mutateIn("customer123", [ - new \Couchbase\MutateUpsertSpec("level_0.level_1.foo.bar.phone", - ["num" => "311-555-0101", "ext" => 16], - false, true) -]); -// #end::mutateInCreatePath[] - -// #tag::mutateInCas[] -$doc = $collection->get("customer123"); -$options = new \Couchbase\MutateInOptions(); -$options->cas($doc->cas()); - -$res = $collection->mutatein("customer123", [ - new \Couchbase\MutateArrayAppendSpec("purchases.complete", [1000]) -], $options); -// #end::mutateInCas[] \ No newline at end of file diff --git a/modules/howtos/examples/threshold-logging.php b/modules/howtos/examples/threshold-logging.php deleted file mode 100644 index 20320756..00000000 --- a/modules/howtos/examples/threshold-logging.php +++ /dev/null @@ -1,65 +0,0 @@ -credentials("Administrator", "password"); - -// tag::thresholdLogging[] -$connectionString = "couchbase://127.0.0.1?" . - "tracing_threshold_queue_flush_interval=3&" . /* every 3 seconds */ - "tracing_threshold_kv=0.01"; /* 10 milliseconds */ - -$cluster = new Cluster($connectionString, $options); -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->scope("inventory")->collection("airport"); -// end::thresholdLogging[] - -// tag::thresholdLongProcessing[] -/* - * Create a new document - */ -$document = ["answer" => 42, "updated_at" => date("r")]; -$collection->upsert("foo", $document); - -/* - * Replace the document with a big body and very small deadline which should trigger a - * client-side timeout, in which case the server response will be reported as orphan - */ -$options = new UpsertOptions(); -$options->timeout(1); -/* - * Generate a document with 10M payload, that should be unfriendly to the compressing function - * and longer to process on the server side - */ -$document = ["noise" => base64_encode(random_bytes(15_000_000))]; -$numberOfTimeouts = 0; -while (true) { - try { - $collection->upsert("foo", $document, $options); - } catch (TimeoutException $e) { - $numberOfTimeouts++; - if ($numberOfTimeouts > 3) { - break; - } - } -} -// end::thresholdLongProcessing[] - -/* - * Threshold reports will be written like the following - * - * [cb,INFO] (tracer L:149 I:2929787644) Operations over threshold: {"count":14,"service":"kv","top":[{"operation_name":"php/upsert","total_us":537133},{"operation_name":"php/upsert","total_us":513483},{"operation_name":"php/upsert","total_us":510245},{"operation_name":"php/upsert","total_us":500094},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x3","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":150315,"total_us":320528},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x2","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":126118,"total_us":317381},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x4","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":149572,"total_us":311246},{"operation_name":"php/request_encoding","total_us":200289}]} - */ diff --git a/modules/howtos/examples/transactions-example.php b/modules/howtos/examples/transactions-example.php deleted file mode 100644 index e53a5704..00000000 --- a/modules/howtos/examples/transactions-example.php +++ /dev/null @@ -1,535 +0,0 @@ -credentials($CB_USER, $CB_PASS); - -$transactions_configuration = new TransactionsConfiguration(); -$transactions_configuration->durabilityLevel(Couchbase\DurabilityLevel::PERSIST_TO_MAJORITY); -$options->transactionsConfiguration($transactions_configuration); - -$cluster = new Cluster($CB_HOST, $options); -// end::config[] - -// tag::bucket[] -// get a reference to our bucket -$bucket = $cluster->bucket('travel-sample'); -// end::bucket[] - -// tag::collection[] -// get a reference to a collection -$collection = $bucket->scope('inventory')->collection('airline'); -// end::collection[] - -// tag::default-collection[] -// get a reference to the default collection, required for older Couchbase server versions -$collection_default = $bucket->defaultCollection(); -// end::default-collection[] - -function removeOrWarn($collection, $doc) -{ - try { - $collection->remove($doc); - } catch (\Couchbase\Exception\DocumentNotFoundException $e) { - echo "Document does not exist.\n"; - } -} - -$testDoc = 'foo'; -removeOrWarn($collection, $testDoc); -removeOrWarn($collection, 'doc-c'); -removeOrWarn($collection, 'docId'); -removeOrWarn($collection, 'doc-greeting'); -$collection->upsert('doc-a', []); -$collection->upsert('doc-b', []); -$collection->upsert('customer-name', ['balance' => 9]); - -try { - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection, $testDoc) { - $ctx->insert($collection, $testDoc, "hello"); - } - ); -} catch (\Couchbase\Exception\TransactionFailedException $e) { - echo "Transaction did not reach commit point: $e\n"; -} catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { - echo "Transaction possibly committed: $e\n"; -} - -echo "Running: create example\n"; -// tag::create[] -try { - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) { - // `$ctx` is a TransactionAttemptContext which permits getting, inserting, - // removing and replacing documents, performing SQL++ (N1QL) queries, etc. - // … Your transaction logic here … - // Committing is implicit at the end of the lambda. - } - ); -} catch (\Couchbase\Exception\TransactionFailedException $e) { - echo "Transaction did not reach commit point: $e\n"; -} catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { - echo "Transaction possibly committed: $e\n"; -} -// end::create[] - -echo "Running: create-simple example\n"; -// tag::create-simple[] -$cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - $ctx->insert($collection, 'doc1', ['hello' => 'world']); - - $doc = $ctx->get($collection, 'doc1'); - $ctx->replace($doc, ['foo' => 'bar']); - } -); -// end::create-simple[] - -echo "\nRunning: examples\n"; -// tag::examples[] -try { - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - // Inserting a doc: - $ctx->insert($collection, 'doc-c', []); - - // Getting documents: - $docA = $ctx->get($collection, 'doc-a'); - - // Replacing a doc: - $docB = $ctx->get($collection, 'doc-b'); - $content = $docB->content(); - $newContent = array_merge( - ["transactions" => "are awesome"], - $content - ); - $ctx->replace($docB, $newContent); - - // Removing a doc: - $docC = $ctx->get($collection, 'doc-c'); - $ctx->remove($docC); - - // Performing a SELECT SQL++ (N1QL) query: - $selectQuery = 'SELECT * FROM `travel-sample`.inventory.hotel WHERE country = $1 LIMIT 5'; - $qr = $ctx->query( - $selectQuery, - TransactionQueryOptions::build() - ->positionalParameters(["United Kingdom"]) - ); - foreach ($qr->rows() as $row) { - printf("Name: %s, Country: %s\n", $row["hotel"]["name"], $row["hotel"]["country"]); - } - - // Performing an UPDATE SQL++ (N1QL) query: - $updateQuery = 'UPDATE `travel-sample`.inventory.route SET airlineid = $1 WHERE airline = $2 LIMIT 5'; - $ctx->query( - $updateQuery, - TransactionQueryOptions::build() - ->positionalParameters(['airline_137', 'AF']) - ); - } - ); -} catch (\Couchbase\Exception\TransactionFailedException $e) { - echo "Transaction did not reach commit point: $e\n"; -} catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { - echo "Transaction possibly committed: $e\n"; -} -// end::examples[] - -// execute other examples -getExample($cluster, $collection); -getReadOwnWritesExample($cluster, $collection); -replaceExample($cluster, $collection); -removeExample($cluster, $collection); -insertExample($cluster, $collection); -queryExamples($cluster); -queryRYOW($cluster); -queryKvMix($cluster, $collection); -queryOptions($cluster); -// TODO: Uncomment when we have clarity on what the example should do. -// querySingle($cluster); - -// Rollback -playerHitsMonster(42, "arthur", "vogon", $cluster, $collection); -// rollbackExample($cluster, $collection); -rollbackCause($cluster, $collection); - -function getExample($cluster, $collection) -{ - echo "\nRunning: get example\n"; - // tag::get[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - $docA = $ctx->get($collection, "doc-a"); - } - ); - // end::get[] - // TODO: should this show nullable/optional in an example? -} - -function getReadOwnWritesExample($cluster, $collection) -{ - echo "\nRunning: getReadOwnWrites example\n"; - // tag::getReadOwnWrites[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - $docId = 'docId'; - $ctx->insert($collection, $docId, []); - - $doc = $ctx->get($collection, $docId); - } - ); - // end::getReadOwnWrites[] -} - -function replaceExample($cluster, $collection) -{ - echo "\nRunning: replace example\n"; - // tag::replace[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - $doc = $ctx->get($collection, "doc-b"); - $content = $doc->content(); - $newContent = array_merge( - ["transactions" => "are awesome"], - $content - ); - - $ctx->replace($doc, $newContent); - } - ); - // end::replace[] -} - -function removeExample($cluster, $collection) -{ - echo "\nRunning: remove example\n"; - // tag::remove[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - $doc = $ctx->get($collection, "docId"); - $ctx->remove($doc); - } - ); - // end::remove[] -} - -function insertExample($cluster, $collection) -{ - echo "\nRunning: insert example\n"; - // tag::insert[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - $adoc = $ctx->insert($collection, "docId", []); - } - ); - // end::insert[] -} - -function calculateLevelForExperience(int $experience): int -{ - return (int)floor($experience / 100); -} - -function queryExamples($cluster) -{ - echo "\nRunning: queryExamplesSelect\n"; - // TODO: scopeQualifier/scopeName options are both deprecated. - // https://github.com/couchbase/couchbase-php-client/blob/4.0.0/Couchbase/TransactionQueryOptions.php#L296-L325 - // It's unclear what we should use to demonstrate scope level queries. - // Using full qualifier for now. - // tag::queryExamplesSelect[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) { - $st = "SELECT * FROM `travel-sample`.inventory.hotel WHERE country = $1"; - $qr = $ctx->query( - $st, - TransactionQueryOptions::build() - ->positionalParameters(["United Kingdom"]) - ); - - foreach ($qr->rows() as $row) { - // do something - } - } - ); - // end::queryExamplesSelect[] - - // TODO: scopeQualifier/scopeName options are both deprecated. - // https://github.com/couchbase/couchbase-php-client/blob/4.0.0/Couchbase/TransactionQueryOptions.php#L296-L325 - // It's unclear what we should use to demonstrate scope level queries. - // Using full qualifier for now. - // $st = UPDATE hotel SET price = $1 WHERE url LIKE $2 AND country = $3"; - // tag::queryExamplesUpdate[] - $hotelChain = 'http://marriot%'; - $country = 'United States'; - - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($hotelChain, $country) { - $st = "UPDATE `travel-sample`.inventory.hotel SET price = $1 WHERE url LIKE $2 AND country = $3"; - $qr = $ctx->query( - $st, - TransactionQueryOptions::build() - ->positionalParameters([99.99, $hotelChain, $country]) - ); - - print_r($qr->metaData()->metrics()); - if ($qr->metaData()->metrics()["mutationCount"] != 2) { - // throw new \Exception("Mutation count not the expected amount."); - echo "WARN: Mutation count not the expected amount.\n"; - } - } - ); - // end::queryExamplesUpdate[] - - // tag::queryExamplesComplex[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($hotelChain, $country) { - // Find all hotels of the chain - $qr = $ctx->query( - 'SELECT reviews FROM `travel-sample`.inventory.hotel WHERE url LIKE $1 AND country = $2', - TransactionQueryOptions::build() - ->positionalParameters([$hotelChain, $country]) - ); - - // This function (not provided here) will use a trained machine learning model to provide a - // suitable price based on recent customer reviews. - $priceFromRecentReviews = function (\Couchbase\QueryResult $qr): float { - // this would call a trained ML model to get the best price - return 99.98; - }; - $updatedPrice = $priceFromRecentReviews($qr); - - // Set the price of all hotels in the chain - $ctx->query( - 'UPDATE `travel-sample`.inventory.hotel SET price = $1 WHERE url LIKE $2 AND country = $3', - TransactionQueryOptions::build() - ->positionalParameters([$updatedPrice, $hotelChain, $country]) - ); - } - ); - // end::queryExamplesComplex[] -} - -function queryRYOW($cluster) -{ - echo "\nRunning: queryInsert example\n"; - // tag::queryRYOW[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) { - // Query INSERT - $ctx->query( - "INSERT INTO `travel-sample`.inventory.airline VALUES ('doc-c', {'hello':'world'})" // <1> - ); - - // Query SELECT - $ctx->query( - "SELECT hello FROM `travel-sample`.inventory.airline WHERE META().id = 'doc-c'" // <2> - ); - } - ); - // end::queryRYOW[] -} - -function queryKvMix($cluster, $collection) -{ - echo "\nRunning: queryKvMix example\n"; - // tag::queryKvMix[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection) { - // Key-Value insert - $ctx->insert($collection, "doc-greeting", ["greeting" => "Hello World"]); // <1> - - // Query SELECT - $selectQuery = "SELECT greeting FROM `travel-sample`.inventory.airline WHERE META().id = 'doc-greeting'"; - $ctx->query($selectQuery); // <2> - } - ); - // end::queryKvMix[] -} - -function queryOptions($cluster) -{ - echo "\nRunning: queryOptions example\n"; - // tag::queryOptions[] - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) { - $txQo = TransactionQueryOptions::build() - ->readonly(false) - ->positionalParameters(["key", "value"]); - - $ctx->query( - "UPSERT INTO `travel-sample`.inventory.airline VALUES ('docId', {\$1:\$2})", - $txQo - ); - } - ); - // end::queryOptions[] -} - -// TODO: Verify this is the correct example for a single query transaction. -// function querySingle($cluster) -// { -// echo "\nRunning: querySingle example\n"; -// // tag::querySingle[] -// try { -// $cluster->transactions()->run( -// function (TransactionAttemptContext $ctx) { -// $bulkLoadStatement = "..."; // a bulk-loading SQL++ (N1QL) statement not provided here - -// $ctx->query($bulkLoadStatement); -// } -// ); -// } catch (\Couchbase\Exception\TransactionFailedException $e) { -// echo "Transaction did not reach commit point\n"; -// } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { -// echo "Transaction possibly committed\n"; -// } -// // end::querySingle[] -// } - -// SKIP querySingleScoped till checked Scoped examples above! -// async function querySingleScoped() { -// let cluster = await getCluster() - -// const bulkLoadStatement = "" /* your statement here */ - -// // String bulkLoadStatement = null /* your statement here */; - -// // // tag::querySingleScoped[] -// const travelSample = cluster.bucket("travel-sample") -// const inventory = travelSample.scope("inventory") -// // TODO: enable after implementation -// // cluster.query(bulkLoadStatement, queryOptions().asTransaction()) -// // // end::querySingleScoped[] -// } - -echo "\nRunning: full example\n"; -// tag::full[] -function playerHitsMonster($damage, $playerId, $monsterId, $cluster, $collection) -{ - try { - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($damage, $playerId, $monsterId, $collection) { - $monsterDoc = $ctx->get($collection, $monsterId); - $monsterContent = $monsterDoc->content(); - $playerDoc = $ctx->get($playerId, $monsterId); - $playerContent = $playerDoc->content(); - - $monsterHitpoints = $monsterContent["hitpoints"]; - $monsterNewHitpoints = $monsterHitpoints - $damage; - - if ($monsterNewHitpoints <= 0) { - // Monster is killed. The remove is just for demoing, and a more realistic - // example would set a "dead" flag or similar. - $ctx->remove($monsterDoc); - - // The player earns experience for killing the monster - $experienceForKillingMonster = $monsterContent["experienceWhenKilled"]; - $playerExperience = $playerContent["experience"]; - $playerNewExperience = $playerExperience + $experienceForKillingMonster; - $playerNewLevel = calculateLevelForExperience($playerNewExperience); - - $playerContent['experience'] = $playerNewExperience; - $playerContent['level'] = $playerNewLevel; - - $ctx->replace($playerDoc, $playerContent); - } - } - ); - } catch (\Couchbase\Exception\TransactionFailedException $e) { - echo "Transaction did not reach commit point\n"; - // The operation failed. Both the monster and the player will be untouched. - // - // Situations that can cause this would include either the monster - // or player not existing (as get is used), or a persistent - // failure to be able to commit the transaction, for example on - // prolonged node failure. - } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { - // Indicates the state of a transaction ended as ambiguous and may or - // may not have committed successfully. - // - // Situations that may cause this would include a network or node failure - // after the transactions operations completed and committed, but before the - // commit result was returned to the client - echo "Transaction possibly committed\n"; - } -} -// end::full[] - -class InsufficientBalanceException extends Exception -{ -} - -function rollbackCause($cluster, $collection) -{ - echo "\nRunning: rollback-cause example\n"; - // tag::rollback-cause[] - $costOfItem = 10; - - try { - $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection, $costOfItem) { - $customer = $ctx->get($collection, "customer-name"); - - if ($customer->content()["balance"] < $costOfItem) { - throw new \InsufficientBalanceException("Transaction failed, customer does not have enough funds."); - } - // else continue transaction - } - ); - } catch (\Couchbase\Exception\TransactionFailedException $e) { - echo "Transaction did not reach commit point: $e\n"; - } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { - echo "Transaction possibly committed: $e\n"; - } - // end::rollback-cause[] -} - -echo "\nRunning: full-error-handling example\n"; -function completeErrorHandling($cluster, $collection) -{ - $costOfItem = 0; - // tag::full-error-handling[] - try { - $result = $cluster->transactions()->run( - function (TransactionAttemptContext $ctx) use ($collection, $costOfItem) { - // ... transactional code here ... - } - ); - - // The transaction definitely reached the commit point. Unstaging - // the individual documents may or may not have completed - - if (!$result->unstagingComplete) { - // In rare cases, the application may require the commit to have - // completed. (Recall that the asynchronous cleanup process is - // still working to complete the commit.) - // The next step is application-dependent. - } - } catch (\Couchbase\Exception\TransactionFailedException $e) { - echo "Transaction did not reach commit point\n"; - } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { - echo "Transaction possibly committed\n"; - } - // end::full-error-handling[] -} - -echo "\n\nTransactions Examples completed successfully\n\n"; diff --git a/modules/howtos/examples/transcoding.php b/modules/howtos/examples/transcoding.php deleted file mode 100644 index 4e23be86..00000000 --- a/modules/howtos/examples/transcoding.php +++ /dev/null @@ -1,113 +0,0 @@ -credentials('Administrator', 'password'); -$cluster = new Cluster('couchbase://localhost', $options); - -/* - * We open the default bucket to store our cached data in. - */ -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->scope("inventory")->collection("airport"); - -/* - * Some flags for differentiating what kind of data is stored so our - * decoder knows what to do with it. - */ -define('CBTE_FLAG_IMG', 1); -define('CBTE_FLAG_JSON', 2); - - -// tag::encoder[] -/* - * Lets define some custom transcoding functions. For this example, any - * image types that are stored will be serialized as a PNG, and all other - * object types will be encoded as JSON. - */ -function example_encoder($value) { - if (gettype($value) == 'resource' && get_resource_type($value) == 'gd') { - // This is am image, lets capture the PNG data! - ob_start(); - imagepng($value); - $png_data = ob_get_contents(); - ob_end_clean(); - - // Return our bytes and flags - return array($png_data, CBTE_FLAG_IMG, 0); - } else { - // This is an arbitrary type, lets JSON encode it - $json_data = json_encode($value); - - // Return our bytes and flags - return array($json_data, CBTE_FLAG_JSON, 0); - } -} -// end::encoder[] - -// tag::decoder[] -function example_decoder($bytes, $flags, $datatype) { - if ($flags == CBTE_FLAG_IMG) { - // Recreate our image object from the stored data - return imagecreatefromstring($bytes); - } else if ($flags == CBTE_FLAG_JSON) { - // Simply JSON decode - return json_decode($bytes); - } else { - // Ugh oh... - return NULL; - } -} -// end::decoder[] - - -// tag::usage[] -/* - * Create an image to test with - */ -$im = imagecreatetruecolor(300, 50); -$text_color = imagecolorallocate($im, 233, 14, 91); -imagestring($im, 6, 10, 10, 'Couchbase Rocks!', $text_color); - -/* - * Store it in Couchbase. This should execute our custom encoder. - */ -$options = new UpsertOptions(); -$options->encoder('example_encoder'); // Could be any callable. -$collection->upsert('test_image', $im, $options); - -/* - * Now lets retreive it back, it should still be an image thanks to our - * custom decoder. - */ -$options = new GetOptions(); -$options->decoder('example_decoder'); // Could be any callable. -$image_doc = $collection->get('test_image', $options); - -/* - * Output our retrieved document to the browser with a image/png content-type. - */ -header('Content-Type: image/png'); -imagepng($image_doc->content()); -// end::usage[] diff --git a/modules/howtos/examples/using-cas.php b/modules/howtos/examples/using-cas.php deleted file mode 100644 index e2a7d8eb..00000000 --- a/modules/howtos/examples/using-cas.php +++ /dev/null @@ -1,66 +0,0 @@ -get($userId); - - // Increment the visit count - $user = $res->content(); - $user["visit_count"]++; - - try { - // Attempt to replace the document using CAS - $opts = new ReplaceOptions(); - $opts->cas($res->cas()); - $collection->replace($userId, $user, $opts); - } catch (CasMismatchException $ex) { - continue; - } - - // If no errors occured during the replace, we can exit our retry loop - return; - } - printf("Replace failed after %d attempts\n", $maxRetries); -} -// #end::increment[] - - -function lockingAndCas(Collection $collection, string $userId) { -// #tag::locking[] - $res = $collection->getAndLock($userId, 2 /* seconds */); - $lockedCas = $res->cas(); - - /* // an example of simply unlocking the document: - * $collection->unlock($userId, $lockedCas); - */ - - // Increment the visit count - $user = $res->content(); - $user["visit_count"]++; - - $opts = new ReplaceOptions(); - $opts->cas($lockedCas); - $collection->replace($userId, $user, $opts); -// #end::locking[] -} - -$opts = new ClusterOptions(); -$opts->credentials("Administrator", "password"); -$cluster = new Cluster("couchbase://localhost", $opts); - -$bucket = $cluster->bucket("travel-sample"); -$collection = $bucket->scope("inventory")->collection("airport"); - -$collection->upsert("userId", ["visit_count" => 0]); - -incrementVisitCount($collection, "userId"); -lockingAndCas($collection, "userId"); diff --git a/modules/howtos/pages/analytics-using-sdk.adoc b/modules/howtos/pages/analytics-using-sdk.adoc index e4ba83e1..f49be838 100644 --- a/modules/howtos/pages/analytics-using-sdk.adoc +++ b/modules/howtos/pages/analytics-using-sdk.adoc @@ -55,7 +55,7 @@ Alternatively, the query may be performed with named parameters: [source,php] ---- -include::example$analytics.php[tag=named] +include::devguide:example$php/analytics.php[tag=named] ---- NOTE: As timeouts are propagated to the server by the client, a timeout set on the client side may be used to stop the processing of a request, in order to save system resources. @@ -80,7 +80,7 @@ Here, we set a custom, server-side timeout value: [source,php] ---- -include::example$analytics.php[tag=options] +include::devguide:example$php/analytics.php[tag=options] ---- @@ -92,7 +92,7 @@ as you will have seen when working through our xref:{version-server}@server:anal [source,php] ---- -include::example$analytics.php[tag=results] +include::devguide:example$php/analytics.php[tag=results] ---- // Move these to Error reference doc? @@ -115,7 +115,7 @@ Here is a snippet using several items of metadata [source,php] ---- -include::example$analytics.php[tag=metadata] +include::devguide:example$php/analytics.php[tag=metadata] ---- @@ -139,7 +139,7 @@ We can then query the Dataset as normal, using the fully qualified keyspace: [source,php] ---- -include::example$analytics.php[tag=handle-collection,indent=0] +include::devguide:example$php/analytics.php[tag=handle-collection,indent=0] ---- Note that using the `CREATE DATASET` syntax we could choose any Dataset name in any Dataverse, including the default. @@ -147,5 +147,5 @@ However the SDK supports this standard convention, allowing us to query from the [source,php] ---- -include::example$analytics.php[tag=handle-scope,indent=0] +include::devguide:example$php/analytics.php[tag=handle-scope,indent=0] ---- diff --git a/modules/howtos/pages/collecting-information-and-logging.adoc b/modules/howtos/pages/collecting-information-and-logging.adoc index 204eefab..84dfd699 100644 --- a/modules/howtos/pages/collecting-information-and-logging.adoc +++ b/modules/howtos/pages/collecting-information-and-logging.adoc @@ -30,7 +30,7 @@ For example, the script below: [source,php] ---- -include::example$logging.php[tag=logging, indent=0] +include::devguide:example$php/logging.php[tag=logging, indent=0] ---- ...along with this `php.ini` snippet: diff --git a/modules/howtos/pages/concurrent-async-apis.adoc b/modules/howtos/pages/concurrent-async-apis.adoc index e8bbd0f1..dea0d688 100644 --- a/modules/howtos/pages/concurrent-async-apis.adoc +++ b/modules/howtos/pages/concurrent-async-apis.adoc @@ -76,7 +76,7 @@ you can find the default locations for other Operating Systems in our xref:https [source,php] ---- -include::example$batch.php[tag=loading] +include::devguide:example$php/batch.php[tag=loading] ---- Here we've unzipped the zip file containing the dataset and then set up the relevant number of batches, @@ -91,7 +91,7 @@ The parent then uses `pcntl_waitpid` to wait for each child process to complete. [source,php] ---- -include::example$batch.php[tag=batching] +include::devguide:example$php/batch.php[tag=batching] ---- In the output we can see something like: diff --git a/modules/howtos/pages/concurrent-document-mutations.adoc b/modules/howtos/pages/concurrent-document-mutations.adoc index f139e7cb..5c096f31 100644 --- a/modules/howtos/pages/concurrent-document-mutations.adoc +++ b/modules/howtos/pages/concurrent-document-mutations.adoc @@ -14,7 +14,7 @@ include::{version-common}@sdk:shared:partial$cas.adoc[tag=errors] [source,php] ---- -include::example$using-cas.php[tag=increment] +include::devguide:example$php/using-cas.php[tag=increment] ---- Sometimes more logic is needed when performing updates, for example, if a property is mutually exclusive with another property; only one or the other can exist, but not both. @@ -28,7 +28,7 @@ include::{version-common}@sdk:shared:partial$cas.adoc[tag=locking] [source,php] ---- -include::example$using-cas.php[tag=locking] +include::devguide:example$php/using-cas.php[tag=locking] ---- The handler will unlock the item either via an explicit unlock operation ([.api]`unlock`) or implicitly via modifying the item with the correct CAS. diff --git a/modules/howtos/pages/distributed-acid-transactions-from-the-sdk.adoc b/modules/howtos/pages/distributed-acid-transactions-from-the-sdk.adoc index 422ad5ac..640b4624 100644 --- a/modules/howtos/pages/distributed-acid-transactions-from-the-sdk.adoc +++ b/modules/howtos/pages/distributed-acid-transactions-from-the-sdk.adoc @@ -51,7 +51,7 @@ include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tag=creating [source,php] ---- -include::example$transactions-example.php[tag=examples,indent=0] +include::devguide:example$php/transactions-example.php[tag=examples,indent=0] ---- include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tag={lambda}-ctx] @@ -66,7 +66,7 @@ To aid troubleshooting, raise the log level on the SDK. //[source,java] //---- -//include::example$TransactionsExample.java[tag=logging,indent=0] +//include::devguide:example$php/TransactionsExample.java[tag=logging,indent=0] //---- // //A failed transaction can involve dozens, even hundreds, of lines of logging, so the application may prefer to write failed transactions into a separate file. @@ -75,7 +75,7 @@ To aid troubleshooting, raise the log level on the SDK. //This will log all lines of any failed transactions, to `WARN` level: //[source,java] //---- -//include::example$TransactionsExample.java[tag=config_warn,indent=0] +//include::devguide:example$php/TransactionsExample.java[tag=config_warn,indent=0] //---- // @@ -104,7 +104,7 @@ To insert a document within a transaction {lambda}, simply call `ctx.insert()`. [source,php] ---- -include::example$transactions-example.php[tag=insert,indent=0] +include::devguide:example$php/transactions-example.php[tag=insert,indent=0] ---- === Get @@ -113,7 +113,7 @@ From a transaction context you may get a document: [source,php] ---- -include::example$transactions-example.php[tag=get,indent=0] +include::devguide:example$php/transactions-example.php[tag=get,indent=0] ---- If the document does not exist, the transaction will fail with a `TransactionFailedException` (after rolling back any changes, of course). @@ -122,7 +122,7 @@ Gets will "Read Your Own Writes", e.g. this will succeed: [source,php] ---- -include::example$transactions-example.php[tag=getReadOwnWrites,indent=0] +include::devguide:example$php/transactions-example.php[tag=getReadOwnWrites,indent=0] ---- === Replace @@ -132,7 +132,7 @@ This is necessary so the SDK can check that the document is not involved in anot [source,php] ---- -include::example$transactions-example.php[tag=replace,indent=0] +include::devguide:example$php/transactions-example.php[tag=replace,indent=0] ---- === Remove @@ -141,7 +141,7 @@ As with replaces, removing a document requires a `$ctx->get()` call first. [source,php] ---- -include::example$transactions-example.php[tag=remove,indent=0] +include::devguide:example$php/transactions-example.php[tag=remove,indent=0] ---- == {sqlpp} Queries @@ -158,7 +158,7 @@ Here is an example of selecting some rows from the `travel-sample` bucket: [source,php] ---- -include::example$transactions-example.php[tag=queryExamplesSelect,indent=0] +include::devguide:example$php/transactions-example.php[tag=queryExamplesSelect,indent=0] ---- // TODO: Scope reference stuff doesn't seem to work (marked as deprecated?) @@ -167,21 +167,21 @@ include::example$transactions-example.php[tag=queryExamplesSelect,indent=0] // [source,php] // ---- -// include::example$transactions-example.php[tag=queryExamplesSelectScope,indent=0] +// include::devguide:example$php/transactions-example.php[tag=queryExamplesSelectScope,indent=0] // ---- // An example using a `Scope` for an UPDATE: // [source,php] // ---- -// include::example$transactions-example.php[tag=queryExamplesUpdate,indent=0] +// include::devguide:example$php/transactions-example.php[tag=queryExamplesUpdate,indent=0] // ---- And an example combining `SELECT` and an `UPDATE`. [source,php] ---- -include::example$transactions-example.php[tag=queryExamplesComplex,indent=0] +include::devguide:example$php/transactions-example.php[tag=queryExamplesComplex,indent=0] ---- As you can see from the snippet above, it is possible to call regular PHP functions from the {lambda}, permitting complex logic to be performed. @@ -192,7 +192,7 @@ This example shows inserting a document and then selecting it again: [source,php] ---- -include::example$transactions-example.php[tag=queryRYOW,indent=0] +include::devguide:example$php/transactions-example.php[tag=queryRYOW,indent=0] ---- <1> The inserted document is only staged at this point, as the transaction has not yet committed. + Other transactions, and other non-transactional actors, will not be able to see this staged insert yet. @@ -204,7 +204,7 @@ Query options can be provided via `TransactionQueryOptions`, which provides a su [source,php] ---- -include::example$transactions-example.php[tag=queryOptions,indent=0] +include::devguide:example$php/transactions-example.php[tag=queryOptions,indent=0] ---- .Supported Transaction Query Options @@ -233,7 +233,7 @@ In this example we insert a document with a key-value operation, and read it wit [source,php] ---- -include::example$transactions-example.php[tag=queryKvMix,indent=0] +include::devguide:example$php/transactions-example.php[tag=queryKvMix,indent=0] ---- <1> The key-value insert operation is only staged, and so it is not visible to other transactions or non-transactional actors. @@ -246,7 +246,7 @@ For example, if you want to change the level of durability which must be attaine [source,php] ---- -include::example$transactions-example.php[tag=config,indent=0] +include::devguide:example$php/transactions-example.php[tag=config,indent=0] ---- include::{version-common}@sdk:shared:partial$acid-transactions.adoc[tag=config] diff --git a/modules/howtos/pages/error-handling.adoc b/modules/howtos/pages/error-handling.adoc index ec693665..06b454e4 100644 --- a/modules/howtos/pages/error-handling.adoc +++ b/modules/howtos/pages/error-handling.adoc @@ -55,7 +55,7 @@ Transient errors -- such as those caused by resource starvation -- are best tack [source,php] ---- -include::example$errors.php[tag=retry] +include::devguide:example$php/errors.php[tag=retry] ---- == Key-Value Errors @@ -68,7 +68,7 @@ If a particular key cannot be found it is raised as a `DocumentNotFoundException [source,php] ---- -include::example$errors.php[tag=document-not-found-exception] +include::devguide:example$php/errors.php[tag=document-not-found-exception] ---- === Key already exists @@ -77,14 +77,14 @@ On the other hand if the key already exists and should not (e.g. on an insert) t [source,php] ---- -include::example$errors.php[tag=key-exists-exception] +include::devguide:example$php/errors.php[tag=key-exists-exception] ---- === Document body too large [source,php] ---- -include::example$errors.php[tag=value-too-big-exception] +include::devguide:example$php/errors.php[tag=value-too-big-exception] ---- === Concurrency @@ -94,7 +94,7 @@ When you get a document you automatically receive its CAS value, and when replac [source,php] ---- -include::example$errors.php[tag=cas-mismatch-exception, indent=0] +include::devguide:example$php/errors.php[tag=cas-mismatch-exception, indent=0] ---- @@ -113,7 +113,7 @@ For instance, for inserts, they can simply be retried to see if they fail on `Do [source,scala] ---- -include::example$ErrorHandling.scala[tag=insert,indent=0] +include::devguide:example$php/ErrorHandling.scala[tag=insert,indent=0] ---- That example is much closer to what an application will want to be doing. Let's flesh it out further. @@ -123,7 +123,7 @@ The application can write wrappers so that it can easily do operations without h [source,scala] ---- -include::example$ErrorHandling.scala[tag=insert-real,indent=0] +include::devguide:example$php/ErrorHandling.scala[tag=insert-real,indent=0] ---- This will make a 'best effort' to do the insert (though its retry strategy is rather naive, and applications may want to implement a more sophisticated approach involving exponential backoff and circuit breaking.) @@ -147,7 +147,7 @@ A SQL++ query either returns results or `QueryError`, like so: [source,scala] ---- -include::example$ErrorHandling.scala[tag=query,indent=0] +include::devguide:example$php/ErrorHandling.scala[tag=query,indent=0] ---- Analytics works in an identical fashion, raising an `AnalyticsError`. diff --git a/modules/howtos/pages/full-text-searching-with-sdk.adoc b/modules/howtos/pages/full-text-searching-with-sdk.adoc index d72a2958..fc23ba3b 100644 --- a/modules/howtos/pages/full-text-searching-with-sdk.adoc +++ b/modules/howtos/pages/full-text-searching-with-sdk.adoc @@ -33,7 +33,7 @@ For the purposes of the below examples we will use the Travel Sample bucket with [source,json] ---- -include::example$search.php[tag=indexdefinition] +include::devguide:example$php/search.php[tag=indexdefinition] ---- Search queries are executed at Cluster level (not bucket or collection). As of Couchbase Server 6.5+ they do also not @@ -44,7 +44,7 @@ Here is a simple MatchQuery that looks for the text “swanky” using a defined [source,php] ---- -include::example$search.php[tag=matchquery] +include::devguide:example$php/search.php[tag=matchquery] ---- All simple query types are created in the same manner, although some have additional properties, which can be seen in @@ -55,7 +55,7 @@ Here is a numeric range query that looks for hotels with `"Cleanliness"` ratings [source,php] ---- -include::example$search.php[tag=numrangequery] +include::devguide:example$php/search.php[tag=numrangequery] ---- Queries can also be combined together. @@ -63,7 +63,7 @@ A conjunction query contains multiple child queries; its result documents must s [source,php] ---- -include::example$search.php[tag=conjunctionquery] +include::devguide:example$php/search.php[tag=conjunctionquery] ---- [TIP] @@ -103,7 +103,7 @@ Facets can only be accessed once `Close` has been called on rows. [source,php] ---- -include::example$search-facets.php[tag=iteratingfacets] +include::devguide:example$php/search-facets.php[tag=iteratingfacets] ---- @@ -123,7 +123,7 @@ And note that traditional FTS queries, without vector search, are also supported [source,php] ---- -include::example$search.php[tag=traditionalftsquery] +include::devguide:example$php/search.php[tag=traditionalftsquery] ---- The `SearchQuery` is created in the same way as detailed earlier. @@ -136,7 +136,7 @@ ensuring results contain information from updated indexes: [source,php] ---- -include::example$search.php[tag=consistency] +include::devguide:example$php/search.php[tag=consistency] ---- diff --git a/modules/howtos/pages/kv-operations.adoc b/modules/howtos/pages/kv-operations.adoc index ee2c9ae3..5b01b3eb 100644 --- a/modules/howtos/pages/kv-operations.adoc +++ b/modules/howtos/pages/kv-operations.adoc @@ -37,14 +37,14 @@ Here is the _Insert_ operation at its simplest: [source,php] ---- -include::example$kv-crud.php[tag=insert] +include::devguide:example$php/kv-crud.php[tag=insert] ---- Options may be added to operations: [source,php] ---- -include::example$kv-crud.php[tag=insertwithoptions] +include::devguide:example$php/kv-crud.php[tag=insertwithoptions] ---- Setting a Compare and Swap (CAS) value is a form of optimistic locking - dealt with in depth in the xref:concurrent-document-mutations.adoc[CAS page]. @@ -58,7 +58,7 @@ We will add to these options for the _Replace_ example: [source,php] ---- -include::example$kv-crud.php[tag=replacewithcas] +include::devguide:example$php/kv-crud.php[tag=replacewithcas] ---- The example above also shows how to handle the case when optimistic falure will fail. @@ -70,7 +70,7 @@ xref:{version-server}@server:learn:buckets-memory-and-storage/expiration.adoc#ex [source,php] ---- -include::example$kv-crud.php[tag=upsertwithexpiry] +include::devguide:example$php/kv-crud.php[tag=upsertwithexpiry] ---- // TODO: old-style durability will come later @@ -99,7 +99,7 @@ The following example demonstrates using the newer durability features available [source,php] ---- -include::example$kv-crud.php[tag=upsertwithdurability] +include::devguide:example$php/kv-crud.php[tag=upsertwithdurability] ---- To stress, durability is a useful feature but should not be the default for most applications, as there is a performance consideration, @@ -159,14 +159,14 @@ Using the `Get()` method with the document key can be done in a similar fashion [source,php] ---- -include::example$kv-crud.php[tag=get] +include::devguide:example$php/kv-crud.php[tag=get] ---- Timeout can also be set - as in the earlier `Insert` example: [source,php] ---- -include::example$kv-crud.php[tag=getwithoptions] +include::devguide:example$php/kv-crud.php[tag=getwithoptions] ---- @@ -177,7 +177,7 @@ When removing a document, you will have the same concern for durability as with Remove (with options) [source,php] ---- -include::example$kv-crud.php[tag=removewithoptions] +include::devguide:example$php/kv-crud.php[tag=removewithoptions] ---- // TODO: old-style durability will come later @@ -191,21 +191,21 @@ NOTE: Increment & Decrement are considered part of the ‘binary’ API and as s [source,php] ---- -include::example$kv-expiry.php[tag=touch] +include::devguide:example$php/kv-expiry.php[tag=touch] ---- A network timeout can be set with the optional `TouchOptions()`, in the same fashion as earlier examples on this page: [source,php] ---- -include::example$kv-expiry.php[tag=touchwithoptions] +include::devguide:example$php/kv-expiry.php[tag=touchwithoptions] ---- Another way to change expiration time is to use `getAndTouch()` method of the collection. [source,php] ---- -include::example$kv-expiry.php[tag=getandtouch] +include::devguide:example$php/kv-expiry.php[tag=getandtouch] ---- @@ -219,24 +219,24 @@ NOTE: Increment & Decrement are considered part of the ‘binary’ API and as s .Increment [source,php] ---- -include::example$kv-counter.php[tag=increment] +include::devguide:example$php/kv-counter.php[tag=increment] ---- [source,php] ---- -include::example$kv-counter.php[tag=incrementwithoptions] +include::devguide:example$php/kv-counter.php[tag=incrementwithoptions] ---- .Decrement [source,php] ---- -include::example$kv-counter.php[tag=decrement] +include::devguide:example$php/kv-counter.php[tag=decrement] ---- .Decrement (With Options) [source,php] ---- -include::example$kv-counter.php[tag=decrementwithoptions] +include::devguide:example$php/kv-counter.php[tag=decrementwithoptions] ---- TIP: Setting the document expiry time only works when a document is created, and it is not possible to update the expiry time of an existing counter document with the Increment method -- to do this during an increment, use with the `Touch()` method. @@ -262,7 +262,7 @@ Here's an example of a KV range scan that gets all documents in a collection: .KV Range Scan for all documents in a collection [source,php] ---- -include::example$kv-crud.php[tag=rangescanalldocuments] +include::devguide:example$php/kv-crud.php[tag=rangescanalldocuments] ---- <1> The `RangeScan` class has two optional parameters: `from` and `to`. @@ -282,7 +282,7 @@ For example, to get all documents associated with user "alice", you would write: .KV Range Scan for all documents in a collection whose IDs start with `alice::` [source,php] ---- -include::example$kv-crud.php[tag=rangescanprefix] +include::devguide:example$php/kv-crud.php[tag=rangescanprefix] ---- <1> Note the scan type is `PrefixScan` @@ -295,7 +295,7 @@ If you want to get random documents from a collection, use a sample scan. .KV Range Scan for 100 random documents [source,php] ---- -include::example$kv-crud.php[tag=rangescansample] +include::devguide:example$php/kv-crud.php[tag=rangescansample] ---- [#kv-range-scan-only-ids] @@ -306,7 +306,7 @@ If you only want the document IDs, set the `idsOnly()` in `ScanOptions` to `true .KV Range Scan for all document IDs in a collection [source,php] ---- -include::example$kv-crud.php[tag=rangescanalldocumentids] +include::devguide:example$php/kv-crud.php[tag=rangescanalldocumentids] ---- == Scoped KV Operations @@ -321,7 +321,7 @@ Here is an example showing an upsert in the `users` collection, which lives in t [source,php] ---- -include::example$kv-crud.php[tag=namedcollectionupsert] +include::devguide:example$php/kv-crud.php[tag=namedcollectionupsert] ---- == Additional Resources diff --git a/modules/howtos/pages/managing-connections.adoc b/modules/howtos/pages/managing-connections.adoc index 93daddaa..b7b47585 100644 --- a/modules/howtos/pages/managing-connections.adoc +++ b/modules/howtos/pages/managing-connections.adoc @@ -18,7 +18,7 @@ The simplest way to create a `Cluster` is to call `new Cluster()` with a <> option: [source,php] ---- -include::example$subdoc-mutatein-arrays.php[tag=mutateInArrayAppendCreatePath] +include::devguide:example$php/subdoc-mutatein-arrays.php[tag=mutateInArrayAppendCreatePath] ---- // TODO: SDK will have fluent API to set spec options more verbosely like isXattr(false)->withCreateParents(true) @@ -177,7 +177,7 @@ This will do a check to determine if the given value exists or not before actual [source,php] ---- -include::example$subdoc-mutatein-arrays.php[tag=mutateInArrayAddUnique] +include::devguide:example$php/subdoc-mutatein-arrays.php[tag=mutateInArrayAddUnique] ---- Note that currently the _addunique_ will fail with a _Path Mismatch_ error if the array contains JSON _floats_, _objects_, or _arrays_. @@ -194,7 +194,7 @@ For example, to insert `"cruel"` as the second element in the array `["Hello", " [source,php] ---- -include::example$subdoc-mutatein-arrays.php[tag=mutateInArrayInsert] +include::devguide:example$php/subdoc-mutatein-arrays.php[tag=mutateInArrayInsert] ---- // for your examples, above, CD: “I feel like somewhere in this we should also just a an example path like "my.path[1]" too, just to show how to use the index with a nested path. I don't think it's necessarily clear.” @@ -209,7 +209,7 @@ These operations are logically similar to the _counter_ operation on an entire d [source,php] ---- -include::example$subdoc-counters.php[tag=mutateInIncrement] +include::devguide:example$php/subdoc-counters.php[tag=mutateInIncrement] ---- The _subdoc-counter_ operation performs simple arithmetic against a numeric value, either incrementing or decrementing the existing value. @@ -217,7 +217,7 @@ The new value is returned. [source,php] ---- -include::example$subdoc-counters.php[tag=mutateInDecrement] +include::devguide:example$php/subdoc-counters.php[tag=mutateInDecrement] ---- The existing value for _subdoc-counter_ operations must be within range of a 64 bit signed integer. @@ -276,7 +276,7 @@ In this case, the _create-path_ option may be used. [source,php] ---- -include::example$subdoc-mutatein.php[tag=mutateInCreatePath] +include::devguide:example$php/subdoc-mutatein.php[tag=mutateInCreatePath] ---- // TODO: php sdk will have fluent APi for subdocument specs @@ -290,7 +290,7 @@ The `Collection->lookupinAnyReplica()` method returns the first response -- from .Sub-Document read from any replica [source,php] ---- -include::example$subdoc-lookupin.php[tag=lookupinanyreplica] +include::devguide:example$php/subdoc-lookupin.php[tag=lookupinanyreplica] ---- The `Collection->lookupInAllReplicas()` method fetches all available replicas (and the active copy), and returns all responses: @@ -298,7 +298,7 @@ The `Collection->lookupInAllReplicas()` method fetches all available replicas (a .Sub-Document read from all replicas [source,php] ---- -include::example$subdoc-lookupin.php[tag=lookupinallreplicas] +include::devguide:example$php/subdoc-lookupin.php[tag=lookupinallreplicas] ---- == CAS Semantics @@ -309,7 +309,7 @@ For example the following two operations can execute concurrently without any ri [source,php] ---- -include::example$subdoc-concurrent.php[tag=mutateInConcurrent] +include::devguide:example$php/subdoc-concurrent.php[tag=mutateInConcurrent] ---- Even when modifying the _same_ part of the document, operations will not necessarily conflict. @@ -320,7 +320,7 @@ If CAS is required then it can be provided like this: [source,php] ---- -include::example$subdoc-mutatein.php[tag=mutateInCas] +include::devguide:example$php/subdoc-mutatein.php[tag=mutateInCas] ---- == Durability @@ -329,7 +329,7 @@ In Couchbase Server 6.5 and up, this is built upon with xref:concept-docs:durabi [source,php] ---- -include::example$subdoc-mutatein-durability.php[tag=mutateInDurableWrites] +include::devguide:example$php/subdoc-mutatein-durability.php[tag=mutateInDurableWrites] ---- diff --git a/modules/howtos/pages/transcoders-nonjson.adoc b/modules/howtos/pages/transcoders-nonjson.adoc index b918d8f6..f9d630f2 100644 --- a/modules/howtos/pages/transcoders-nonjson.adoc +++ b/modules/howtos/pages/transcoders-nonjson.adoc @@ -81,21 +81,21 @@ First we will create the encoder function: [source,php] ---- -include::example$transcoding.php[tag=encoder,indent=0] +include::devguide:example$php/transcoding.php[tag=encoder,indent=0] ---- And now create a corresponding decoder function: [source,php] ---- -include::example$transcoding.php[tag=decoder,indent=0] +include::devguide:example$php/transcoding.php[tag=decoder,indent=0] ---- To use these functions with some data we can do the following and our image will be seamlessly stored in Couchbase Server: [source,php] ---- -include::example$transcoding.php[tag=usage,indent=0] +include::devguide:example$php/transcoding.php[tag=usage,indent=0] ---- == Configuration diff --git a/modules/howtos/pages/vector-searching-with-sdk.adoc b/modules/howtos/pages/vector-searching-with-sdk.adoc index e0a89194..dfdfc0b8 100644 --- a/modules/howtos/pages/vector-searching-with-sdk.adoc +++ b/modules/howtos/pages/vector-searching-with-sdk.adoc @@ -52,7 +52,7 @@ wrapped inside the {name-sdk} Query API. .Hyperscale Index Example [source,php] ---- -include::example$query.php[indent=0,tag=VectorSearchWithQueryHyperscaleIndex] +include::devguide:example$php/query.php[indent=0,tag=VectorSearchWithQueryHyperscaleIndex] ---- Parameterizing the query, as with xref:sqlpp-queries-with-sdk.adoc#parameterized-queries[regular queries], will allow the reuse of the xref:server:n1ql:n1ql-intro/queriesandresults.adoc#prepare-stmts[Query Plan]. @@ -61,7 +61,7 @@ This can be more efficient, unless you are doing a lot of optimization to your q .Parameterized Vector Query [source,php] ---- -include::example$query.php[indent=0,tag=VectorSearchWithQueryParameterized] +include::devguide:example$php/query.php[indent=0,tag=VectorSearchWithQueryParameterized] ---- @@ -82,7 +82,7 @@ Couchbase Server 7.6.0 (7.6.2 for base64-encoded vectors) — or recent Cape In this first example we are performing a single vector query: [source,php] ---- -include::example$search.php[tag=singlevectorquery] +include::devguide:example$php/search.php[tag=singlevectorquery] ---- Let's break this down. @@ -107,7 +107,7 @@ You can run multiple vector queries together: [source,php] ---- -include::example$search.php[tag=multiplevectorqueries] +include::devguide:example$php/search.php[tag=multiplevectorqueries] ---- How the results are combined (ANDed or ORed) can be controlled with `VectorSearchOptions::vectorQueryCombination()`. @@ -117,7 +117,7 @@ You can combine a traditional Search query with vector queries: [source,php] ---- -include::example$search.php[tag=combinedvectorquery] +include::devguide:example$php/search.php[tag=combinedvectorquery] ---- @@ -170,7 +170,7 @@ You can run multiple vector queries together: [source,php] ---- -include::example$search.php[indent=0,tag=multiplevectorqueries] +include::devguide:example$php/search.php[indent=0,tag=multiplevectorqueries] ---- Note that `num_candidates` sets how many similar vectors are returned. @@ -185,7 +185,7 @@ You can combine a traditional Search query with vector queries: [source,php] ---- -include::example$search.php[indent=0,tag=combinedvectorquery] +include::devguide:example$php/search.php[indent=0,tag=combinedvectorquery] ---- How the results are combined (ANDed or ORed) can be controlled with `VectorSearchOptions::vectorQueryCombination()`. From 39b4e133a09ed42f3370b28e5fa8adb59fc72ab5 Mon Sep 17 00:00:00 2001 From: Richard Smedley Date: Wed, 3 Jun 2026 14:08:33 +0100 Subject: [PATCH 2/3] temp removal to fix symlink-induced breakage --- modules/devguide/examples | 1 - modules/devguide/striptags.rb | 39 ----------------------------------- 2 files changed, 40 deletions(-) delete mode 160000 modules/devguide/examples delete mode 100755 modules/devguide/striptags.rb diff --git a/modules/devguide/examples b/modules/devguide/examples deleted file mode 160000 index 6a59c83d..00000000 --- a/modules/devguide/examples +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6a59c83df2b42155a17f91c06dfa34e6b9d44d6b diff --git a/modules/devguide/striptags.rb b/modules/devguide/striptags.rb deleted file mode 100755 index 803e971c..00000000 --- a/modules/devguide/striptags.rb +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/ruby - -project = "docs-sdk-php" -current_branch = `git branch --show-current`.strip -header_template = < Date: Wed, 3 Jun 2026 14:10:04 +0100 Subject: [PATCH 3/3] DOC-14413 all examples --- modules/devguide/examples/php/analytics.php | 81 +++ modules/devguide/examples/php/auth.php | 32 ++ modules/devguide/examples/php/batch.php | 52 ++ modules/devguide/examples/php/cloud.php | 51 ++ .../examples/php/collection-manager.php | 88 +++ .../examples/php/collections-concept.php | 27 + modules/devguide/examples/php/connections.php | 8 + .../devguide/examples/php/customer123.json | 24 + .../examples/php/documents-concept.php | 67 +++ modules/devguide/examples/php/durability.php | 20 + modules/devguide/examples/php/errors.php | 83 +++ modules/devguide/examples/php/kv-counter.php | 61 ++ modules/devguide/examples/php/kv-crud.php | 144 +++++ modules/devguide/examples/php/kv-expiry.php | 66 +++ modules/devguide/examples/php/logging.php | 19 + .../examples/php/managing-connections.php | 36 ++ .../devguide/examples/php/n1ql-concept.php | 89 +++ .../devguide/examples/php/orphan-logging.php | 62 ++ .../php/provisioning-resources-buckets.php | 69 +++ .../php/provisioning-resources-users.php | 104 ++++ .../examples/php/query-index-manager.php | 113 ++++ modules/devguide/examples/php/query.php | 123 ++++ .../devguide/examples/php/search-facets.php | 205 +++++++ modules/devguide/examples/php/search.php | 193 +++++++ modules/devguide/examples/php/start-using.php | 47 ++ .../examples/php/subdoc-concurrent.php | 46 ++ .../devguide/examples/php/subdoc-counters.php | 32 ++ .../devguide/examples/php/subdoc-lookupin.php | 62 ++ .../examples/php/subdoc-mutatein-arrays.php | 84 +++ .../php/subdoc-mutatein-durability.php | 22 + .../devguide/examples/php/subdoc-mutatein.php | 52 ++ .../examples/php/threshold-logging.php | 65 +++ .../examples/php/transactions-example.php | 535 ++++++++++++++++++ modules/devguide/examples/php/transcoding.php | 113 ++++ modules/devguide/examples/php/using-cas.php | 66 +++ modules/devguide/striptags.rb | 39 ++ 36 files changed, 2980 insertions(+) create mode 100644 modules/devguide/examples/php/analytics.php create mode 100644 modules/devguide/examples/php/auth.php create mode 100644 modules/devguide/examples/php/batch.php create mode 100644 modules/devguide/examples/php/cloud.php create mode 100644 modules/devguide/examples/php/collection-manager.php create mode 100644 modules/devguide/examples/php/collections-concept.php create mode 100644 modules/devguide/examples/php/connections.php create mode 100644 modules/devguide/examples/php/customer123.json create mode 100644 modules/devguide/examples/php/documents-concept.php create mode 100644 modules/devguide/examples/php/durability.php create mode 100644 modules/devguide/examples/php/errors.php create mode 100644 modules/devguide/examples/php/kv-counter.php create mode 100644 modules/devguide/examples/php/kv-crud.php create mode 100644 modules/devguide/examples/php/kv-expiry.php create mode 100644 modules/devguide/examples/php/logging.php create mode 100644 modules/devguide/examples/php/managing-connections.php create mode 100644 modules/devguide/examples/php/n1ql-concept.php create mode 100644 modules/devguide/examples/php/orphan-logging.php create mode 100644 modules/devguide/examples/php/provisioning-resources-buckets.php create mode 100644 modules/devguide/examples/php/provisioning-resources-users.php create mode 100644 modules/devguide/examples/php/query-index-manager.php create mode 100644 modules/devguide/examples/php/query.php create mode 100644 modules/devguide/examples/php/search-facets.php create mode 100644 modules/devguide/examples/php/search.php create mode 100644 modules/devguide/examples/php/start-using.php create mode 100644 modules/devguide/examples/php/subdoc-concurrent.php create mode 100644 modules/devguide/examples/php/subdoc-counters.php create mode 100644 modules/devguide/examples/php/subdoc-lookupin.php create mode 100644 modules/devguide/examples/php/subdoc-mutatein-arrays.php create mode 100644 modules/devguide/examples/php/subdoc-mutatein-durability.php create mode 100644 modules/devguide/examples/php/subdoc-mutatein.php create mode 100644 modules/devguide/examples/php/threshold-logging.php create mode 100644 modules/devguide/examples/php/transactions-example.php create mode 100644 modules/devguide/examples/php/transcoding.php create mode 100644 modules/devguide/examples/php/using-cas.php create mode 100755 modules/devguide/striptags.rb diff --git a/modules/devguide/examples/php/analytics.php b/modules/devguide/examples/php/analytics.php new file mode 100644 index 00000000..6d1c0f80 --- /dev/null +++ b/modules/devguide/examples/php/analytics.php @@ -0,0 +1,81 @@ +credentials("Administrator", "password"); +$cluster = new \Couchbase\Cluster($connectionString, $options); + +$bucket = $cluster->bucket("travel-sample"); + +// #tag::query[] +$options = new \Couchbase\AnalyticsOptions(); +$result = $cluster->analyticsQuery('SELECT "hello" as greeting;', $options); + +foreach ($result->rows() as $row) { + printf("result: %s\n", $row["greeting"]); +} +// #end::query[] + +// #tag::simple[] +$options = new \Couchbase\AnalyticsOptions(); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); +// #end::simple[] + +// #tag::positional[] +$options = new \Couchbase\AnalyticsOptions(); +$options->positionalParameters(["France"]); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = $1;', $options); +// #end::positional[] + +// #tag::named[] +$options = new \Couchbase\AnalyticsOptions(); +$options->namedParameters(['$country' => "France"]); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = $country;', $options); +// #end::named[] + +// #tag::options[] +$options = new \Couchbase\AnalyticsOptions(); +$options->timeout(100); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); +// #end::options[] + +// #tag::results[] +$options = new \Couchbase\AnalyticsOptions(); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); + +foreach ($result->rows() as $row) { + printf("Name: %s, Country: %s\n", $row["airportname"], $row["country"]); +} +// #end::results[] + +// #tag::metadata[] +$options = new \Couchbase\AnalyticsOptions(); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM airports WHERE country = "France";', $options); + +$metadata = $result->metadata(); +$metrics = $metadata->metrics(); +printf("Elapsed time: %d\n", $metrics["elapsedTime"]); +printf("Execution time: %d\n", $metrics["executionTime"]); +printf("Result count: %d\n", $metrics["resultCount"]); +// #tag::metadata[] + +// tag::handle-collection[] +$options = new \Couchbase\AnalyticsOptions(); +$result = $cluster->analyticsQuery( + 'SELECT airportname, country FROM `travel-sample`.inventory.airport WHERE country = "France" LIMIT 3;', + $options +); + +foreach ($result->rows() as $row) { + printf("Name: %s, Country: %s\n", $row["airportname"], $row["country"]); +} +// end::handle-collection[] + +// tag::handle-scope[] +$scope = $bucket->scope("inventory"); +$options = new \Couchbase\AnalyticsOptions(); +$result = $cluster->analyticsQuery('SELECT airportname, country FROM `airports` WHERE country = "France" LIMIT 2;', $options); + +foreach ($result->rows() as $row) { + printf("Name: %s, Country: %s\n", $row["airportname"], $row["country"]); +} +// end::handle-scope[] diff --git a/modules/devguide/examples/php/auth.php b/modules/devguide/examples/php/auth.php new file mode 100644 index 00000000..4632e265 --- /dev/null +++ b/modules/devguide/examples/php/auth.php @@ -0,0 +1,32 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $options); +$bucket = $cluster->bucket("travel-sample"); +// end::auth1[] + +// tag::auth2[] +$options = new ClusterOptions(); +$options->credentials("Administrator", "password"); + +# authentication with TLS client certificate +$connectionString = "couchbases://localhost?" . + "truststorepath=/path/to/ca/certificates.pem&" . + "certpath=/path/to/client/certificate.pem&" . + "keypath=/path/to/client/key.pem"; + +$cluster = new Cluster($connectionString, $options); +$bucket = $cluster->bucket("travel-sample"); +// end::auth2[] + +// tag::auth3[] +$options = new ClusterOptions(); +$options->credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost?sasl_mech_force=PLAIN", $options); +$bucket = $cluster->bucket("travel-sample"); +// end::auth3[] diff --git a/modules/devguide/examples/php/batch.php b/modules/devguide/examples/php/batch.php new file mode 100644 index 00000000..16b3f91f --- /dev/null +++ b/modules/devguide/examples/php/batch.php @@ -0,0 +1,52 @@ +credentials("Administrator", "password"); + $cluster = new Cluster("couchbase://localhost", $options); + $collection = $cluster->bucket("travel-sample")->scope("inventory")->collection("airport"); + foreach ($batch as $path) { + $collection->upsert($path, json_decode(file_get_contents($path))); + } +} +// #end::batching[] diff --git a/modules/devguide/examples/php/cloud.php b/modules/devguide/examples/php/cloud.php new file mode 100644 index 00000000..c41ea2ba --- /dev/null +++ b/modules/devguide/examples/php/cloud.php @@ -0,0 +1,51 @@ +.cloud.couchbase.com"; +$options = new ClusterOptions(); + +$options->credentials("username", "Password!123"); +// Sets a pre-configured profile called "wan_development" to help avoid latency issues +// when accessing Capella from a different Wide Area Network +// or Availability Zone (e.g. your laptop). +$options->applyProfile("wan_development"); +$cluster = new Cluster($connectionString, $options); +// end::connect[] + +// tag::bucket[] +// get a bucket reference +$bucket = $cluster->bucket("travel-sample"); +// end::bucket[] + +// tag::collection[] +// get a user-defined collection reference +$scope = $bucket->scope("tenant_agent_00"); +$collection = $scope->collection("users"); +// end::collection[] + +// tag::upsert-get[] +$upsertResult = $collection->upsert("my-document-key", ["name" => "Ted", "Age" => 31]); + +$getResult = $collection->get("my-document-key"); + +print_r($getResult->content()); +// end::upsert-get[] + +// tag::n1ql-query[] +$inventoryScope = $bucket->scope("inventory"); +$queryResult = $inventoryScope->query("SELECT * FROM airline WHERE id = 10"); + +// Print result data to the terminal. +foreach ($queryResult->rows() as $row) { + print_r($row); +} +// end::n1ql-query[] diff --git a/modules/devguide/examples/php/collection-manager.php b/modules/devguide/examples/php/collection-manager.php new file mode 100644 index 00000000..89a10b9e --- /dev/null +++ b/modules/devguide/examples/php/collection-manager.php @@ -0,0 +1,88 @@ +credentials("Administrator", "password"); + $cluster = new \Couchbase\Cluster($connectionString, $options); + + $bucket = $cluster->bucket("travel-sample"); + + + print "scopeAdmin\n"; + // tag::scopeAdmin[] + $users = $cluster->users(); + + $user = new \Couchbase\User(); + $user->setUsername("scopeAdmin"); + $user->setDisplayName("Manage Scopes [travel-sample]"); + $user->setPassword("password"); + $user->setRoles([ + (new \Couchbase\Role)->setName("scope_admin")->setBucket("travel-sample"), + (new \Couchbase\Role)->setName("data_reader")->setBucket("travel-sample") + ]); + + $users->upsertUser($user); + // end::scopeAdmin[] + + print "create-collection-manager\n"; + + // tag::create-collection-manager[] + $options = new \Couchbase\ClusterOptions(); + $options->credentials("scopeAdmin", "password"); + $cluster = new \Couchbase\Cluster("localhost", $options); + $bucket = $cluster->bucket("travel-sample"); + + $collections = $bucket->collections(); + // end::create-collection-manager[] + + print "create-scope\n"; + // tag::create-scope[] + try { + $collections->createScope("example-scope"); + } + catch (Exception $e) { + print $e; + } + // end::create-scope[] + + print "create-collection\n"; + // tag::create-collection[] + $collection = new \Couchbase\CollectionSpec(); + $collection->setName("example-collection"); + $collection->setScopeName("example-scope"); + + try { + $collections->createCollection($collection); + } + catch (Exception $e) { + print $e; + } + // end::create-collection[] + + print "listing-scope-collection\n"; + // tag::listing-scope-collection[] + $scopes = $collections->getAllScopes(); + foreach ($scopes as $scope) { + print "Scope {$scope->name()}\n"; + + foreach ($scope->collections() as $collection) { + print " - {$collection->name()}\n"; + } + } + // end::listing-scope-collection[] + + print "drop-collection\n"; + // tag::drop-collection[] + $collections->dropCollection($collection); + // end::drop-collection[] + + print "drop-scope\n"; + // tag::drop-scope[] + $collections->dropScope("example-scope"); + // end::drop-scope[] + +} + +main(); + diff --git a/modules/devguide/examples/php/collections-concept.php b/modules/devguide/examples/php/collections-concept.php new file mode 100644 index 00000000..be781758 --- /dev/null +++ b/modules/devguide/examples/php/collections-concept.php @@ -0,0 +1,27 @@ +credentials('Administrator', 'password'); + +$cluster = new Cluster($connectionString, $options); +$bucket = $cluster->bucket('travel-sample'); + +$collectionMgr = $bucket->collections(); + +$spec = new CollectionSpec(); +$spec->setName('bookings'); +$spec->setScopeName('_default'); + +$collectionMgr->createCollection($spec); + +// tag::collections_1[] +$bucket->scope('_default')->collection('bookings'); +// end::collections_1[] + +// tag::collections_2[] +$bucket->scope('tenant_agent_00')->collection('bookings'); +// end::collections_2[] diff --git a/modules/devguide/examples/php/connections.php b/modules/devguide/examples/php/connections.php new file mode 100644 index 00000000..e9b745f5 --- /dev/null +++ b/modules/devguide/examples/php/connections.php @@ -0,0 +1,8 @@ +credentials("Administrator", "password"); +$cluster = new \Couchbase\Cluster($connectionString, $opts); +// end::rbac[] diff --git a/modules/devguide/examples/php/customer123.json b/modules/devguide/examples/php/customer123.json new file mode 100644 index 00000000..1d7c72e8 --- /dev/null +++ b/modules/devguide/examples/php/customer123.json @@ -0,0 +1,24 @@ +{ + "name": "Douglas Reynholm", + "email": "douglas@reynholmindustries.com", + "addresses": { + "billing": { + "line1": "123 Any Street", + "line2": "Anytown", + "country": "United Kingdom" + }, + "delivery": { + "line1": "123 Any Street", + "line2": "Anytown", + "country": "United Kingdom" + } + }, + "purchases": { + "complete": [ + 339, 976, 442, 666 + ], + "abandoned": [ + 157, 42, 999 + ] + } +} diff --git a/modules/devguide/examples/php/documents-concept.php b/modules/devguide/examples/php/documents-concept.php new file mode 100644 index 00000000..4413b742 --- /dev/null +++ b/modules/devguide/examples/php/documents-concept.php @@ -0,0 +1,67 @@ +credentials('Administrator', 'password'); + +$cluster = new Cluster($connectionString, $clusterOpts); +$bucket = $cluster->bucket('travel-sample'); +$collection = $bucket->scope('inventory')->collection('airline'); + +print("Example - [mutate-in]\n"); +// tag::mutate-in[] +$result = $collection->mutateIn('airline_10', [ + new MutateUpsertSpec('msrp', 18.00) +]); +// end::mutate-in[] + +print("Example - [lookup-in]\n"); +// tag::lookup-in[] +$usersCollection = $bucket->scope('tenant_agent_00')->collection('users'); +$usersCollection->lookupIn('1', [ + new LookupGetSpec('credit_cards[0].type'), + new LookupGetSpec('credit_cards[0].expiration') +]); +// end::lookup-in[] + +print("Example - [counters]\n"); +// tag::counters[] +$counterDocId = 'counter-doc'; +$decrementOpts = new DecrementOptions(); +$incrementOpts = new IncrementOptions(); +// Increment by 1, creating doc if needed. +// By using `initial(1)` we set the starting count(non-negative) to 1 if the document needs to be created. +// If it already exists, the count will increase by 1. +$collection->binary()->increment($counterDocId, $incrementOpts->initial(1)); +// Decrement by 1 +$collection->binary()->decrement($counterDocId); +// Decrement by 5 +$collection->binary()->decrement($counterDocId, $decrementOpts->delta(5)); +// end::counters[] + +print("Example - [counter-increment]\n"); +// tag::counter-increment[] +$result = $collection->get('counter-doc'); +$value = $result->content(); +$incrementAmnt = 5; + +if (shouldIncrementValue($value)) { + $opts = new ReplaceOptions(); + $opts->cas($result->cas()); + $collection->replace('counter-doc', $value + $incrementAmnt, $opts); +} +// end::counter-increment[] +printf("RESULT: %d", $value + $incrementAmnt); + +function shouldIncrementValue($value): bool { + printf("Current value: %d\n", $value); + return $value == 0; +} diff --git a/modules/devguide/examples/php/durability.php b/modules/devguide/examples/php/durability.php new file mode 100644 index 00000000..55b1e7f9 --- /dev/null +++ b/modules/devguide/examples/php/durability.php @@ -0,0 +1,20 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("inventory")->collection("airport"); + +// #tag::enhanced[] +$document = ["foo" => "bar", "bar" => "foo"]; +// Upsert with Durability level Majority +$opts = new UpsertOptions(); +$opts->durabilityLevel(DurabilityLevel::MAJORITY); +$res = $collection->upsert("durable-key", $document, $opts); +printf("Successfully created document \"durable-key\". CAS=\"%s\"\n", $res->cas()); +// #end::enhanced[] diff --git a/modules/devguide/examples/php/errors.php b/modules/devguide/examples/php/errors.php new file mode 100644 index 00000000..c17e3249 --- /dev/null +++ b/modules/devguide/examples/php/errors.php @@ -0,0 +1,83 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("inventory")->collection("airport"); + + +// tag::document-not-found-exception[] +try { + $collection->get("foo"); +} catch (\Couchbase\Exception\DocumentNotFoundException $ex) { + printf("Document does not exist, creating. \n"); + $collection->upsert("foo", ["bar" => 42]); +} +// end::document-not-found-exception[] + + +// tag::key-exists-exception[] +try { + $collection->insert("foo", ["bar" => 43]); +} catch (\Couchbase\KeyExistsException $ex) { + printf("Document already exists. \n"); +} +// end::key-exists-exception[] + +$max_size = 1024 * 1024 * 20; # 20MB +$big_object = str_repeat(' ', $max_size + 1); + +// tag::value-too-big-exception[] +try { + $collection->insert("big", $big_object); +} catch (\Couchbase\ValueTooBigException $ex) { + printf("Document is bigger than maximum size (20MB). \n"); +} +// end::value-too-big-exception[] + + +// tag::cas-mismatch-exception[] +$result1 = $collection->get("foo"); +$original_cas = $result1->cas(); + +$opts = new \Couchbase\ReplaceOptions(); + +$result2 = $collection->replace("foo", + ["bar" => 44], + $opts->cas($original_cas)); +$updated_cas = $result2->cas(); + +try { + $collection->replace("foo", + ["bar" => 45], + $opts->cas($original_cas)); + # oops, we should have used $updated_cas! +} catch (\Couchbase\Exception\CasMismatchException $ex) { + printf("CAS mismatch error. \n"); +} +// end::cas-mismatch-exception[] + + +// tag::retry[] +$max_attempts = 5; +for ($attempt = 1; $attempt <= $max_attempts; $attempt++) { + printf("Attempt $attempt. \n"); + try { + $result = $collection->get("expected-document"); + break; + } + catch (\Couchbase\Exception\DocumentNotFoundException $ex) { + printf("Document still not created. \n"); + usleep(100); + continue; + } + catch (\Couchbase\NetworkException $ex) { + printf("An unrecoverable network exception happened! \n"); + break; + } +} +// end::retry[] diff --git a/modules/devguide/examples/php/kv-counter.php b/modules/devguide/examples/php/kv-counter.php new file mode 100644 index 00000000..221f0595 --- /dev/null +++ b/modules/devguide/examples/php/kv-counter.php @@ -0,0 +1,61 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->defaultCollection(); + +$collection->upsert("foo", 0); +// tag::increment[] +// increment binary value by 1 (default) +$binaryCollection = $collection->binary(); +$res = $binaryCollection->increment("foo"); +// end::increment[] + +// tag::decrement[] +// decremtnt binary value by 1 (default) +$res = $binaryCollection->decrement("foo"); +// end::decrement[] + +// Increment & Decrement are considered part of the 'binary' API +// and as such may still be a subject to change + +// tag::incrementwithoptions[] +// Create a document and assign it to 10 -- counter works atomically +// by first creating a document if it doesn't exist. If it exists, +// the same method will increment/decrement per the "delta" parameter +$key = "phpDevguideExampleCounter"; +$opts = new IncrementOptions(); +$opts->initial(10)->delta(2); + +$res = $binaryCollection->increment($key, $opts); +// Should print 10 +printf("Initialized Counter: %d\n", $res->content()); +// end::incrementwithoptions[] + +// Issue the same operation, increment value by 2 to 12 +$res = $binaryCollection->increment($key, $opts); +// Should print 12 +printf("Incremented Counter: %d\n", $res->content()); + +// tag::decrementwithoptions[] +$opts = new DecrementOptions(); +$opts->initial(10)->delta(4); +// Decrement value by 4 to 8 +$res = $binaryCollection->decrement($key, $opts); +// Should print 8 +printf("Decremented Counter: %d\n", $res->content()); +// end::decrementwithoptions[] + +// Output: +// +// Initialized Counter: 10 +// Incremented Counter: 12 +// Decremented Counter: 8 diff --git a/modules/devguide/examples/php/kv-crud.php b/modules/devguide/examples/php/kv-crud.php new file mode 100644 index 00000000..53ebf71c --- /dev/null +++ b/modules/devguide/examples/php/kv-crud.php @@ -0,0 +1,144 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->defaultCollection(); + +// tag::insert[] +$document = ["foo" => "bar", "bar" => "foo"]; +$res = $collection->insert("document-key-new", $document); +printf("document \"document-key-new\" has been created with CAS \"%s\"\n", $res->cas()); +// end::insert[] + +// Insert document with options +// tag::insertwithoptions[] +$document = ["foo" => "bar", "bar" => "foo"]; +$opts = new InsertOptions(); +$opts->timeout(300000 /* milliseconds */); +$res = $collection->insert("document-key", $document, $opts); +printf("document \"document-key\" has been created with CAS \"%s\"\n", $res->cas()); +// end::insertwithoptions[] + +// tag::replacewithcas[] +// Replace document with incorrect CAS +$opts = new ReplaceOptions(); +$opts->timeout(300000 /* milliseconds */); +$invalidCas = "776t3gAAAAA="; +$opts->cas($invalidCas); +try { + $collection->replace("document-key", $document, $opts); +} catch (\Couchbase\Exception\CasMismatchException $ex) { + printf("document \"document-key\" cannot be replaced with CAS \"%s\"\n", $invalidCas); +} + +// Get and Replace document with CAS +$res = $collection->get("document-key"); +$doc = $res->content(); +$doc["bar"] = "moo"; + +$opts = new ReplaceOptions(); +$oldCas = $res->cas(); +$opts->cas($oldCas); +$res = $collection->replace("document-key", $doc, $opts); +printf("document \"document-key\" \"%s\" been replaced successfully. New CAS \"%s\"\n", $oldCas, $res->cas()); +// end::replacewithcas[] + +// tag::removewithoptions[] +$opts = new RemoveOptions(); +$opts->timeout(5000); // 5 seconds +$result = $collection->remove("document-key", $opts); +printf("document \"document-key\" \"%s\" been removed successfully.\n", $res->cas()); +// end::removewithoptions[] + +// tag::upsertwithexpiry[] +$document = ["foo" => "bar", "bar" => "foo"]; +$opts = new UpsertOptions(); +$opts->expiry(60 * 1000 /* 60 seconds */); +$res = $collection->upsert("document-key", $document, $opts); +printf("document \"document-key\" has been created with CAS \"%s\"\n", $res->cas()); +// end::upsertwithexpiry[] + +// Get +// tag::get[] +$res = $collection->get("document-key"); +$doc = $res->content(); +printf("document \"document-key\" has content: \"%s\" CAS \"%s\"\n", json_encode($doc), $res->cas()); +// end::get[] + +// tag::getwithoptions[] +$opts = new GetOptions(); +$opts->timeout(3000 /* milliseconds */); +$res = $collection->get("document-key", $opts); +$doc = $res->content(); +printf("document \"document-key\" has content: \"%s\" CAS \"%s\"\n", json_encode($doc), $res->cas()); +// end::getwithoptions[] + +// tag::upsertwithdurability[] +// Upsert with Durability +$opts = new UpsertOptions(); +$opts->timeout(3000 /* milliseconds */); +$opts->durabilityLevel(DurabilityLevel::MAJORITY); +$res = $collection->upsert("document-key2", $opts); +printf("document \"document-key2\" has been created with CAS \"%s\"\n", $res->cas()); +// end::upsertwithdurability[] + +// tag::namedcollectionupsert[] +$document = ["name" => "John Doe", "preferred_email" => "johndoe111@test123.test"]; +$opts = new UpsertOptions(); + +$agentScope = $bucket->scope("tenant_agent_00"); +$usersCollection = $agentScope->collection("users"); + +$res = $usersCollection->upsert("user-key", $document, $opts); +printf("document \"user-key\" has been created with CAS \"%s\"\n", $res->cas()); +// end::namedcollectionupsert[] + +// Cleanup example data to avoid errors when running locally (mainly for inserts). +$opts = new RemoveOptions(); +$collection->remove("document-key-new", $opts); +$collection->remove("document-key", $opts); + +// tag::rangescanalldocuments[] +$results = $collection->scan(RangeScan::build()); +foreach ($results as $result) { + printf("\n ID: %s, content:\n ", $result->id()); + print_r($result->content()); +} +// end::rangescanalldocuments[] +// tag::rangescanalldocumentids[] +$results = $collection->scan(RangeScan::build(), ScanOptions::build()->idsOnly(true)); +foreach ($results as $result) { + printf("ID: %s \n", $result->id()); +} +// end::rangescanalldocumentids[] +// tag::rangescanprefix[] +$results = $collection->scan(PrefixScan::build("alice::")); +foreach ($results as $result) { + printf("\n ID: %s, content:\n ", $result->id()); + print_r($result->content()); +} + +// end::rangescanprefix[] + +// tag::rangescansample[] +$results = $collection->scan(SamplingScan::build(100)); +foreach ($results as $result) { + printf("\n ID: %s, content:\n ", $result->id()); + print_r($result->content()); +} +// end::rangescansample[] diff --git a/modules/devguide/examples/php/kv-expiry.php b/modules/devguide/examples/php/kv-expiry.php new file mode 100644 index 00000000..3ee0e590 --- /dev/null +++ b/modules/devguide/examples/php/kv-expiry.php @@ -0,0 +1,66 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->defaultCollection(); + +$document = [ + "foo" => "bar", + "bar" => "foo", +]; + +$key = "document-key"; + +// Upsert with Expiry +$opts = new UpsertOptions(); +$opts->expiry(60 /* seconds */); +$res = $collection->upsert($key, $document, $opts); + +// Retrieve the document immediately, must be exist +$res = $collection->get($key); +printf("[get] document content: %s\n", var_export($res->content(), true)); + +// Touch the document to adjust expiration time +// tag::touch[] +$collection->touch($key, 60 /* seconds */); +// end::touch[] + +// Touch the document to adjust expiration time +// tag::touchwithoptions[] +$opts = new TouchOptions(); +$opts->timeout(500000 /* microseconds */); +$collection->touch($key, 60 /* seconds */); +// end::touchwithoptions[] + +// Get and touch retrieves the document and adjusting expiration time +// tag::getandtouch[] +$res = $collection->getAndTouch($key, 1 /* seconds */); +printf("[getAndTouch] document content: %s\n", var_export($res->content(), true)); + +sleep(2); // wait until the document will expire + +try { + $collection->get($key); +} catch (Couchbase\Exception\DocumentNotFoundException $ex) { + printf("The document does not exist\n"); +} +// end::getandtouch[] + +// Output: +// +// [get] document content: array ( +// 'foo' => 'bar', +// 'bar' => 'foo', +// ) +// [getAndTouch] document content: array ( +// 'foo' => 'bar', +// 'bar' => 'foo', +// ) +// The document does not exist diff --git a/modules/devguide/examples/php/logging.php b/modules/devguide/examples/php/logging.php new file mode 100644 index 00000000..ed975807 --- /dev/null +++ b/modules/devguide/examples/php/logging.php @@ -0,0 +1,19 @@ +credentials("Administrator", "password"); + +$cluster = new Cluster('couchbase://localhost', $options); +$bucket = $cluster->bucket('travel-sample'); + +$collection = $bucket->scope('inventory')->collection('airline'); +$getResult = $collection->get('airline_10'); + +print_r($getResult->content()); +// end::logging[] diff --git a/modules/devguide/examples/php/managing-connections.php b/modules/devguide/examples/php/managing-connections.php new file mode 100644 index 00000000..2d124b5b --- /dev/null +++ b/modules/devguide/examples/php/managing-connections.php @@ -0,0 +1,36 @@ +credentials("Administrator", "password"); + +$connectionString = "couchbase://10.112.210.101,10.112.210.102"; +$cluster = new Cluster($connectionString, $opts); +// end::multiplenodes[] + +// tag::customPorts[] +$opts = new ClusterOptions(); +$opts->credentials("Administrator", "password"); + +$connectionString = "couchbase://192.168.42.101:12000,192.168.42.102:12002"; +$cluster = new Cluster($connectionString, $opts); +// end::customPorts[] + +// tag::tls[] +$opts = new ClusterOptions(); +$opts->credentials("Administrator", "password"); + +$connectionString = "couchbases://localhost?trust_certificate=/path/to/ca/certificates.pem"; +$cluster = new Cluster($connectionString, $opts); +// end::tls[] + +// tag::dnssrv[] +$opts = new ClusterOptions(); +$opts->credentials("Administrator", "password"); + +$connectionString = "couchbase://couchbase.example.com"; +$cluster = new Cluster($connectionString, $opts); +// end::dnssrv[] diff --git a/modules/devguide/examples/php/n1ql-concept.php b/modules/devguide/examples/php/n1ql-concept.php new file mode 100644 index 00000000..6a830cd0 --- /dev/null +++ b/modules/devguide/examples/php/n1ql-concept.php @@ -0,0 +1,89 @@ +credentials('Administrator', 'password'); + +$cluster = new Cluster($connectionString, $clusterOpts); +$bucket = $cluster->bucket('travel-sample'); +$collection = $bucket->scope('inventory')->collection('airline'); + +print("Example - [prepared-statement]\n"); +// tag::prepared-statement[] +$query = "SELECT count(*) FROM `travel-sample`.inventory.airport where country = $1"; +$opts = new QueryOptions(); +$opts->adhoc(false); +$opts->positionalParameters(['France']); + +$result = $cluster->query($query, $opts); +foreach ($result->rows() as $row) { + // do something +} +// end::prepared-statement[] + +print("Example - [create-index]\n"); +// tag::create-index[] +$mgr = $cluster->queryIndexes(); + +$mgr->createPrimaryIndex('travel-sample'); +$mgr->createIndex('travel-sample', 'ix_name', ['name']); +$mgr->createIndex('travel-sample', 'ix_email', ['email']); +// end::create-index[] + +dropIndexes($mgr); + +print("Example - [deferred-index]\n"); +// tag::deferred-index[] +$indexOpts = new CreateQueryIndexOptions(); +$primaryIndexOpts = new CreateQueryPrimaryIndexOptions(); + +$mgr->createPrimaryIndex('travel-sample', $primaryIndexOpts->deferred(true)); +$mgr->createIndex('travel-sample', 'ix_name', ['name'], $indexOpts->deferred(true)); +$mgr->createIndex('travel-sample', 'ix_email', ['email'], $indexOpts->deferred(true)); + +$indexesToBuild = $mgr->buildDeferredIndexes('travel-sample'); +$mgr->watchIndexes('travel-sample', $indexesToBuild, 2); +// end::deferred-index[] + +dropIndexes($mgr); + +print("Example - [index-consistency]\n"); +// tag::index-consistency[] +$random = rand(0, 10000000); +$userDoc = [ + 'name' => 'Brass Doorknob', + 'email' => 'brass.doorknob@juno.com', + 'random' => $random +]; + +$collection->upsert(sprintf("user:%d", $random), $userDoc); +$queryOpts = new QueryOptions(); +$cluster->query( + "SELECT name, email, random, META().id FROM `travel-sample`.inventory.airport WHERE $1 IN name", + $queryOpts->positionalParameters(['Brass']) +); +// end::index-consistency[] + +print("Example - [index-consistency-request-plus]\n"); +// tag::index-consistency-request-plus[] +$queryOpts->scanConsistency(QueryScanConsistency::REQUEST_PLUS); +$queryOpts->positionalParameters(['Brass']); +$cluster->query( + "SELECT name, email, random, META().id FROM `travel-sample`.inventory.airport WHERE $1 IN name", + $queryOpts, +); +// end::index-consistency-request-plus[] + +function dropIndexes($mgr) { + print("Dropping indexes...\n"); + $mgr->dropPrimaryIndex('travel-sample'); + $mgr->dropIndex('travel-sample', 'ix_name'); + $mgr->dropIndex('travel-sample', 'ix_email'); +} \ No newline at end of file diff --git a/modules/devguide/examples/php/orphan-logging.php b/modules/devguide/examples/php/orphan-logging.php new file mode 100644 index 00000000..813e3c8b --- /dev/null +++ b/modules/devguide/examples/php/orphan-logging.php @@ -0,0 +1,62 @@ +credentials("Administrator", "password"); + +// tag::orphanLogging[] +$connectionString = "couchbase://127.0.0.1?" . + "tracing_orphaned_queue_flush_interval=5&"; /* every 5 seconds */ + +$cluster = new Cluster($connectionString, $options); +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->scope("inventory")->collection("airport"); +// end::orphanLogging[] + +// tag::orphanTimeout[] +/* + * Create a new document + */ +$document = ["answer" => 42, "updated_at" => date("r")]; +$collection->upsert("foo", $document); + +/* + * Replace the document with a big body and very small deadline which should trigger a + * client-side timeout, in which case the server response will be reported as orphan + */ +$options = new UpsertOptions(); +$options->timeout(1); +/* + * Generate a document with 10M payload, that should be unfriendly to the compressing function + * and longer to process on the server side + */ +$document = ["noise" => base64_encode(random_bytes(15_000_000))]; +$numberOfTimeouts = 0; +while (true) { + try { + $collection->upsert("foo", $document, $options); + } catch (TimeoutException $e) { + $numberOfTimeouts++; + if ($numberOfTimeouts > 3) { + break; + } + } +} +// end::orphanTimeout[] + +/* + * Messages like one below will appear in the log for the orphaned response + * + * [cb,WARN] (tracer L:147 I:2929787644) Orphan responses observed: {"count":2,"service":"kv","top":[{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x11","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":0,"total_us":34904},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0xb","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":0,"total_us":32195}]} + */ diff --git a/modules/devguide/examples/php/provisioning-resources-buckets.php b/modules/devguide/examples/php/provisioning-resources-buckets.php new file mode 100644 index 00000000..95ee5c1f --- /dev/null +++ b/modules/devguide/examples/php/provisioning-resources-buckets.php @@ -0,0 +1,69 @@ +credentials("Administrator", "password"); + $cluster = new Cluster($connectionString, $options); + + $bucketMgr = $cluster->buckets(); + // end::creating-bucket-mgr[] + + createBucket($bucketMgr); + updateBucket($bucketMgr); + // The examples can run quite fast, wait a few seconds before flushing. + sleep(5); + flushBucket($bucketMgr); + removeBucket($bucketMgr); +} + +function createBucket($bucketMgr) +{ + // tag::create-bucket[] + $settings = new BucketSettings("hello"); + $settings->enableFlush(false); + $settings->enableReplicaIndexes(false); + $settings->setRamQuotaMb(150); + $settings->setNumReplicas(1); + $settings->setBucketType(BucketType::COUCHBASE); + $settings->conflictResolutionType(ConflictResolutionType::SEQUENCE_NUMBER); + + $bucketMgr->createBucket($settings); + // end::create-bucket[] +} + +function updateBucket($bucketMgr) +{ + // tag::update-bucket[] + $settings = $bucketMgr->getBucket("hello"); + $settings->enableFlush(true); + + $bucketMgr->updateBucket($settings); + // end::update-bucket[] +} + +function flushBucket($bucketMgr) +{ + // tag::flush-bucket[] + $bucketMgr->flush("hello"); + // end::flush-bucket[] +} + +function removeBucket($bucketMgr) +{ + // tag::remove-bucket[] + $bucketMgr->dropBucket("hello"); + // end::remove-bucket[] +} + +main(); diff --git a/modules/devguide/examples/php/provisioning-resources-users.php b/modules/devguide/examples/php/provisioning-resources-users.php new file mode 100644 index 00000000..c2c4e071 --- /dev/null +++ b/modules/devguide/examples/php/provisioning-resources-users.php @@ -0,0 +1,104 @@ +credentials("Administrator", "password"); + $adminCluster = new Cluster("couchbase://localhost", $options); + + $userMgr = $adminCluster->users(); + + createUser($userMgr); + sleep(2); // Give user creation some time to settle before getAllUsers() call. + getAllUsers($userMgr); + userOperations(); +} + +function createUser($userMgr) +{ + // tag::create-user[] + $roles = [ + // Roles required for reading data from bucket + Role::build()->setName("data_reader")->setBucket("*"), + Role::build()->setName("query_select")->setBucket("*"), + // Roles required for writing data to bucket + Role::build()->setName("data_writer")->setBucket("travel-sample"), + Role::build()->setName("query_insert")->setBucket("travel-sample"), + Role::build()->setName("query_delete")->setBucket("travel-sample"), + // Roles required for idx creation on bucket + Role::build()->setName("query_manage_index")->setBucket("travel-sample"), + ]; + + $user = new User(); + $user->setUsername("test-user"); + $user->setDisplayName("Test User"); + $user->setRoles($roles); + $user->setPassword("test-passw0rd!"); + + $userMgr->upsertUser($user); + // end::create-user[] +} + +function getAllUsers($userMgr) +{ + // tag::get-all-users[] + $userMetadata = $userMgr->getAllUsers(); + foreach ($userMetadata as &$u) { + printf("User's display name: %s\n", $u->user()->displayName()); + + $userRoles = $u->user()->roles(); + foreach ($userRoles as &$role) { + printf("\tUser has role %s, applicable to bucket %s\n", $role->name(), $role->bucket()); + } + } + // end::get-all-users[] +} + +function userOperations() +{ + # tag::user-operations[] + $options = new ClusterOptions(); + $options->credentials("test-user", "test-passw0rd!"); + $userCluster = new Cluster("couchbase://localhost", $options); + + # For Server versions 6.5 or later you do not need to open a bucket here + $userBucket = $userCluster->bucket("travel-sample"); + $collection = $userBucket->defaultCollection(); + + # create primary idx for testing purposes + $createPrimaryQueryIndexOpts = new CreateQueryPrimaryIndexOptions(); + $createPrimaryQueryIndexOpts->ignoreIfExists(true); + + $userCluster->queryIndexes()->createPrimaryIndex("travel-sample", $createPrimaryQueryIndexOpts); + + # test k/v operations + $airline10 = $collection->get("airline_10"); + printf("Airline 10: %s", $airline10->contentAs(RawJsonTranscoder::getInstance())); + + $airline11 = [ + "callsign" => "MILE-AIR", + "iata" => "Q5", "id" => 11, + "name" => "40-Mile Air", + "type" => "airline" + ]; + $collection->upsert("airline11", $airline11); + + # test query operations + $queryResult = $userCluster->query("SELECT * FROM `travel-sample` LIMIT 5;"); + foreach ($queryResult->rows() as &$row) { + print("\nQuery Row:\n"); + print_r($row); + } + # end::user-operations[] +} + +main(); diff --git a/modules/devguide/examples/php/query-index-manager.php b/modules/devguide/examples/php/query-index-manager.php new file mode 100644 index 00000000..34fde0ad --- /dev/null +++ b/modules/devguide/examples/php/query-index-manager.php @@ -0,0 +1,113 @@ +credentials("Administrator", "password"); + $cluster = new Cluster("couchbase://localhost", $options); + + $queryIndexMgr = $cluster->queryIndexes(); + // end::creating-index-mgr[] + + primaryIndex($queryIndexMgr); + secondaryIndex($queryIndexMgr); + deferAndWatchIndex($queryIndexMgr); + dropPrimaryIndex($queryIndexMgr); +} + +function primaryIndex($queryIndexMgr) +{ + print "Example - [primary]\n"; + // tag::primary[] + $options = new CreateQueryPrimaryIndexOptions(); + $options->scopeName("tenant_agent_01"); + $options->collectionName("users"); + // Set this if you wish to use a custom name + // $options->indexName("custom_name"); + $options->ignoreIfExists(true); + + $queryIndexMgr->createPrimaryIndex("travel-sample", $options); + // end::primary[] +} + +function secondaryIndex($queryIndexMgr) +{ + print "\nExample - [secondary]\n"; + try { + // tag::secondary[] + $options = new CreateQueryIndexOptions(); + $options->scopeName("tenant_agent_01"); + $options->collectionName("users"); + + $queryIndexMgr->createIndex("travel-sample", "tenant_agent_01_users_email", ["preferred_email"], $options); + // end::secondary[] + } catch (Couchbase\Exception\IndexExistsException) { + print "Index already exists\n"; + } +} + +function deferAndWatchIndex($queryIndexMgr) +{ + print "\nExample - [defer-indexes]\n"; + try { + // tag::defer-indexes[] + // Create a deferred index + $createOpts = new CreateQueryIndexOptions(); + $createOpts->scopeName("tenant_agent_01"); + $createOpts->collectionName("users"); + $createOpts->deferred(true); + + $queryIndexMgr->createIndex("travel-sample", "tenant_agent_01_users_phone", ["preferred_phone"], $createOpts); + + // Build any deferred indexes within `travel-sample`.tenant_agent_01.users + $deferredOpts = new BuildQueryIndexesOptions(); + $deferredOpts->scopeName("tenant_agent_01"); + $deferredOpts->collectionName("users"); + + $queryIndexMgr->buildDeferredIndexes("travel-sample", $deferredOpts); + + // Wait for indexes to come online + $watchOpts = new WatchQueryIndexesOptions(); + $watchOpts->scopeName("tenant_agent_01"); + $watchOpts->collectionName("users"); + + $queryIndexMgr->watchIndexes("travel-sample", ["tenant_agent_01_users_phone"], 30000, $watchOpts); + // end::defer-indexes[] + } catch (Couchbase\Exception\IndexExistsException) { + print "Index already exists\n"; + } +} + +function dropPrimaryIndex($queryIndexMgr) +{ + print "\nExample - [drop-primary-or-secondary-index]\n"; + // tag::drop-primary-or-secondary-index[] + // Drop a primary index + $options = new DropQueryPrimaryIndexOptions(); + $options->scopeName("tenant_agent_01"); + $options->collectionName("users"); + + $queryIndexMgr->dropPrimaryIndex("travel-sample", $options); + + // Drop a secondary index + $options = new DropQueryIndexOptions(); + $options->scopeName("tenant_agent_01"); + $options->collectionName("users"); + + $queryIndexMgr->dropIndex("travel-sample", "tenant_agent_01_users_email", $options); + // end::drop-primary-or-secondary-index[] +} + +main(); diff --git a/modules/devguide/examples/php/query.php b/modules/devguide/examples/php/query.php new file mode 100644 index 00000000..9ffc8c83 --- /dev/null +++ b/modules/devguide/examples/php/query.php @@ -0,0 +1,123 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $options); + +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->scope("inventory")->collection("hotel"); + +// tag::positionalParams[] +$options = new QueryOptions(); +$options->positionalParameters(["France"]); +// NOTE: string is single-quoted to avoid PHP variable substitutions and pass '$1' as is +$result = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`=$1 LIMIT 10;', $options); +// end::positionalParams[] + +// tag::namedParams[] +$options = new QueryOptions(); +$options->namedParameters(['country' => "France"]); +$result = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`=$country LIMIT 10;', $options); +// end::namedParams[] + +// tag::results[] +$options = new QueryOptions(); +$options->positionalParameters(["France"]); +$result = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`=$1 LIMIT 10;', $options); + +foreach ($result->rows() as $row) { + printf("Name: %s, Address: %s, Description: %s\n", $row["name"], $row["address"], $row["description"]); +} +// end::results[] + +// tag::scan[] +$query = 'SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`="France" LIMIT 10'; +$opts = new QueryOptions(); +$opts->scanConsistency(QueryScanConsistency::REQUEST_PLUS); +$res = $cluster->query($query, $opts); +// end::scan[] +$idx = 1; +foreach ($res->rows() as $row) { + printf("%d. %s, \"%s\"\n", $idx++, $row['country'], $row['name']); +} +// tag::metrics[] +printf("Execution Time: %d\n", $res->metaData()->metrics()['executionTime']); +// end::metrics[] + +// NOTE: This currently fails with Couchbase Internal Server error. +// Server issue tracked here: https://issues.couchbase.com/browse/MB-46876 +// Add back in once Couchbase Server 7.0.1 is available, which will fix this issue. +// tag::consistentWith[] +// create/update document (mutation) +//$res = $collection->upsert("id", ["name" => "somehotel", "type" => "hotel"]); +// +//// create mutation state from mutation results +//$state = new MutationState(); +//$state->add($res); +// +//// use mutation state with query optionss +//$opts = new QueryOptions(); +//$opts->consistentWith($state); +//$res = $cluster->query('SELECT x.* FROM `travel-sample`.inventory.hotel x WHERE x.`country`="United States" AND x.city LIKE "%pool%" LIMIT 10', $opts); +//// end::consistentWith[] +//$idx = 1; +//foreach ($res->rows() as $row) { +// printf("%d. %s\n", $idx++, $row['name']); +//} +// +//printf("Execution Time: %d\n", $res->metaData()->metrics()['executionTime']); + +// tag::scope-level-query[] +$opts = new QueryOptions(); +$opts->namedParameters(['country' => "France"]); + +$scope = $bucket->scope("inventory"); +$result = $scope->query('SELECT x.* FROM `airline` x WHERE x.`country`=$country LIMIT 10;', $opts); + +foreach ($result->rows() as $row) { + printf("Name: %s, Callsign: %s, Country: %s\n", $row["name"], $row["callsign"], $row["country"]); +} +// end::scope-level-query[] + +// tag::VectorSearchWithQueryHyperscaleIndex[] +$res = $cluster->query( + "SELECT d.id, d.question, d.wanted_similar_color_from_search, + ARRAY_CONCAT( + d.couchbase_search_query.knn[0].vector[0:4], + ['...'] + ) AS vector + FROM `vector-sample`.`color`.`rgb-questions` AS d + WHERE d.id = '#87CEEB';", + QueryOptions::build()->metrics(true) +); +foreach ($res->rows() as $row) { + print("\nFound match:\n"); + print_r($row); +} +// end::VectorSearchWithQueryHyperscaleIndex[] + +// tag::VectorSearchWithQueryParameterized[] +$result = $cluster->query( + "SELECT d.id, d.question, d.wanted_similar_color_from_search, + ARRAY_CONCAT( + d.couchbase_search_query.knn[0].vector[0:4], + ['...'] + ) AS vector + FROM `vector-sample`.`color`.`rgb-questions` AS d + WHERE d.id = \$id;", + QueryOptions::build()->namedParameters(["id" => "#87CEEB"]) +); +foreach ($res->rows() as $row) { + print("\nFound match:\n"); + print_r($row); +} + + + +// end::VectorSearchWithQueryParameterized[] diff --git a/modules/devguide/examples/php/search-facets.php b/modules/devguide/examples/php/search-facets.php new file mode 100644 index 00000000..d74f1bbc --- /dev/null +++ b/modules/devguide/examples/php/search-facets.php @@ -0,0 +1,205 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://192.168.1.101", $opts); + +// tag::iteratingfacets[] +$query = (new TermSearchQuery("beer"))->field("type"); +$options = new SearchOptions(); +$options->facets([ + "foo" => new TermSearchFacet("name", 3), + "bar" => (new DateRangeSearchFacet("updated", 1)) + ->addRange("old", NULL, mktime(0, 0, 0, 1, 1, 2014)), // "2014-01-01T00:00:00" also acceptable + "baz" => (new NumericRangeSearchFacet("abv", 2)) + ->addRange("strong", 4.9, NULL) + ->addRange("light", NULL, 4.89) +]); +$res = $cluster->searchQuery("beer-search", $query, $options); + +$facet = $res->facets()["foo"]; +printf("Term facet \"foo\" on field \"%s\". Total: %d, missing: %d: other: %d\n", + $facet["field"], $facet["total"], $facet["missing"], $facet["other"]); +foreach ($facet["terms"] as $term) { + printf(" * %-5s ... %d\n", $term["term"], $term["count"]); +} + +$facet = $res->facets()["bar"]; +printf("Date range facet \"bar\" on field \"%s\". Total: %d, missing: %d: other: %d\n", + $facet["field"], $facet["total"], $facet["missing"], $facet["other"]); +foreach ($facet["date_ranges"] as $range) { + printf(" * %-20s ... %d\n", $range["end"], $range["count"]); +} + +$facet = $res->facets()["baz"]; +printf("Numeric range facet \"baz\" on field \"%s\". Total: %d, missing: %d: other: %d\n", + $facet["field"], $facet["total"], $facet["missing"], $facet["other"]); +foreach ($facet["numeric_ranges"] as $range) { + if (isset($range["max"])) { + printf(" * max %-4s ... %d\n", $range["max"], $range["count"]); + } else { + printf(" * min %-4s ... %d\n", $range["min"], $range["count"]); + } +} +// end::iteratingfacets[] + +// Output +// +// Term facet "foo" on field "name". Total: 15260, missing: 0: other: 13000 +// * ale ... 1421 +// * stout ... 432 +// * pale ... 407 +// Date range facet "bar" on field "updated". Total: 5891, missing: 0: other: 0 +// * 2014-01-01T00:00:00Z ... 5891 +// Numeric range facet "baz" on field "abv". Total: 5891, missing: 0: other: 0 +// * max 4.89 ... 3386 +// * min 4.9 ... 2505 + + +/* + * index definition +{ + "type": "fulltext-index", + "name": "beer-search", + "uuid": "5f58f6e660a5ebea", + "sourceType": "couchbase", + "sourceName": "beer-sample", + "sourceUUID": "37838ef14de076784cc5b49b17682e0d", + "planParams": { + "maxPartitionsPerPIndex": 171, + "indexPartitions": 6 + }, + "params": { + "doc_config": { + "docid_prefix_delim": "", + "docid_regexp": "", + "mode": "type_field", + "type_field": "type" + }, + "mapping": { + "analysis": {}, + "default_analyzer": "standard", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "default_mapping": { + "dynamic": true, + "enabled": true + }, + "default_type": "_default", + "docvalues_dynamic": true, + "index_dynamic": true, + "store_dynamic": false, + "type_field": "_type", + "types": { + "beer": { + "dynamic": true, + "enabled": true, + "properties": { + "abv": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "abv", + "store": true, + "type": "number" + } + ] + }, + "category": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "category", + "store": true, + "type": "text" + } + ] + }, + "description": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "description", + "store": true, + "type": "text" + } + ] + }, + "name": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "name", + "store": true, + "type": "text" + } + ] + }, + "style": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "style", + "store": true, + "type": "text" + } + ] + }, + "updated": { + "dynamic": false, + "enabled": true, + "fields": [ + { + "docvalues": true, + "include_in_all": true, + "include_term_vectors": true, + "index": true, + "name": "updated", + "store": true, + "type": "datetime" + } + ] + } + } + } + } + }, + "store": { + "indexType": "scorch" + } + }, + "sourceParams": {} +} + */ diff --git a/modules/devguide/examples/php/search.php b/modules/devguide/examples/php/search.php new file mode 100644 index 00000000..2c2e6e6c --- /dev/null +++ b/modules/devguide/examples/php/search.php @@ -0,0 +1,193 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +// #tag::matchquery[] +$matchQuery = new MatchSearchQuery("swanky"); +$matchQuery->field("reviews.content"); +$opts = new SearchOptions(); +$opts->limit(10); +$res = $cluster->searchQuery("travel-sample-index", $matchQuery, $opts); +printf("Match query: \"swanky\":\n"); +foreach ($res->rows() as $row) { + printf("id: %s, score: %f\n", $row['id'], $row['score']); +} +// #end::matchquery[] + +// #tag::numrangequery[] +$numericRangeQuery = new NumericRangeSearchQuery(); +$numericRangeQuery->field("reviews.ratings.Cleanliness")->min(5); +$opts = new SearchOptions(); +$opts->limit(10); +$res = $cluster->searchQuery("travel-sample-index", $numericRangeQuery, $opts); +printf("Cleanliness 5+:\n"); +foreach ($res->rows() as $row) { + printf("id: %s, score: %f\n", $row['id'], $row['score']); +} +// #end::numrangequery[] + +// #tag::conjunctionquery[] +$conjunction = new ConjunctionSearchQuery([$matchQuery, $numericRangeQuery]); +$opts = new SearchOptions(); +$opts->limit(10); +$res = $cluster->searchQuery("travel-sample-index", $conjunction, $opts); +printf("Swanky and with cleanliness 5+:\n"); +foreach ($res->rows() as $row) { + printf("id: %s, score: %f\n", $row['id'], $row['score']); +} +// #end::conjunctionquery[] + + +// #tag::consistency[] +// Create new hotel document and demonstrate query with consistency requirement +$scope = $cluster->bucket('travel-sample')->scope('inventory'); +$collection = $scope->collection('hotel'); +$hotel = [ + "name" => "super hotel", + "reviews" => [ + [ + "content" => "Super swanky hotel!", + "ratings" => [ + "Cleanliness" => 6 + ] + ] + ] +]; +$res = $collection->upsert("a-new-hotel", $hotel); +$mutationState = new MutationState(); +$mutationState->add($res); +$opts = new SearchOptions(); +$opts->limit(10); +$opts->consistentWith("travel-sample-index", $mutationState); +$res = $cluster->searchQuery("travel-sample-index", $matchQuery, $opts); +printf("Match query: \"swanky\":\n"); +foreach ($res->rows() as $row) { + printf("id: %s, score: %f\n", $row['id'], $row['score']); +} +// #end::consistency[] + +// this should come from an external source, such as an embeddings API +$vectorQuery = []; +$anotherVectorQuery = []; + +// #tag::singlevectorquery[] +$request = SearchRequest::build(VectorSearch::build([ + VectorQuery::build("vector_field", $vectorQuery) +])); + +$result = $scope->search("vector-index", $request); +// #end::singlevectorquery[] + +// #tag::multiplevectorqueries[] +$request = SearchRequest::build(VectorSearch::build([ + VectorQuery::build("vector_field", $vectorQuery)->numCandidates(2)->boost(0.3), + VectorQuery::build("vector_field", $anotherVectorQuery)->numCandidates(5)->boost(0.7) +])); + +$result = $scope->search("vector-index", $request); +// #end::multiplevectorqueries[] + +// #tag::combinedvectorquery[] +$request = SearchRequest::build(MatchAllSearchQuery::build()); +$request->vectorSearch(VectorSearch::build([ + VectorQuery::build("vector_field", $vectorQuery) +])); + +$result = $scope->search("vector-and-fts-index", $request); +// #end::combinedvectorquery[] + +// #tag::traditionalftsquery[] +$request = SearchRequest::build(MatchAllSearchQuery::build()); + +$result = $scope->search("travel-sample-index", $request); +// #end::traditionalftsquery[] + +// Output +// +// Match query: "swanky": +// id: hotel_25794, score: 0.541554 +// id: hotel_25800, score: 0.511521 +// id: hotel_25598, score: 0.510087 +// id: hotel_16350, score: 0.480130 +// id: hotel_25301, score: 0.418002 +// Cleanliness 5+: +// id: hotel_5335, score: 1.220367 +// id: hotel_21673, score: 1.220367 +// id: hotel_26139, score: 1.220367 +// id: hotel_635, score: 1.220367 +// id: hotel_21665, score: 1.220367 +// id: hotel_21679, score: 1.220367 +// id: hotel_15978, score: 1.220367 +// id: hotel_35667, score: 1.220367 +// id: hotel_4397, score: 1.220367 +// id: hotel_2241, score: 1.220367 +// Swanky and with cleanliness 5+: +// id: hotel_16350, score: 1.005243 +// id: hotel_25800, score: 0.900247 +// id: hotel_25301, score: 0.792935 +// id: hotel_25794, score: 0.534181 +// Match query: "swanky": +// id: a-new-hotel, score: 4.884002 +// id: hotel_25794, score: 0.541554 +// id: hotel_25800, score: 0.511521 +// id: hotel_25598, score: 0.510087 +// id: hotel_16350, score: 0.480130 +// id: hotel_25301, score: 0.418002 + diff --git a/modules/devguide/examples/php/start-using.php b/modules/devguide/examples/php/start-using.php new file mode 100644 index 00000000..93854327 --- /dev/null +++ b/modules/devguide/examples/php/start-using.php @@ -0,0 +1,47 @@ +credentials("Administrator", "password"); +$cluster = new Cluster($connectionString, $options); +// end::connect[] + +// tag::bucket[] +// get a bucket reference +$bucket = $cluster->bucket("travel-sample"); +// end::bucket[] + +// tag::collection[] +// get a user-defined collection reference +$scope = $bucket->scope("tenant_agent_00"); +$collection = $scope->collection("users"); +// end::collection[] + +// tag::upsert-get[] +$upsertResult = $collection->upsert("my-document-key", ["name" => "Ted", "Age" => 31]); + +$getResult = $collection->get("my-document-key"); + +print_r($getResult->content()); +// end::upsert-get[] + +// tag::n1ql-query[] +$inventoryScope = $bucket->scope("inventory"); +$queryResult = $inventoryScope->query("SELECT * FROM airline WHERE id = 10"); + +// Print result data to the terminal. +foreach ($queryResult->rows() as $row) { + print_r($row); +} +// end::n1ql-query[] diff --git a/modules/devguide/examples/php/subdoc-concurrent.php b/modules/devguide/examples/php/subdoc-concurrent.php new file mode 100644 index 00000000..4db21552 --- /dev/null +++ b/modules/devguide/examples/php/subdoc-concurrent.php @@ -0,0 +1,46 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); +$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + +printf("Creating customer123 document\n"); +$customer123 = json_decode(file_get_contents("customer123.json")); +$collection->upsert("customer123", $customer123); +printf("Created customer123 document\n"); + +// #tag::mutateInConcurrent[] +$operations = [new \Couchbase\MutateArrayAppendSpec("purchases.complete", [999]), new \Couchbase\MutateArrayAppendSpec("purchases.complete", [998])]; +$pids = []; + +for ($i = 0; $i < count($operations); $i++) { + $pid = pcntl_fork(); + if ($pid == -1) { + die("unable to spawn child process"); + } else if ($pid == 0) { + // Child process + concurrent_mutatein($operations[$i]); + exit(0); + } else { + array_push($pids, $pid); + } +} + +foreach ($pids as $child) { + pcntl_waitpid($child, $status); +} + +function concurrent_mutatein($op) { + $opts = new ClusterOptions(); + $opts->credentials("Administrator", "password"); + $cluster = new Cluster("couchbase://localhost", $opts); + $collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + + $result = $collection->mutateIn("customer123", [ + $op + ]); +} +// #end::mutateInConcurrent[] diff --git a/modules/devguide/examples/php/subdoc-counters.php b/modules/devguide/examples/php/subdoc-counters.php new file mode 100644 index 00000000..e9451600 --- /dev/null +++ b/modules/devguide/examples/php/subdoc-counters.php @@ -0,0 +1,32 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + +printf("Creating customer123 document\n"); +$customer123 = json_decode(file_get_contents("customer123.json")); +$collection->upsert("customer123", $customer123); +printf("Created customer123 document\n"); + +// #tag::mutateInIncrement[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateCounterSpec("logins", 1) +]); + +printf("%d\n", $result->content(0)); // 1 +// #end::mutateInIncrement[] + +// #tag::mutateInDecrement[] +$result = $collection->upsert("player432", ["gold" => 1000]); + +$result = $collection->mutateIn("player432", [ + new \Couchbase\MutateCounterSpec("gold", -150) +]); +printf("player 432 now has %d gold remaining\n", $result->content(0)); +// => player 432 now has 850 gold remaining +// #end::mutateInDecrement[] \ No newline at end of file diff --git a/modules/devguide/examples/php/subdoc-lookupin.php b/modules/devguide/examples/php/subdoc-lookupin.php new file mode 100644 index 00000000..642982e1 --- /dev/null +++ b/modules/devguide/examples/php/subdoc-lookupin.php @@ -0,0 +1,62 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + +printf("Creating customer123 document\n"); +$customer123 = json_decode(file_get_contents("customer123.json")); +$collection->upsert("customer123", $customer123); +printf("Created customer123 document\n"); + +// #tag::lookupInGet[] +$result = $collection->lookupIn("customer123", [ + new \Couchbase\LookupGetSpec("addresses.delivery.country") +]); +$country = $result->content(0); +printf("%s\n", $country); +// "United Kingdom" +// #end::lookupInGet[] + +// #tag::lookupInExists[] +$result = $collection->lookupIn("customer123", [ + new \Couchbase\LookupExistsSpec("purchases.pending[-1]") +]); +printf("Path exists? %s\n", $result->exists(0) ? "true" : "false"); +// Path exists? false +// #end::lookupInExists[] + +// #tag::lookupInMulti[] +$result = $collection->lookupIn("customer123", [ + new \Couchbase\LookupGetSpec("addresses.delivery.country"), + new \Couchbase\LookupExistsSpec("purchases.pending[-1]") +]); +printf("%s\n", $result->content(0)); +printf("Path exists? %s\n", $result->exists(1) ? "true" : "false"); +// United Kingdom +// Path exists? false +// #end::lookupInMulti[] +// #tag::lookupinanyreplica[] +$result = $collection->lookupInAnyReplica("customer123", [ + new \Couchbase\LookupGetSpec("addresses.delivery.country") +]); +printf("%s\n", $result->content(0)); +// United Kingdom +printf("Is replica? %s", $result->isReplica() ? "true" : "false"); +// Is replica?: false|true +// #end::lookupinanyreplica[] +// #tag::lookupinallreplicas[] +$results = $collection->lookupInAllReplicas("customer123", [ + new \Couchbase\LookupGetSpec("addresses.delivery.country") +]); +foreach ($results as $result) { + printf("%s\n", $result->content(0)); + // United Kingdom + printf("Is replica? %s\n", $result->isReplica() ? "true" : "false"); + // Is replica? false|true +} +// #end::lookupinallreplicas[] diff --git a/modules/devguide/examples/php/subdoc-mutatein-arrays.php b/modules/devguide/examples/php/subdoc-mutatein-arrays.php new file mode 100644 index 00000000..a2beeada --- /dev/null +++ b/modules/devguide/examples/php/subdoc-mutatein-arrays.php @@ -0,0 +1,84 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + +printf("Creating customer123 document\n"); +$customer123 = json_decode(file_get_contents("customer123.json")); +$collection->upsert("customer123", $customer123); +printf("Created customer123 document\n"); + + +// #tag::mutateInArrayAppend[] +$result = $collection->MutateIn("customer123", [ + new \Couchbase\MutateArrayAppendSpec("purchases.complete", [777]) +]); +// purchases.complete is now [339, 976, 442, 666, 777] +// #end::mutateInArrayAppend[] + +// #tag::mutateInArrayPrepend[] +$result = $collection->MutateIn("customer123", [ + new \Couchbase\MutateArrayPrependSpec("purchases.abandoned", [18]) +]); +// purchases.abandoned is now [18, 157, 49, 999] +// #end::mutateInArrayPrepend[] + +// #tag::mutateInArrayDoc[] +$result = $collection->upsert("my_array", []); +$result = $collection->mutateIn("my_array", [ + new \Couchbase\MutateArrayAppendSpec("", ["some element"]) +]); +// the document my_array is now ["some element"] +// #end::mutateInArrayDoc[] + +// #tag::mutateInArrayDocMulti[] +$result = $collection->mutateIn("my_array", [ + new \Couchbase\MutateArrayAppendSpec("", ["elem1", "elem2", "elem3"]) +]); +// the document my_array is now ["some_element", "elem1", "elem2", "elem3"] +// #end::mutateInArrayDocMulti[] + +// #tag::mutateInArrayDocMultiSingle[] +$result = $collection->mutateIn("my_array", [ + new \Couchbase\MutateArrayAppendSpec("", [["elem1", "elem2", "elem3"]]) +]); +// the document my_array is now ["some_element", ["elem1", "elem2", "elem3"]] +// #end::mutateInArrayDocMultiSingle[] + +// #tag::mutateInArrayAppendMulti[] +$result = $collection->mutateIn("my_array", [ + new \Couchbase\MutateArrayAppendSpec("", ["elem1"]), + new \Couchbase\MutateArrayAppendSpec("", ["elem2"]), + new \Couchbase\MutateArrayAppendSpec("", ["elem3"]), +]); +// #end::mutateInArrayAppendMulti[] + +// #tag::mutateInArrayAppendCreatePath[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateArrayAppendSpec("some.array", ["Hello", "World"], false, true) + ]); +// #end::mutateInArrayAppendCreatePath[] + +// #tag::mutateInArrayAddUnique[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateArrayAddUniqueSpec("purchases.complete", 95) +]); +// => Success + +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateArrayAddUniqueSpec("purchases.complete", 95) +]); +// => SubdocPathExists exception! +// #end::mutateInArrayAddUnique[] + +// #tag::mutateInArrayInsert[] +$result = $collection->upsert("array", ["Hello", "world"]); +$result = $collection->mutateIn("array", [ + new \Couchbase\MutateArrayInsertSpec("[1]", ["cruel"]) +]); +// #end::mutateInArrayInsert[] \ No newline at end of file diff --git a/modules/devguide/examples/php/subdoc-mutatein-durability.php b/modules/devguide/examples/php/subdoc-mutatein-durability.php new file mode 100644 index 00000000..e101a8ed --- /dev/null +++ b/modules/devguide/examples/php/subdoc-mutatein-durability.php @@ -0,0 +1,22 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + +printf("Creating customer123 document\n"); +$customer123 = json_decode(file_get_contents("customer123.json")); +$collection->upsert("customer123", $customer123); +printf("Created customer123 document\n"); + +// #tag::mutateInDurableWrites[] +$options = new \Couchbase\MutateInOptions(); +$options->durabilityLevel(\Couchbase\DurabilityLevel::MAJORITY); +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateUpsertSpec("name", "dave") +], $options); +// #end::mutateInDurableWrites[] diff --git a/modules/devguide/examples/php/subdoc-mutatein.php b/modules/devguide/examples/php/subdoc-mutatein.php new file mode 100644 index 00000000..768c70de --- /dev/null +++ b/modules/devguide/examples/php/subdoc-mutatein.php @@ -0,0 +1,52 @@ +credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$collection = $cluster->bucket("travel-sample")->scope("tenant_agent_00")->collection("users"); + +printf("Creating customer123 document\n"); +$customer123 = json_decode(file_get_contents("customer123.json")); +$collection->upsert("customer123", $customer123); +printf("Created customer123 document\n"); + +// #tag::mutateInUpsert[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateUpsertSpec("fax", "311-555-0151") +]); +// #end::mutateInUpsert[] + +// #tag::mutateInInsert[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateInsertSpec("purchases.complete", [42, true, "None"]) +]); +// SubdocPathExistsError +// #end::mutateInInsert[] + +// #tag::mutateInMulti[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateRemoveSpec("addresses.billing"), + new \Couchbase\MutateReplaceSpec("email", "dougr96@hotmail.com") +]); +// #end::mutateInMulti[] + +// #tag::mutateInCreatePath[] +$result = $collection->mutateIn("customer123", [ + new \Couchbase\MutateUpsertSpec("level_0.level_1.foo.bar.phone", + ["num" => "311-555-0101", "ext" => 16], + false, true) +]); +// #end::mutateInCreatePath[] + +// #tag::mutateInCas[] +$doc = $collection->get("customer123"); +$options = new \Couchbase\MutateInOptions(); +$options->cas($doc->cas()); + +$res = $collection->mutatein("customer123", [ + new \Couchbase\MutateArrayAppendSpec("purchases.complete", [1000]) +], $options); +// #end::mutateInCas[] \ No newline at end of file diff --git a/modules/devguide/examples/php/threshold-logging.php b/modules/devguide/examples/php/threshold-logging.php new file mode 100644 index 00000000..20320756 --- /dev/null +++ b/modules/devguide/examples/php/threshold-logging.php @@ -0,0 +1,65 @@ +credentials("Administrator", "password"); + +// tag::thresholdLogging[] +$connectionString = "couchbase://127.0.0.1?" . + "tracing_threshold_queue_flush_interval=3&" . /* every 3 seconds */ + "tracing_threshold_kv=0.01"; /* 10 milliseconds */ + +$cluster = new Cluster($connectionString, $options); +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->scope("inventory")->collection("airport"); +// end::thresholdLogging[] + +// tag::thresholdLongProcessing[] +/* + * Create a new document + */ +$document = ["answer" => 42, "updated_at" => date("r")]; +$collection->upsert("foo", $document); + +/* + * Replace the document with a big body and very small deadline which should trigger a + * client-side timeout, in which case the server response will be reported as orphan + */ +$options = new UpsertOptions(); +$options->timeout(1); +/* + * Generate a document with 10M payload, that should be unfriendly to the compressing function + * and longer to process on the server side + */ +$document = ["noise" => base64_encode(random_bytes(15_000_000))]; +$numberOfTimeouts = 0; +while (true) { + try { + $collection->upsert("foo", $document, $options); + } catch (TimeoutException $e) { + $numberOfTimeouts++; + if ($numberOfTimeouts > 3) { + break; + } + } +} +// end::thresholdLongProcessing[] + +/* + * Threshold reports will be written like the following + * + * [cb,INFO] (tracer L:149 I:2929787644) Operations over threshold: {"count":14,"service":"kv","top":[{"operation_name":"php/upsert","total_us":537133},{"operation_name":"php/upsert","total_us":513483},{"operation_name":"php/upsert","total_us":510245},{"operation_name":"php/upsert","total_us":500094},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x3","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":150315,"total_us":320528},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x2","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":126118,"total_us":317381},{"last_local_address":"127.0.0.1:41210","last_local_id":"aa562ed8aea102fc/a4a9305660272565","last_operation_id":"0x4","last_remote_address":"127.0.0.1:11210","operation_name":"upsert","server_us":149572,"total_us":311246},{"operation_name":"php/request_encoding","total_us":200289}]} + */ diff --git a/modules/devguide/examples/php/transactions-example.php b/modules/devguide/examples/php/transactions-example.php new file mode 100644 index 00000000..e53a5704 --- /dev/null +++ b/modules/devguide/examples/php/transactions-example.php @@ -0,0 +1,535 @@ +credentials($CB_USER, $CB_PASS); + +$transactions_configuration = new TransactionsConfiguration(); +$transactions_configuration->durabilityLevel(Couchbase\DurabilityLevel::PERSIST_TO_MAJORITY); +$options->transactionsConfiguration($transactions_configuration); + +$cluster = new Cluster($CB_HOST, $options); +// end::config[] + +// tag::bucket[] +// get a reference to our bucket +$bucket = $cluster->bucket('travel-sample'); +// end::bucket[] + +// tag::collection[] +// get a reference to a collection +$collection = $bucket->scope('inventory')->collection('airline'); +// end::collection[] + +// tag::default-collection[] +// get a reference to the default collection, required for older Couchbase server versions +$collection_default = $bucket->defaultCollection(); +// end::default-collection[] + +function removeOrWarn($collection, $doc) +{ + try { + $collection->remove($doc); + } catch (\Couchbase\Exception\DocumentNotFoundException $e) { + echo "Document does not exist.\n"; + } +} + +$testDoc = 'foo'; +removeOrWarn($collection, $testDoc); +removeOrWarn($collection, 'doc-c'); +removeOrWarn($collection, 'docId'); +removeOrWarn($collection, 'doc-greeting'); +$collection->upsert('doc-a', []); +$collection->upsert('doc-b', []); +$collection->upsert('customer-name', ['balance' => 9]); + +try { + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection, $testDoc) { + $ctx->insert($collection, $testDoc, "hello"); + } + ); +} catch (\Couchbase\Exception\TransactionFailedException $e) { + echo "Transaction did not reach commit point: $e\n"; +} catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { + echo "Transaction possibly committed: $e\n"; +} + +echo "Running: create example\n"; +// tag::create[] +try { + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) { + // `$ctx` is a TransactionAttemptContext which permits getting, inserting, + // removing and replacing documents, performing SQL++ (N1QL) queries, etc. + // … Your transaction logic here … + // Committing is implicit at the end of the lambda. + } + ); +} catch (\Couchbase\Exception\TransactionFailedException $e) { + echo "Transaction did not reach commit point: $e\n"; +} catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { + echo "Transaction possibly committed: $e\n"; +} +// end::create[] + +echo "Running: create-simple example\n"; +// tag::create-simple[] +$cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + $ctx->insert($collection, 'doc1', ['hello' => 'world']); + + $doc = $ctx->get($collection, 'doc1'); + $ctx->replace($doc, ['foo' => 'bar']); + } +); +// end::create-simple[] + +echo "\nRunning: examples\n"; +// tag::examples[] +try { + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + // Inserting a doc: + $ctx->insert($collection, 'doc-c', []); + + // Getting documents: + $docA = $ctx->get($collection, 'doc-a'); + + // Replacing a doc: + $docB = $ctx->get($collection, 'doc-b'); + $content = $docB->content(); + $newContent = array_merge( + ["transactions" => "are awesome"], + $content + ); + $ctx->replace($docB, $newContent); + + // Removing a doc: + $docC = $ctx->get($collection, 'doc-c'); + $ctx->remove($docC); + + // Performing a SELECT SQL++ (N1QL) query: + $selectQuery = 'SELECT * FROM `travel-sample`.inventory.hotel WHERE country = $1 LIMIT 5'; + $qr = $ctx->query( + $selectQuery, + TransactionQueryOptions::build() + ->positionalParameters(["United Kingdom"]) + ); + foreach ($qr->rows() as $row) { + printf("Name: %s, Country: %s\n", $row["hotel"]["name"], $row["hotel"]["country"]); + } + + // Performing an UPDATE SQL++ (N1QL) query: + $updateQuery = 'UPDATE `travel-sample`.inventory.route SET airlineid = $1 WHERE airline = $2 LIMIT 5'; + $ctx->query( + $updateQuery, + TransactionQueryOptions::build() + ->positionalParameters(['airline_137', 'AF']) + ); + } + ); +} catch (\Couchbase\Exception\TransactionFailedException $e) { + echo "Transaction did not reach commit point: $e\n"; +} catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { + echo "Transaction possibly committed: $e\n"; +} +// end::examples[] + +// execute other examples +getExample($cluster, $collection); +getReadOwnWritesExample($cluster, $collection); +replaceExample($cluster, $collection); +removeExample($cluster, $collection); +insertExample($cluster, $collection); +queryExamples($cluster); +queryRYOW($cluster); +queryKvMix($cluster, $collection); +queryOptions($cluster); +// TODO: Uncomment when we have clarity on what the example should do. +// querySingle($cluster); + +// Rollback +playerHitsMonster(42, "arthur", "vogon", $cluster, $collection); +// rollbackExample($cluster, $collection); +rollbackCause($cluster, $collection); + +function getExample($cluster, $collection) +{ + echo "\nRunning: get example\n"; + // tag::get[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + $docA = $ctx->get($collection, "doc-a"); + } + ); + // end::get[] + // TODO: should this show nullable/optional in an example? +} + +function getReadOwnWritesExample($cluster, $collection) +{ + echo "\nRunning: getReadOwnWrites example\n"; + // tag::getReadOwnWrites[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + $docId = 'docId'; + $ctx->insert($collection, $docId, []); + + $doc = $ctx->get($collection, $docId); + } + ); + // end::getReadOwnWrites[] +} + +function replaceExample($cluster, $collection) +{ + echo "\nRunning: replace example\n"; + // tag::replace[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + $doc = $ctx->get($collection, "doc-b"); + $content = $doc->content(); + $newContent = array_merge( + ["transactions" => "are awesome"], + $content + ); + + $ctx->replace($doc, $newContent); + } + ); + // end::replace[] +} + +function removeExample($cluster, $collection) +{ + echo "\nRunning: remove example\n"; + // tag::remove[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + $doc = $ctx->get($collection, "docId"); + $ctx->remove($doc); + } + ); + // end::remove[] +} + +function insertExample($cluster, $collection) +{ + echo "\nRunning: insert example\n"; + // tag::insert[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + $adoc = $ctx->insert($collection, "docId", []); + } + ); + // end::insert[] +} + +function calculateLevelForExperience(int $experience): int +{ + return (int)floor($experience / 100); +} + +function queryExamples($cluster) +{ + echo "\nRunning: queryExamplesSelect\n"; + // TODO: scopeQualifier/scopeName options are both deprecated. + // https://github.com/couchbase/couchbase-php-client/blob/4.0.0/Couchbase/TransactionQueryOptions.php#L296-L325 + // It's unclear what we should use to demonstrate scope level queries. + // Using full qualifier for now. + // tag::queryExamplesSelect[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) { + $st = "SELECT * FROM `travel-sample`.inventory.hotel WHERE country = $1"; + $qr = $ctx->query( + $st, + TransactionQueryOptions::build() + ->positionalParameters(["United Kingdom"]) + ); + + foreach ($qr->rows() as $row) { + // do something + } + } + ); + // end::queryExamplesSelect[] + + // TODO: scopeQualifier/scopeName options are both deprecated. + // https://github.com/couchbase/couchbase-php-client/blob/4.0.0/Couchbase/TransactionQueryOptions.php#L296-L325 + // It's unclear what we should use to demonstrate scope level queries. + // Using full qualifier for now. + // $st = UPDATE hotel SET price = $1 WHERE url LIKE $2 AND country = $3"; + // tag::queryExamplesUpdate[] + $hotelChain = 'http://marriot%'; + $country = 'United States'; + + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($hotelChain, $country) { + $st = "UPDATE `travel-sample`.inventory.hotel SET price = $1 WHERE url LIKE $2 AND country = $3"; + $qr = $ctx->query( + $st, + TransactionQueryOptions::build() + ->positionalParameters([99.99, $hotelChain, $country]) + ); + + print_r($qr->metaData()->metrics()); + if ($qr->metaData()->metrics()["mutationCount"] != 2) { + // throw new \Exception("Mutation count not the expected amount."); + echo "WARN: Mutation count not the expected amount.\n"; + } + } + ); + // end::queryExamplesUpdate[] + + // tag::queryExamplesComplex[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($hotelChain, $country) { + // Find all hotels of the chain + $qr = $ctx->query( + 'SELECT reviews FROM `travel-sample`.inventory.hotel WHERE url LIKE $1 AND country = $2', + TransactionQueryOptions::build() + ->positionalParameters([$hotelChain, $country]) + ); + + // This function (not provided here) will use a trained machine learning model to provide a + // suitable price based on recent customer reviews. + $priceFromRecentReviews = function (\Couchbase\QueryResult $qr): float { + // this would call a trained ML model to get the best price + return 99.98; + }; + $updatedPrice = $priceFromRecentReviews($qr); + + // Set the price of all hotels in the chain + $ctx->query( + 'UPDATE `travel-sample`.inventory.hotel SET price = $1 WHERE url LIKE $2 AND country = $3', + TransactionQueryOptions::build() + ->positionalParameters([$updatedPrice, $hotelChain, $country]) + ); + } + ); + // end::queryExamplesComplex[] +} + +function queryRYOW($cluster) +{ + echo "\nRunning: queryInsert example\n"; + // tag::queryRYOW[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) { + // Query INSERT + $ctx->query( + "INSERT INTO `travel-sample`.inventory.airline VALUES ('doc-c', {'hello':'world'})" // <1> + ); + + // Query SELECT + $ctx->query( + "SELECT hello FROM `travel-sample`.inventory.airline WHERE META().id = 'doc-c'" // <2> + ); + } + ); + // end::queryRYOW[] +} + +function queryKvMix($cluster, $collection) +{ + echo "\nRunning: queryKvMix example\n"; + // tag::queryKvMix[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection) { + // Key-Value insert + $ctx->insert($collection, "doc-greeting", ["greeting" => "Hello World"]); // <1> + + // Query SELECT + $selectQuery = "SELECT greeting FROM `travel-sample`.inventory.airline WHERE META().id = 'doc-greeting'"; + $ctx->query($selectQuery); // <2> + } + ); + // end::queryKvMix[] +} + +function queryOptions($cluster) +{ + echo "\nRunning: queryOptions example\n"; + // tag::queryOptions[] + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) { + $txQo = TransactionQueryOptions::build() + ->readonly(false) + ->positionalParameters(["key", "value"]); + + $ctx->query( + "UPSERT INTO `travel-sample`.inventory.airline VALUES ('docId', {\$1:\$2})", + $txQo + ); + } + ); + // end::queryOptions[] +} + +// TODO: Verify this is the correct example for a single query transaction. +// function querySingle($cluster) +// { +// echo "\nRunning: querySingle example\n"; +// // tag::querySingle[] +// try { +// $cluster->transactions()->run( +// function (TransactionAttemptContext $ctx) { +// $bulkLoadStatement = "..."; // a bulk-loading SQL++ (N1QL) statement not provided here + +// $ctx->query($bulkLoadStatement); +// } +// ); +// } catch (\Couchbase\Exception\TransactionFailedException $e) { +// echo "Transaction did not reach commit point\n"; +// } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { +// echo "Transaction possibly committed\n"; +// } +// // end::querySingle[] +// } + +// SKIP querySingleScoped till checked Scoped examples above! +// async function querySingleScoped() { +// let cluster = await getCluster() + +// const bulkLoadStatement = "" /* your statement here */ + +// // String bulkLoadStatement = null /* your statement here */; + +// // // tag::querySingleScoped[] +// const travelSample = cluster.bucket("travel-sample") +// const inventory = travelSample.scope("inventory") +// // TODO: enable after implementation +// // cluster.query(bulkLoadStatement, queryOptions().asTransaction()) +// // // end::querySingleScoped[] +// } + +echo "\nRunning: full example\n"; +// tag::full[] +function playerHitsMonster($damage, $playerId, $monsterId, $cluster, $collection) +{ + try { + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($damage, $playerId, $monsterId, $collection) { + $monsterDoc = $ctx->get($collection, $monsterId); + $monsterContent = $monsterDoc->content(); + $playerDoc = $ctx->get($playerId, $monsterId); + $playerContent = $playerDoc->content(); + + $monsterHitpoints = $monsterContent["hitpoints"]; + $monsterNewHitpoints = $monsterHitpoints - $damage; + + if ($monsterNewHitpoints <= 0) { + // Monster is killed. The remove is just for demoing, and a more realistic + // example would set a "dead" flag or similar. + $ctx->remove($monsterDoc); + + // The player earns experience for killing the monster + $experienceForKillingMonster = $monsterContent["experienceWhenKilled"]; + $playerExperience = $playerContent["experience"]; + $playerNewExperience = $playerExperience + $experienceForKillingMonster; + $playerNewLevel = calculateLevelForExperience($playerNewExperience); + + $playerContent['experience'] = $playerNewExperience; + $playerContent['level'] = $playerNewLevel; + + $ctx->replace($playerDoc, $playerContent); + } + } + ); + } catch (\Couchbase\Exception\TransactionFailedException $e) { + echo "Transaction did not reach commit point\n"; + // The operation failed. Both the monster and the player will be untouched. + // + // Situations that can cause this would include either the monster + // or player not existing (as get is used), or a persistent + // failure to be able to commit the transaction, for example on + // prolonged node failure. + } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { + // Indicates the state of a transaction ended as ambiguous and may or + // may not have committed successfully. + // + // Situations that may cause this would include a network or node failure + // after the transactions operations completed and committed, but before the + // commit result was returned to the client + echo "Transaction possibly committed\n"; + } +} +// end::full[] + +class InsufficientBalanceException extends Exception +{ +} + +function rollbackCause($cluster, $collection) +{ + echo "\nRunning: rollback-cause example\n"; + // tag::rollback-cause[] + $costOfItem = 10; + + try { + $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection, $costOfItem) { + $customer = $ctx->get($collection, "customer-name"); + + if ($customer->content()["balance"] < $costOfItem) { + throw new \InsufficientBalanceException("Transaction failed, customer does not have enough funds."); + } + // else continue transaction + } + ); + } catch (\Couchbase\Exception\TransactionFailedException $e) { + echo "Transaction did not reach commit point: $e\n"; + } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { + echo "Transaction possibly committed: $e\n"; + } + // end::rollback-cause[] +} + +echo "\nRunning: full-error-handling example\n"; +function completeErrorHandling($cluster, $collection) +{ + $costOfItem = 0; + // tag::full-error-handling[] + try { + $result = $cluster->transactions()->run( + function (TransactionAttemptContext $ctx) use ($collection, $costOfItem) { + // ... transactional code here ... + } + ); + + // The transaction definitely reached the commit point. Unstaging + // the individual documents may or may not have completed + + if (!$result->unstagingComplete) { + // In rare cases, the application may require the commit to have + // completed. (Recall that the asynchronous cleanup process is + // still working to complete the commit.) + // The next step is application-dependent. + } + } catch (\Couchbase\Exception\TransactionFailedException $e) { + echo "Transaction did not reach commit point\n"; + } catch (\Couchbase\Exception\TransactionCommitAmbiguousException $e) { + echo "Transaction possibly committed\n"; + } + // end::full-error-handling[] +} + +echo "\n\nTransactions Examples completed successfully\n\n"; diff --git a/modules/devguide/examples/php/transcoding.php b/modules/devguide/examples/php/transcoding.php new file mode 100644 index 00000000..4e23be86 --- /dev/null +++ b/modules/devguide/examples/php/transcoding.php @@ -0,0 +1,113 @@ +credentials('Administrator', 'password'); +$cluster = new Cluster('couchbase://localhost', $options); + +/* + * We open the default bucket to store our cached data in. + */ +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->scope("inventory")->collection("airport"); + +/* + * Some flags for differentiating what kind of data is stored so our + * decoder knows what to do with it. + */ +define('CBTE_FLAG_IMG', 1); +define('CBTE_FLAG_JSON', 2); + + +// tag::encoder[] +/* + * Lets define some custom transcoding functions. For this example, any + * image types that are stored will be serialized as a PNG, and all other + * object types will be encoded as JSON. + */ +function example_encoder($value) { + if (gettype($value) == 'resource' && get_resource_type($value) == 'gd') { + // This is am image, lets capture the PNG data! + ob_start(); + imagepng($value); + $png_data = ob_get_contents(); + ob_end_clean(); + + // Return our bytes and flags + return array($png_data, CBTE_FLAG_IMG, 0); + } else { + // This is an arbitrary type, lets JSON encode it + $json_data = json_encode($value); + + // Return our bytes and flags + return array($json_data, CBTE_FLAG_JSON, 0); + } +} +// end::encoder[] + +// tag::decoder[] +function example_decoder($bytes, $flags, $datatype) { + if ($flags == CBTE_FLAG_IMG) { + // Recreate our image object from the stored data + return imagecreatefromstring($bytes); + } else if ($flags == CBTE_FLAG_JSON) { + // Simply JSON decode + return json_decode($bytes); + } else { + // Ugh oh... + return NULL; + } +} +// end::decoder[] + + +// tag::usage[] +/* + * Create an image to test with + */ +$im = imagecreatetruecolor(300, 50); +$text_color = imagecolorallocate($im, 233, 14, 91); +imagestring($im, 6, 10, 10, 'Couchbase Rocks!', $text_color); + +/* + * Store it in Couchbase. This should execute our custom encoder. + */ +$options = new UpsertOptions(); +$options->encoder('example_encoder'); // Could be any callable. +$collection->upsert('test_image', $im, $options); + +/* + * Now lets retreive it back, it should still be an image thanks to our + * custom decoder. + */ +$options = new GetOptions(); +$options->decoder('example_decoder'); // Could be any callable. +$image_doc = $collection->get('test_image', $options); + +/* + * Output our retrieved document to the browser with a image/png content-type. + */ +header('Content-Type: image/png'); +imagepng($image_doc->content()); +// end::usage[] diff --git a/modules/devguide/examples/php/using-cas.php b/modules/devguide/examples/php/using-cas.php new file mode 100644 index 00000000..e2a7d8eb --- /dev/null +++ b/modules/devguide/examples/php/using-cas.php @@ -0,0 +1,66 @@ +get($userId); + + // Increment the visit count + $user = $res->content(); + $user["visit_count"]++; + + try { + // Attempt to replace the document using CAS + $opts = new ReplaceOptions(); + $opts->cas($res->cas()); + $collection->replace($userId, $user, $opts); + } catch (CasMismatchException $ex) { + continue; + } + + // If no errors occured during the replace, we can exit our retry loop + return; + } + printf("Replace failed after %d attempts\n", $maxRetries); +} +// #end::increment[] + + +function lockingAndCas(Collection $collection, string $userId) { +// #tag::locking[] + $res = $collection->getAndLock($userId, 2 /* seconds */); + $lockedCas = $res->cas(); + + /* // an example of simply unlocking the document: + * $collection->unlock($userId, $lockedCas); + */ + + // Increment the visit count + $user = $res->content(); + $user["visit_count"]++; + + $opts = new ReplaceOptions(); + $opts->cas($lockedCas); + $collection->replace($userId, $user, $opts); +// #end::locking[] +} + +$opts = new ClusterOptions(); +$opts->credentials("Administrator", "password"); +$cluster = new Cluster("couchbase://localhost", $opts); + +$bucket = $cluster->bucket("travel-sample"); +$collection = $bucket->scope("inventory")->collection("airport"); + +$collection->upsert("userId", ["visit_count" => 0]); + +incrementVisitCount($collection, "userId"); +lockingAndCas($collection, "userId"); diff --git a/modules/devguide/striptags.rb b/modules/devguide/striptags.rb new file mode 100755 index 00000000..803e971c --- /dev/null +++ b/modules/devguide/striptags.rb @@ -0,0 +1,39 @@ +#!/usr/bin/ruby + +project = "docs-sdk-php" +current_branch = `git branch --show-current`.strip +header_template = <