Update.php 4.5 KB
Newer Older
1 2 3 4 5
<?php

namespace MongoDB\Operation;

use MongoDB\UpdateResult;
6
use MongoDB\Driver\BulkWrite as Bulk;
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
use MongoDB\Driver\Server;
use MongoDB\Driver\WriteConcern;
use MongoDB\Exception\InvalidArgumentException;

/**
 * Operation for the update command.
 *
 * This class is used internally by the ReplaceOne, UpdateMany, and UpdateOne
 * operation classes.
 *
 * @internal
 * @see http://docs.mongodb.org/manual/reference/command/update/
 */
class Update implements Executable
{
22 23
    private static $wireVersionForDocumentLevelValidation = 4;

24 25 26 27 28 29 30 31 32 33 34
    private $databaseName;
    private $collectionName;
    private $filter;
    private $update;
    private $options;

    /**
     * Constructs a update command.
     *
     * Supported options:
     *
35 36 37
     *  * bypassDocumentValidation (boolean): If true, allows the write to opt
     *    out of document level validation.
     *
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
     *  * multi (boolean): When true, updates all documents matching the query.
     *    This option cannot be true if the $update argument is a replacement
     *    document (i.e. contains no update operators). The default is false.
     *
     *  * upsert (boolean): When true, a new document is created if no document
     *    matches the query. The default is false.
     *
     *  * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
     *
     * @param string       $databaseName   Database name
     * @param string       $collectionName Collection name
     * @param array|object $filter         Query by which to delete documents
     * @param array|object $update         Update to apply to the matched
     *                                     document(s) or a replacement document
     * @param array        $options        Command options
     * @throws InvalidArgumentException
     */
Jeremy Mikola's avatar
Jeremy Mikola committed
55
    public function __construct($databaseName, $collectionName, $filter, $update, array $options = [])
56 57
    {
        if ( ! is_array($filter) && ! is_object($filter)) {
58
            throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object');
59 60 61
        }

        if ( ! is_array($update) && ! is_object($update)) {
62
            throw InvalidArgumentException::invalidType('$update', $filter, 'array or object');
63 64
        }

Jeremy Mikola's avatar
Jeremy Mikola committed
65
        $options += [
66 67
            'multi' => false,
            'upsert' => false,
Jeremy Mikola's avatar
Jeremy Mikola committed
68
        ];
69

70
        if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) {
71
            throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean');
72 73
        }

74
        if ( ! is_bool($options['multi'])) {
75
            throw InvalidArgumentException::invalidType('"multi" option', $options['multi'], 'boolean');
76 77 78 79 80 81 82
        }

        if ($options['multi'] && ! \MongoDB\is_first_key_operator($update)) {
            throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document');
        }

        if ( ! is_bool($options['upsert'])) {
83
            throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean');
84 85
        }

86
        if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
87
            throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
        }

        $this->databaseName = (string) $databaseName;
        $this->collectionName = (string) $collectionName;
        $this->filter = $filter;
        $this->update = $update;
        $this->options = $options;
    }

    /**
     * Execute the operation.
     *
     * @see Executable::execute()
     * @param Server $server
     * @return UpdateResult
     */
    public function execute(Server $server)
    {
106
        $updateOptions = [
107 108
            'multi' => $this->options['multi'],
            'upsert' => $this->options['upsert'],
Jeremy Mikola's avatar
Jeremy Mikola committed
109
        ];
110

111 112 113 114 115 116 117 118
        $bulkOptions = [];

        if (isset($this->options['bypassDocumentValidation']) && \MongoDB\server_supports_feature($server, self::$wireVersionForDocumentLevelValidation)) {
            $bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
        }

        $bulk = new Bulk($bulkOptions);
        $bulk->update($this->filter, $this->update, $updateOptions);
119 120 121 122 123 124 125

        $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null;
        $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern);

        return new UpdateResult($writeResult);
    }
}