Completed
Push — master ( e1b1f8...a83c37 )
by Andreas
02:50
created

MongoWriteBatch::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4286
cc 1
eloc 4
nc 1
nop 3
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 */
15
16
use Alcaeus\MongoDbAdapter\TypeConverter;
17
use Alcaeus\MongoDbAdapter\Helper\WriteConcernConverter;
18
19
/**
20
 * MongoWriteBatch allows you to "batch up" multiple operations (of same type)
21
 * and shipping them all to MongoDB at the same time. This can be especially
22
 * useful when operating on many documents at the same time to reduce roundtrips.
23
 *
24
 * @see http://php.net/manual/en/class.mongowritebatch.php
25
 */
26
class MongoWriteBatch
1 ignored issue
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
27
{
28
    use WriteConcernConverter;
29
30
    const COMMAND_INSERT = 1;
31
    const COMMAND_UPDATE = 2;
32
    const COMMAND_DELETE = 3;
33
34
    /**
35
     * @var MongoCollection
36
     */
37
    private $collection;
38
39
    /**
40
     * @var int
41
     */
42
    private $batchType;
43
44
    /**
45
     * @var array
46
     */
47
    private $writeOptions;
48
49
    /**
50
     * @var array
51
     */
52
    private $items = [];
53
54
    /**
55
     * Creates a new batch of write operations
56
     *
57
     * @see http://php.net/manual/en/mongowritebatch.construct.php
58
     * @param MongoCollection $collection
59
     * @param int $batchType
60
     * @param array $writeOptions
61
     */
62
    protected function __construct(MongoCollection $collection, $batchType, $writeOptions)
63
    {
64
        $this->collection = $collection;
65
        $this->batchType = $batchType;
66
        $this->writeOptions = $writeOptions;
67
    }
68
69
    /**
70
     * Adds a write operation to a batch
71
     *
72
     * @see http://php.net/manual/en/mongowritebatch.add.php
73
     * @param array|object $item
74
     * @return boolean
75
     */
76
    public function add($item)
77
    {
78
        if (is_object($item)) {
79
            $item = (array)$item;
80
        }
81
82
        $this->validate($item);
83
        $this->addItem($item);
84
85
        return true;
86
    }
87
88
    /**
89
     * Executes a batch of write operations
90
     *
91
     * @see http://php.net/manual/en/mongowritebatch.execute.php
92
     * @param array $writeOptions
93
     * @return array
94
     */
95
    final public function execute(array $writeOptions = [])
96
    {
97
        $writeOptions += $this->writeOptions;
98
        if (! count($this->items)) {
99
            return ['ok' => true];
100
        }
101
102
        if (isset($writeOptions['j'])) {
103
            trigger_error('j parameter is not supported', E_WARNING);
104
        }
105
        if (isset($writeOptions['fsync'])) {
106
            trigger_error('fsync parameter is not supported', E_WARNING);
107
        }
108
109
        $options['writeConcern'] = $this->createWriteConcernFromArray($writeOptions);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
110
        if (isset($writeOptions['ordered'])) {
111
            $options['ordered'] = $writeOptions['ordered'];
112
        }
113
114
        $collection = $this->collection->getCollection();
115
116
        try {
117
            $result = $collection->BulkWrite($this->items, $options);
118
            $ok = 1.0;
119
        } catch (\MongoDB\Driver\Exception\BulkWriteException $e) {
1 ignored issue
show
Bug introduced by
The class MongoDB\Driver\Exception\BulkWriteException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
120
            $result = $e->getWriteResult();
121
            $ok = 0.0;
122
        }
123
124
        if ($ok === 1.0) {
125
            $this->items = [];
126
        }
127
128
        return [
129
            'ok' => $ok,
130
            'nInserted' => $result->getInsertedCount(),
131
            'nMatched' => $result->getMatchedCount(),
132
            'nModified' => $result->getModifiedCount(),
133
            'nUpserted' => $result->getUpsertedCount(),
134
            'nRemoved' => $result->getDeletedCount(),
135
        ];
136
    }
137
138
    private function validate(array $item)
139
    {
140
        switch ($this->batchType) {
141
            case self::COMMAND_UPDATE:
142
                if (! isset($item['q']) || ! isset($item['u'])) {
143
                    throw new Exception('invalid item');
144
                }
145
                break;
146
147
            case self::COMMAND_DELETE:
148
                if (! isset($item['q']) || ! isset($item['limit'])) {
149
                    throw new Exception('invalid item');
150
                }
151
                break;
152
        }
153
    }
154
155
    private function addItem(array $item)
156
    {
157
        switch ($this->batchType) {
158
            case self::COMMAND_UPDATE:
159
                $method = isset($item['multi']) ? 'updateMany' : 'updateOne';
160
161
                $options = [];
162
                if (isset($item['upsert']) && $item['upsert']) {
163
                    $options['upsert'] = true;
164
                }
165
166
                $this->items[] = [$method => [TypeConverter::fromLegacy($item['q']), TypeConverter::fromLegacy($item['u']), $options]];
167
                break;
168
169
            case self::COMMAND_INSERT:
170
                $this->items[] = ['insertOne' => [TypeConverter::fromLegacy($item)]];
171
                break;
172
173
            case self::COMMAND_DELETE:
174
                $method = $item['limit'] === 0 ? 'deleteMany' : 'deleteOne';
175
176
                $this->items[] = [$method => [TypeConverter::fromLegacy($item['q'])]];
177
                break;
178
        }
179
    }
180
}
181