Uploaded image for project: 'PHP Driver: Library'
  1. PHP Driver: Library
  2. PHPLIB-1137

Prohibit PackedArray objects where a document type is expected

    • Type: Icon: Improvement Improvement
    • Resolution: Fixed
    • Priority: Icon: Unknown Unknown
    • 1.16.1
    • Affects Version/s: None
    • Component/s: None
    • None

      Opening this issue to decide whether we want to explicitly prohibit PackedArray objects where we currently allow "array or object" types for document values. If we ultimately decide not to do so, we can resolve this as "Won't Do".

      In PHPLIB-1122, I intentionally chose to allow PackedArray in an internal document_to_array() utility function, since it is not used for validation but to facilitate convenient access to fields (e.g. checking keys for a dollar prefix to detect operators). Prohibiting PackedArray there would just have required every caller to explicitly ignore PackedArray before invoking the function.

      There is still the question of accepting PackedArray in our public APIs where we currently expect documents. For instance, a PackedArray can currently be provided as a query filter for a Find operation.

      In PHPLIB-1122, I did look into adding PackedArray to TestCase::getInvalidDocumentValues(), which is used as a data provider for our type-checking tests throughout the library. Doing so yielded many test failures because a PackedArray object passes the "array or object" logic currently used for validation.

      While a PackedArray is certainly not a document, an argument can also be made for not adding strict validation:

      • Explicitly prohibiting PackedArray might complicate documentation. The "array|object" type hint for document arguments/options would be technically incorrect.
      • PHPLIB currently doesn't differentiate between Serializable objects that would encode as a BSON array. For example, a BSONArray could be passed as a query filter. Enforcing that would require an additional invocation of bsonSerialize() just for validation, which could incur significant overhead.
      • Specifying a BSONArray or equivalent PackedArray can, in some cases, behave as if the array was an object due to existing behavior in PHPC. In other cases, the array could result in a server exception. Consider the code example below:
      $client = new MongoDB\Client('mongodb://localhost:27017');
      $collection = $client->test->foo;
      $collection->drop();
      $collection->insertOne(['_id' => 1, '0' => 'foo']);
      
      // Both of these queries return the above document
      var_dump($collection->findOne(new MongoDB\Model\BSONArray(['foo'])));
      var_dump($collection->findOne(MongoDB\BSON\PackedArray::fromPHP(['foo'])));
      

      This works because MongoDB\Driver\Query always encodes its filter as a document. Attempting to use a BSONArray or PackedArray in another context (e.g. findAndModify query) results in a server error due to failed type validation:

      // Both of these operations fail with a CommandException:
      // BSON field 'findAndModify.query' is the wrong type 'array', expected type 'object'
      var_dump($collection->findOneAndUpdate(new MongoDB\Model\BSONArray(['foo']), ['$set' => ['0' => 'bar']]));
      var_dump($collection->findOneAndUpdate(MongoDB\BSON\PackedArray::fromPHP(['foo']), ['$set' => ['0' => 'bar']]));
      

            Assignee:
            andreas.braun@mongodb.com Andreas Braun
            Reporter:
            jmikola@mongodb.com Jeremy Mikola
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: