-
Notifications
You must be signed in to change notification settings - Fork 266
Description
When using MongoDB command monitoring (CommandSubscriber
) with nested documents that implement Persistable
interface, calling CommandStartedEvent::getCommand()
after document insertion causes a fatal error due to deserialization issues.
Uncaught Error: Cannot use object of type stdClass as array
The issue occurs when:
- A document with nested objects is inserted into MongoDB
- The command monitoring subscriber attempts to access the command via
CommandStartedEvent::getCommand()
- The MongoDB driver tries to deserialize the command data, but fails because nested documents are stored as
stdClass
objects instead of arrays
Environment
- PHP 8.3.23
- Library 2.1.0
- Server 7.0.12 (standalone docker image, linux/arm64 platform)
mongodb
libbson bundled version => 1.30.5
libmongoc bundled version => 1.30.5
libmongoc SSL => enabled
libmongoc SSL library => OpenSSL
libmongoc crypto => enabled
libmongoc crypto library => libcrypto
libmongoc crypto system profile => disabled
libmongoc SASL => enabled
libmongoc SRV => enabled
libmongoc compression => enabled
libmongoc compression snappy => disabled
libmongoc compression zlib => enabled
libmongoc compression zstd => disabled
libmongocrypt bundled version => 1.12.0
libmongocrypt crypto => enabled
libmongocrypt crypto library => libcrypto
mongodb.debug => no value => no value
Installed modules
[PHP Modules]
amqp
apcu
bz2
Core
ctype
curl
date
dom
exif
fileinfo
filter
gd
gettext
hash
iconv
intl
json
libxml
mbstring
memcached
mongodb
mysqli
mysqlnd
openssl
opentelemetry
pcntl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
random
rdkafka
readline
redis
Reflection
session
SimpleXML
sockets
sodium
SPL
sqlite3
standard
tokenizer
xdebug
xml
xmlreader
xmlwriter
zip
zlib
[Zend Modules]
Xdebug
Test Script
<?php
declare(strict_types=1);
use MongoDB\Driver\Monitoring\CommandFailedEvent;
use MongoDB\Driver\Monitoring\CommandStartedEvent;
use MongoDB\Driver\Monitoring\CommandSubscriber;
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
use MongoDB\BSON\Persistable;
use MongoDB\Client;
use MongoDB\BSON\Unserializable;
require_once __DIR__ . '/vendor/autoload.php';
class NestedDocument
{
public function __construct(public string $name)
{
}
}
class Document implements Persistable
{
public function __construct(
public int $id,
public NestedDocument $nested,
) {
}
public function bsonSerialize(): array
{
return [
'id' => $this->id,
'nested' => ['name' => $this->nested->name],
];
}
public function bsonUnserialize(array $data): void
{
$this->id = $data['id'];
$this->nested = new NestedDocument($data['nested']['name']);
}
}
class CommandLogger implements CommandSubscriber
{
private array $commands;
public function __construct()
{
$this->commands = [];
}
public function commandStarted(CommandStartedEvent $event): void
{
$this->commands[$event->getRequestId()] = [
'dbname' => $event->getDatabaseName(),
'commandName' => $event->getCommandName(),
'command' => $event->getCommand(), // This line causes the error
];
}
public function commandSucceeded(CommandSucceededEvent $event): void
{
unset($this->commands[$event->getRequestId()]);
}
public function commandFailed(CommandFailedEvent $event): void
{
unset($this->commands[$event->getRequestId()]);
}
}
$client = new Client('mongodb://localhost:27017');
$client->addSubscriber(new CommandLogger());
$collection = $client->getDatabase('test')->getCollection('test');
// This works fine - no deserialization issues with queries
var_dump($collection->findOne([]));
// This causes the error when CommandLogger tries to access getCommand()
var_dump($collection->insertOne(new Document(1, new NestedDocument('test name')))->getInsertedId());
Expected Behavior
The CommandStartedEvent::getCommand()
method should return the command data without causing deserialization errors, even when the command involves documents with nested objects (Do not use bsonUnserialize() ?).
Actual Behavior
A fatal error occurs: Cannot use object of type stdClass as array
when trying to access the command data for insert operations involving nested documents.