collection = $collection; // Set type map to return plain arrays instead of objects // This converts BSON types to PHP native types $this->collection = $collection->withOptions([ 'typeMap' => [ 'root' => 'array', 'document' => 'array', 'array' => 'array' ] ]); } /** * Find documents in the collection * * @param array $filter Query filter * @param array $options Query options * @return Cursor */ public function find(array $filter = [], array $options = []): Cursor { $filter = $this->convertFilter($filter); /** @var \Iterator $cursor */ $cursor = $this->collection->find($filter, $options); return new Cursor($cursor); } /** * Find a single document * * @param array $filter Query filter * @param array $options Query options * @return array|null Returns array with _id as string */ public function findOne(array $filter = [], array $options = []): ?array { $filter = $this->convertFilter($filter); $result = $this->collection->findOne($filter, $options); if ($result === null) { return null; } // Convert to array if it's an object if (is_object($result)) { $result = (array) $result; } return $this->convertBsonToNative($result); } /** * Insert a single document * * @param array|object $document Document to insert * @param array $options Insert options * @return InsertOneResult */ public function insertOne(array|object $document, array $options = []): InsertOneResult { $document = $this->convertDocument($document); return $this->collection->insertOne($document, $options); } /** * Insert multiple documents * * @param array $documents Documents to insert * @param array $options Insert options */ public function insertMany(array $documents, array $options = []): mixed { $documents = array_map(fn($doc) => $this->convertDocument($doc), $documents); return $this->collection->insertMany($documents, $options); } /** * Update a single document * * @param array $filter Query filter * @param array $update Update operations * @param array $options Update options * @return UpdateResult */ public function updateOne(array $filter, array $update, array $options = []): UpdateResult { $filter = $this->convertFilter($filter); $update = $this->convertDocument($update); return $this->collection->updateOne($filter, $update, $options); } /** * Update multiple documents * * @param array $filter Query filter * @param array $update Update operations * @param array $options Update options * @return UpdateResult */ public function updateMany(array $filter, array $update, array $options = []): UpdateResult { $filter = $this->convertFilter($filter); $update = $this->convertDocument($update); return $this->collection->updateMany($filter, $update, $options); } /** * Delete a single document * * @param array $filter Query filter * @param array $options Delete options * @return DeleteResult */ public function deleteOne(array $filter, array $options = []): DeleteResult { $filter = $this->convertFilter($filter); return $this->collection->deleteOne($filter, $options); } /** * Delete multiple documents * * @param array $filter Query filter * @param array $options Delete options * @return DeleteResult */ public function deleteMany(array $filter, array $options = []): DeleteResult { $filter = $this->convertFilter($filter); return $this->collection->deleteMany($filter, $options); } /** * Count documents matching filter * * @param array $filter Query filter * @param array $options Count options * @return int */ public function countDocuments(array $filter = [], array $options = []): int { $filter = $this->convertFilter($filter); return $this->collection->countDocuments($filter, $options); } /** * Execute aggregation pipeline * * @param array $pipeline Aggregation pipeline * @param array $options Aggregation options * @return Cursor */ public function aggregate(array $pipeline, array $options = []): Cursor { /** @var \Iterator $cursor */ $cursor = $this->collection->aggregate($pipeline, $options); return new Cursor($cursor); } /** * Create an index * * @param array $key Index specification * @param array $options Index options * @return string Index name */ public function createIndex(array $key, array $options = []): string { return $this->collection->createIndex($key, $options); } /** * Drop the collection */ public function drop(): array|object|null { return $this->collection->drop(); } /** * Get collection name */ public function getCollectionName(): string { return $this->collection->getCollectionName(); } /** * Get database name */ public function getDatabaseName(): string { return $this->collection->getDatabaseName(); } /** * Convert ObjectId instances in filter to MongoDB ObjectId */ private function convertFilter(array $filter): array { return $this->convertArray($filter); } /** * Convert ObjectId instances in document to MongoDB ObjectId */ private function convertDocument(array|object $document): array|object { if (is_array($document)) { return $this->convertArray($document); } return $document; } /** * Recursively convert ObjectId and UTCDateTime instances */ private function convertArray(array $data): array { foreach ($data as $key => $value) { if ($value instanceof ObjectId) { $data[$key] = $value->toBSON(); } elseif ($value instanceof UTCDateTime) { $data[$key] = $value->toBSON(); } elseif (is_array($value)) { $data[$key] = $this->convertArray($value); } } return $data; } /** * Get the underlying MongoDB Collection * Use sparingly - prefer using wrapper methods */ public function getMongoCollection(): MongoCollection { return $this->collection; } /** * Convert BSON objects to native PHP types * Handles ObjectId, UTCDateTime, and other BSON types */ private function convertBsonToNative(mixed $data): mixed { if (is_array($data)) { foreach ($data as $key => $value) { $data[$key] = $this->convertBsonToNative($value); } return $data; } if (is_object($data)) { // Convert MongoDB BSON ObjectId to string if ($data instanceof \MongoDB\BSON\ObjectId) { return (string) $data; } // Convert MongoDB BSON UTCDateTime to string or DateTime if ($data instanceof \MongoDB\BSON\UTCDateTime) { return (string) $data->toDateTime()->format('c'); } // Convert other objects to arrays recursively if (method_exists($data, 'bsonSerialize')) { return $this->convertBsonToNative($data->bsonSerialize()); } return (array) $data; } return $data; } }