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'] ?? []