Completed
Pull Request — master (#21)
by
unknown
38:19 queued 30:53
created

AbstractCursor::errorIfOpened()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 3
cts 4
cp 0.75
rs 9.4286
nc 2
cc 2
eloc 4
nop 0
crap 2.0625
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
namespace Alcaeus\MongoDbAdapter;
17
18
use Alcaeus\MongoDbAdapter\Helper\ReadPreference;
19
use MongoDB\Collection;
20
use MongoDB\Driver\Cursor;
21
22
/**
23
 * @internal
24
 */
25
abstract class AbstractCursor
26
{
27
    use ReadPreference;
28
29
    /**
30
     * @var int
31
     */
32
    protected $batchSize;
33
34
    /**
35
     * @var Collection
36
     */
37
    protected $collection;
38
39
    /**
40
     * @var \MongoClient
41
     */
42
    protected $connection;
43
44
    /**
45
     * @var Cursor
46
     */
47
    protected $cursor;
48
49
    /**
50
     * @var \MongoDB\Database
51
     */
52
    protected $db;
53
54
    /**
55
     * @var \IteratorIterator
56
     */
57
    protected $iterator;
58
59
    /**
60
     * @var string
61
     */
62
    protected $ns;
63
64
    /**
65
     * @var array
66
     */
67
    protected $optionNames = [
68
        'batchSize',
69
        'readPreference',
70
    ];
71
72
    /**
73
     * @return Cursor
74
     */
75
    abstract protected function ensureCursor();
76
77
    /**
78
     * @return array
79
     */
80
    abstract protected function getCursorInfo();
81
82
    /**
83
     * Create a new cursor
84
     * @link http://www.php.net/manual/en/mongocursor.construct.php
85
     * @param \MongoClient $connection Database connection.
86
     * @param string $ns Full name of database and collection.
87
     */
88 31
    public function __construct(\MongoClient $connection, $ns)
89
    {
90 31
        $this->connection = $connection;
91 31
        $this->ns = $ns;
92
93 31
        $nsParts = explode('.', $ns);
94 31
        $dbName = array_shift($nsParts);
95 31
        $collectionName = implode('.', $nsParts);
96
97 31
        $this->db = $connection->selectDB($dbName)->getDb();
98
99 31
        if ($collectionName) {
100 23
            $this->collection = $connection->selectCollection($dbName, $collectionName)->getCollection();
101
        }
102 31
    }
103
104
    /**
105
     * Returns the current element
106
     * @link http://www.php.net/manual/en/mongocursor.current.php
107
     * @return array
108
     */
109 10
    public function current()
110
    {
111 10
        $document = $this->ensureIterator()->current();
112 10
        if ($document !== null) {
113 10
            $document = TypeConverter::toLegacy($document);
114
        }
115
116 10
        return $document;
117
    }
118
119
    /**
120
     * Returns the current result's _id
121
     * @link http://www.php.net/manual/en/mongocursor.key.php
122
     * @return string The current result's _id as a string.
123
     */
124 10
    public function key()
125
    {
126 10
        return $this->ensureIterator()->key();
127
    }
128
129
    /**
130
     * Advances the cursor to the next result
131
     * @link http://www.php.net/manual/en/mongocursor.next.php
132
     * @throws \MongoConnectionException
133
     * @throws \MongoCursorTimeoutException
134
     * @return void
135
     */
136 10
    public function next()
137
    {
138 10
        $this->ensureIterator()->next();
139 10
    }
140
141
    /**
142
     * Returns the cursor to the beginning of the result set
143
     * @throws \MongoConnectionException
144
     * @throws \MongoCursorTimeoutException
145
     * @return void
146
     */
147 28
    public function rewind()
148
    {
149
        // We can recreate the cursor to allow it to be rewound
150 28
        $this->reset();
151 28
        $this->ensureIterator()->rewind();
152 26
    }
153
154
    /**
155
     * Checks if the cursor is reading a valid result.
156
     * @link http://www.php.net/manual/en/mongocursor.valid.php
157
     * @return boolean If the current result is not null.
158
     */
159 26
    public function valid()
160
    {
161 26
        return $this->ensureIterator()->valid();
162
    }
163
164
    /**
165
     * Limits the number of elements returned in one batch.
166
     *
167
     * @link http://docs.php.net/manual/en/mongocursor.batchsize.php
168
     * @param int $batchSize The number of results to return per batch
169
     * @return $this Returns this cursor.
170
     */
171 1
    public function batchSize($batchSize)
172
    {
173 1
        $this->batchSize = $batchSize;
174
175 1
        return $this;
176
    }
177
178
    /**
179
     * Checks if there are documents that have not been sent yet from the database for this cursor
180
     * @link http://www.php.net/manual/en/mongocursor.dead.php
181
     * @return boolean Returns if there are more results that have not been sent to the client, yet.
182
     */
183
    public function dead()
184
    {
185
        return $this->ensureCursor()->isDead();
186
    }
187
188
    /**
189
     * @return array
190
     */
191 2
    public function info()
192
    {
193 2
        return $this->getCursorInfo() + $this->getIterationInfo();
194
    }
195
196
    /**
197
     * @link http://www.php.net/manual/en/mongocursor.setreadpreference.php
198
     * @param string $readPreference
199
     * @param array $tags
200
     * @return $this Returns this cursor.
201
     */
202 31
    public function setReadPreference($readPreference, $tags = null)
203
    {
204 31
        $this->setReadPreferenceFromParameters($readPreference, $tags);
205
206 31
        return $this;
207
    }
208
209
    /**
210
     * Sets a client-side timeout for this query
211
     * @link http://www.php.net/manual/en/mongocursor.timeout.php
212
     * @param int $ms The number of milliseconds for the cursor to wait for a response. By default, the cursor will wait forever.
213
     * @return $this Returns this cursor
214
     */
215
    public function timeout($ms)
0 ignored issues
show
Unused Code introduced by
The parameter $ms is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
216
    {
217
        $this->notImplemented();
218
    }
219
220
    /**
221
     * Applies all options set on the cursor, overwriting any options that have already been set
222
     *
223
     * @param array $optionNames Array of option names to be applied (will be read from properties)
224
     * @return array
225
     */
226 29
    protected function getOptions($optionNames = null)
227
    {
228 29
        $options = [];
229
230 29
        if ($optionNames === null) {
231 28
            $optionNames = $this->optionNames;
232
        }
233
234 29
        foreach ($optionNames as $option) {
235 29
            $converter = 'convert' . ucfirst($option);
236 29
            $value = method_exists($this, $converter) ? $this->$converter() : $this->$option;
237
238 29
            if ($value === null) {
239 29
                continue;
240
            }
241
242 29
            $options[$option] = $value;
243
        }
244
245 29
        return $options;
246
    }
247
248
    /**
249
     * @return \IteratorIterator
250
     */
251 28
    protected function ensureIterator()
252
    {
253 28
        if ($this->iterator === null) {
254 28
            $this->iterator = new \IteratorIterator($this->ensureCursor());
255
        }
256
257 26
        return $this->iterator;
258
    }
259
260
    /**
261
     * @throws \MongoCursorException
262
     */
263 14
    protected function errorIfOpened()
264
    {
265 14
        if ($this->cursor === null) {
266 14
            return;
267
        }
268
269
        throw new \MongoCursorException('cannot modify cursor after beginning iteration.');
270
    }
271
272
    /**
273
     * @return array
274
     */
275 2
    protected function getIterationInfo()
276
    {
277
        $iterationInfo = [
278 2
            'started_iterating' => $this->cursor !== null,
279
        ];
280
281 2
        if ($this->cursor !== null) {
282 2
            switch ($this->cursor->getServer()->getType()) {
283
                case \MongoDB\Driver\Server::TYPE_RS_ARBITER:
284
                    $typeString = 'ARBITER';
285
                    break;
286
                case \MongoDB\Driver\Server::TYPE_MONGOS:
287
                    $typeString = 'MONGOS';
288
                    break;
289
                case \MongoDB\Driver\Server::TYPE_RS_PRIMARY:
290
                    $typeString = 'PRIMARY';
291
                    break;
292 2
                case \MongoDB\Driver\Server::TYPE_RS_SECONDARY:
293
                    $typeString = 'SECONDARY';
294
                    break;
295
                default:
296 2
                    $typeString = 'STANDALONE';
297
            }
298
299
            $iterationInfo += [
300 2
                'id' => (string) $this->cursor->getId(),
301
                'at' => null, // @todo Complete info for cursor that is iterating
302
                'numReturned' => null, // @todo Complete info for cursor that is iterating
303
                'server' => null, // @todo Complete info for cursor that is iterating
304 2
                'host' => $this->cursor->getServer()->getHost(),
305 2
                'port' => $this->cursor->getServer()->getPort(),
306 2
                'connection_type_desc' => $typeString,
307
            ];
308
        }
309
310 2
        return $iterationInfo;
311
    }
312
313
    /**
314
     * @throws \Exception
315
     */
316
    protected function notImplemented()
317
    {
318
        throw new \Exception('Not implemented');
319
    }
320
321
    /**
322
     * Clears the cursor
323
     *
324
     * This is generic but implemented as protected since it's only exposed in MongoCursor
325
     */
326 28
    protected function reset()
327
    {
328 28
        $this->cursor = null;
329 28
        $this->iterator = null;
330 28
    }
331
}
332