diff --git a/docs/index.txt b/docs/index.txt
index 20045f524..77890982c 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -37,6 +37,8 @@ following pages should help you get started:
- :doc:`/reference/bson`
+Code examples can be found in the ``examples`` directory in the source code.
+
If you have previously worked with the legacy ``mongo`` extension, it will be
helpful to review the :doc:`/upgrade` for a summary of API changes between the
old driver and this library.
diff --git a/examples/aggregate.php b/examples/aggregate.php
new file mode 100644
index 000000000..9a4873593
--- /dev/null
+++ b/examples/aggregate.php
@@ -0,0 +1,58 @@
+test->coll;
+$collection->drop();
+
+$documents = [];
+
+for ($i = 0; $i < 100; $i++) {
+ $documents[] = ['randomValue' => rand(0, 1000)];
+}
+
+$collection->insertMany($documents);
+
+$pipeline = [
+ [
+ '$group' => [
+ '_id' => null,
+ 'totalCount' => ['$sum' => 1],
+ 'evenCount' => [
+ '$sum' => ['$mod' => ['$randomValue', 2]],
+ ],
+ 'oddCount' => [
+ '$sum' => ['$subtract' => [1, ['$mod' => ['$randomValue', 2]]]],
+ ],
+ 'maxValue' => ['$max' => '$randomValue'],
+ 'minValue' => ['$min' => '$randomValue'],
+ ],
+ ],
+];
+
+$cursor = $collection->aggregate($pipeline);
+
+foreach ($cursor as $document) {
+ assert(is_object($document));
+ printf("%s\n", toJSON($document));
+}
diff --git a/examples/bulk.php b/examples/bulk.php
new file mode 100644
index 000000000..1af53f755
--- /dev/null
+++ b/examples/bulk.php
@@ -0,0 +1,78 @@
+test->coll;
+$collection->drop();
+
+$documents = [];
+
+for ($i = 0; $i < 10; $i++) {
+ $documents[] = ['x' => $i];
+}
+
+$collection->insertMany($documents);
+
+$collection->bulkWrite(
+ [
+ [
+ 'deleteMany' => [
+ ['x' => ['$gt' => 7]], // Filter
+ ],
+ ],
+ [
+ 'deleteOne' => [
+ ['x' => 4], // Filter
+ ],
+ ],
+ [
+ 'replaceOne' => [
+ ['x' => 1], // Filter
+ ['y' => 1], // Replacement
+ ],
+ ],
+ [
+ 'updateMany' => [
+ ['x' => ['$gt' => 5]], // Filter
+ ['$set' => ['updateMany' => true]], // Update
+ ],
+ ],
+ [
+ 'updateOne' => [
+ ['x' => 2], // Filter
+ ['$set' => ['y' => 2]], // Update
+ ],
+ ],
+ [
+ 'insertOne' => [
+ ['x' => 10], // Document
+ ],
+ ],
+ ]
+);
+
+$cursor = $collection->find([]);
+
+foreach ($cursor as $document) {
+ assert(is_object($document));
+ printf("%s\n", toJSON($document));
+}
diff --git a/examples/changestream.php b/examples/changestream.php
index b897da4b2..b54be8ff2 100644
--- a/examples/changestream.php
+++ b/examples/changestream.php
@@ -3,8 +3,6 @@
namespace MongoDB\Examples;
-require '../vendor/autoload.php';
-
use MongoDB\Client;
use function assert;
@@ -18,11 +16,14 @@
use const STDERR;
+require __DIR__ . '/../vendor/autoload.php';
+
function toJSON(object $document): string
{
return toRelaxedExtendedJSON(fromPHP($document));
}
+// Change streams require a replica set or sharded cluster
$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/');
$collection = $client->test->coll;
diff --git a/examples/command_logger.php b/examples/command_logger.php
index b987f6e19..7eab169bf 100644
--- a/examples/command_logger.php
+++ b/examples/command_logger.php
@@ -3,8 +3,6 @@
namespace MongoDB\Examples;
-require '../vendor/autoload.php';
-
use MongoDB\Client;
use MongoDB\Driver\Monitoring\CommandFailedEvent;
use MongoDB\Driver\Monitoring\CommandStartedEvent;
@@ -22,12 +20,13 @@
use const STDERR;
+require __DIR__ . '/../vendor/autoload.php';
+
function toJSON(object $document): string
{
return toRelaxedExtendedJSON(fromPHP($document));
}
-// phpcs:disable Squiz.Classes.ClassFileName.NoMatch
class CommandLogger implements CommandSubscriber
{
public function commandStarted(CommandStartedEvent $event): void
diff --git a/examples/persistable.php b/examples/persistable.php
new file mode 100644
index 000000000..f41cc54b3
--- /dev/null
+++ b/examples/persistable.php
@@ -0,0 +1,109 @@
+ */
+ public $emails = [];
+
+ public function __construct(string $name)
+ {
+ $this->id = new ObjectId();
+ $this->name = $name;
+ }
+
+ public function getId(): ObjectId
+ {
+ return $this->id;
+ }
+
+ public function bsonSerialize(): object
+ {
+ return (object) [
+ '_id' => $this->id,
+ 'name' => $this->name,
+ 'emails' => $this->emails,
+ ];
+ }
+
+ public function bsonUnserialize(array $data): void
+ {
+ if (! $data['_id'] instanceof ObjectId) {
+ throw new UnexpectedValueException('_id field is not of the expected type');
+ }
+
+ if (! $data['emails'] instanceof BSONArray) {
+ throw new UnexpectedValueException('emails field is not of the expected type');
+ }
+
+ $this->id = $data['_id'];
+ $this->name = (string) $data['name'];
+
+ /** @psalm-suppress MixedPropertyTypeCoercion */
+ $this->emails = $data['emails']->getArrayCopy(); // Emails will be passed as a BSONArray instance
+ }
+}
+
+class PersistableEmail implements Persistable
+{
+ /** @var string */
+ public $type;
+
+ /** @var string */
+ public $address;
+
+ public function __construct(string $type, string $address)
+ {
+ $this->type = $type;
+ $this->address = $address;
+ }
+
+ public function bsonSerialize(): object
+ {
+ return (object) [
+ 'type' => $this->type,
+ 'address' => $this->address,
+ ];
+ }
+
+ public function bsonUnserialize(array $data): void
+ {
+ $this->type = (string) $data['type'];
+ $this->address = (string) $data['address'];
+ }
+}
+
+$entry = new PersistableEntry('alcaeus');
+$entry->emails[] = new PersistableEmail('work', 'alcaeus@example.com');
+$entry->emails[] = new PersistableEmail('private', 'secret@example.com');
+
+$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/');
+
+$collection = $client->test->coll;
+$collection->drop();
+
+$collection->insertOne($entry);
+
+$foundEntry = $collection->findOne([]);
+
+/** @psalm-suppress ForbiddenCode */
+var_dump($foundEntry);
diff --git a/examples/typemap.php b/examples/typemap.php
new file mode 100644
index 000000000..02d222e01
--- /dev/null
+++ b/examples/typemap.php
@@ -0,0 +1,120 @@
+ */
+ private $emails;
+
+ private function __construct()
+ {
+ }
+
+ public function getId(): ObjectId
+ {
+ return $this->id;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getEmails(): array
+ {
+ return $this->emails;
+ }
+
+ public function bsonUnserialize(array $data): void
+ {
+ if (! $data['_id'] instanceof ObjectId) {
+ throw new UnexpectedValueException('_id field is not of the expected type');
+ }
+
+ if (! is_array($data['emails'])) {
+ throw new UnexpectedValueException('emails field is not of the expected type');
+ }
+
+ $this->id = $data['_id'];
+ $this->name = (string) $data['name'];
+
+ /** @psalm-suppress MixedPropertyTypeCoercion */
+ $this->emails = $data['emails'];
+ }
+}
+
+class TypeMapEmail implements Unserializable
+{
+ /** @var string */
+ private $type;
+
+ /** @var string */
+ private $address;
+
+ private function __construct()
+ {
+ }
+
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ public function getAddress(): string
+ {
+ return $this->address;
+ }
+
+ public function bsonUnserialize(array $data): void
+ {
+ $this->type = (string) $data['type'];
+ $this->address = (string) $data['address'];
+ }
+}
+
+$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/');
+
+$collection = $client->test->coll;
+$collection->drop();
+
+$document = [
+ 'name' => 'alcaeus',
+ 'emails' => [
+ ['type' => 'work', 'address' => 'alcaeus@example.com'],
+ ['type' => 'private', 'address' => 'secret@example.com'],
+ ],
+];
+
+$collection->insertOne($document);
+
+$typeMap = [
+ 'root' => TypeMapEntry::class, // Root object will be an Entry instance
+ 'fieldPaths' => [
+ 'emails' => 'array', // Emails field is used as PHP array
+ 'emails.$' => TypeMapEmail::class, // Each element in the emails array will be an Email instance
+ ],
+];
+
+$entry = $collection->findOne([], ['typeMap' => $typeMap]);
+
+/** @psalm-suppress ForbiddenCode */
+var_dump($entry);
diff --git a/examples/with_transaction.php b/examples/with_transaction.php
new file mode 100644
index 000000000..a30a9ab2b
--- /dev/null
+++ b/examples/with_transaction.php
@@ -0,0 +1,56 @@
+= 4.0) or sharded cluster (MongoDB >= 4.2)
+$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/');
+
+$collection = $client->test->coll;
+$collection->drop();
+
+$insertData = function (Session $session) use ($collection): void {
+ $collection->insertMany(
+ [
+ ['x' => 1],
+ ['x' => 2],
+ ['x' => 3],
+ ],
+ ['session' => $session]
+ );
+
+ $collection->updateMany(
+ ['x' => ['$gt' => 1]],
+ ['$set' => ['y' => 1]],
+ ['session' => $session]
+ );
+};
+
+$session = $client->startSession();
+
+with_transaction($session, $insertData);
+
+$cursor = $collection->find([]);
+
+foreach ($cursor as $document) {
+ assert(is_object($document));
+ printf("%s\n", toJSON($document));
+}
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 546988605..7db7074b7 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -176,6 +176,10 @@
/tests/GridFS/UnusableStream.php
+ /examples
/tests/PHPUnit/ConstraintTrait.php
+
+ /examples
+
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 952117897..179ce8c12 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1,5 +1,14 @@
+
+
+ $address
+ $emails
+ $id
+ $name
+ $type
+
+
$driverOptions['driver'] ?? []