GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( c451b6...d37a73 )
by De
15:02
created

Database::profileAllQueries()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
/**
4
 * This file is part of the PHPMongo package.
5
 *
6
 * (c) Dmytro Sokil <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sokil\Mongo;
13
14
use Sokil\Mongo\Collection\Definition;
15
16
class Database
17
{
18
    /**
19
     *
20
     * @var \Sokil\Mongo\Client
21
     */
22
    private $client;
23
24
    /**
25
     * @var \MongoDB
26
     */
27
    private $mongoDB;
28
29
    /**
30
     * @var array map collection name to class
31
     */
32
    private $mapping = array();
33
34
    /**
35
     * @var array map regexp pattern of collection name to class
36
     */
37
    private $regexpMapping = array();
38
39
    /**
40
     * @var array pool of initialised collections
41
     */
42
    private $collectionPool = array();
43
44
    /**
45
     *
46
     * @var bool is collection pool enabled
47
     */
48
    private $collectionPoolEnabled = true;
49
50
    public function __construct(Client $client, $database) {
51
        $this->client = $client;
52
53
        if ($database instanceof \MongoDB) {
54
            $this->mongoDB = $database;
55
        } else {
56
            $this->mongoDB = $this->client->getMongoClient()->selectDB($database);
57
        }
58
59
    }
60
61
    /**
62
     *
63
     * @param string $username
64
     * @param string $password
65
     */
66
    public function authenticate($username, $password)
67
    {
68
        $this->mongoDB->authenticate($username, $password);
69
    }
70
71
    public function logout()
72
    {
73
        $this->executeCommand(array(
74
            'logout' => 1,
75
        ));
76
    }
77
78
    public function __get($name)
79
    {
80
        return $this->getCollection($name);
81
    }
82
83
    /**
84
     * @return string get name of database
85
     */
86
    public function getName()
87
    {
88
        return $this->mongoDB->__toString();
89
    }
90
91
    /**
92
     *
93
     * @return \MongoDB
94
     */
95
    public function getMongoDB()
96
    {
97
        return $this->mongoDB;
98
    }
99
100
    /**
101
     *
102
     * @return \Sokil\Mongo\Client
103
     */
104
    public function getClient()
105
    {
106
        return $this->client;
107
    }
108
109
    public function disableCollectionPool()
110
    {
111
        $this->collectionPoolEnabled = false;
112
        return $this;
113
    }
114
115
    public function enableCollectionPool()
116
    {
117
        $this->collectionPoolEnabled = true;
118
        return $this;
119
    }
120
121
    public function isCollectionPoolEnabled()
122
    {
123
        return $this->collectionPoolEnabled;
124
    }
125
126
    public function clearCollectionPool()
127
    {
128
        $this->collectionPool = array();
129
        return $this;
130
    }
131
132
    public function isCollectionPoolEmpty()
133
    {
134
        return !$this->collectionPool;
135
    }
136
137
    /**
138
     * Reset specified mapping
139
     *
140
     * @return \Sokil\Mongo\Client
141
     */
142
    public function resetMapping()
143
    {
144
        $this->mapping = array();
145
146
        return $this;
147
    }
148
149
    /**
150
     * Map collection name to class
151
     *
152
     * @param string|array                  $name               collection name or array like [collectionName => collectionClass, ...]
153
     * @param string|array|Definition|null  $classDefinition    if $name is string, then full class name or array with parameters, else omitted
154
     * @return \Sokil\Mongo\Client
155
     */
156
    public function map($name, $classDefinition = null)
157
    {
158
        // map collection to class
159
        if ($classDefinition) {
160
            return $this->defineCollection($name, $classDefinition);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 156 can also be of type array; however, Sokil\Mongo\Database::defineCollection() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
161
        }
162
163
        // map collections to classes
164
        if (is_array($name)) {
165
            foreach ($name as $collectionName => $classDefinition) {
166
                $this->defineCollection($collectionName, $classDefinition);
167
            }
168
            return $this;
169
        }
170
171
        // define class prefix
172
        // deprecated: use class definition
173
        $this->defineCollection('*', array(
174
            'class' => $name,
175
        ));
176
177
        return $this;
178
    }
179
180
    /**
181
     * Define collection through array or Definition instance
182
     * 
183
     * @param string                    $name       collection name
184
     * @param Definition|array|string   $definition collection definition
185
     * @return Database
186
     */
187
    private function defineCollection($name, $definition)
188
    {
189
        // prepare definition object
190
        if (false === ($definition instanceof Definition)) {
191
            if (is_string($definition)) {
192
                $definition = new Definition(array('class' => $definition));
193
            } elseif (is_array($definition)) {
194
                $definition = new Definition($definition);
195
            } else {
196
                throw new Exception(sprintf('Wrong definition passed for collection %s', $name));
197
            }
198
        }
199
200
        // set definition
201
        if ('/' !== substr($name, 0, 1)) {
202
            $this->mapping[$name] = $definition;
203
        } else {
204
            $this->regexpMapping[$name] = $definition;
205
        }
206
207
        return $this;
208
    }
209
210
    /**
211
     * Get class name mapped to collection
212
     *
213
     * @param string        $name               name of collection
214
     * @param array         $defaultDefinition  definition used when no definition found for defined class
215
     * @throws Exception
216
     * @return string|array                     name of class or array of class definition
217
     */
218
    private function getCollectionDefinition($name, array $defaultDefinition = null)
219
    {
220
        if (isset($this->mapping[$name])) {
221
            $classDefinition = $this->mapping[$name];
222
        } elseif ($this->regexpMapping) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->regexpMapping of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
223
            foreach ($this->regexpMapping as $collectionNamePattern => $regexpMappingClassDefinition) {
224
                if (preg_match($collectionNamePattern, $name, $matches)) {
225
                    $classDefinition = clone $regexpMappingClassDefinition;
226
                    $classDefinition->setOption('regexp', $matches);
227
                    break;
228
                }
229
            }
230
        }
231
232
        // mapping not configured - use default
233
        if (!isset($classDefinition)) {
234
            if (!empty($this->mapping['*'])) {
235
                $classDefinition = clone $this->mapping['*'];
236
                $collectionClass = $classDefinition->getClass() . '\\' . implode('\\', array_map('ucfirst', explode('.', $name)));
237
                $classDefinition->setClass($collectionClass);
238
            } else {
239
                $classDefinition = new Definition();
240
                if ($defaultDefinition) {
241
                    $classDefinition->merge($defaultDefinition);
242
                }
243
            }
244
        }
245
246
        // check if class exists
247
        if (!class_exists($classDefinition->getClass())) {
248
            throw new Exception('Class ' . $classDefinition->getClass() . ' not found while map collection name to class');
249
        }
250
251
        return $classDefinition;
252
    }
253
254
    /**
255
     * Create collection
256
     *
257
     * @param string $name name of collection
258
     * @param array|null $options array of options
259
     * @return \Sokil\Mongo\Collection
260
     * @throws \Sokil\Mongo\Exception
261
     */
262
    public function createCollection($name, array $options = null)
263
    {
264
        $classDefinition = $this->getCollectionDefinition($name);
265
        $classDefinition->merge($options);
0 ignored issues
show
Bug introduced by
The method merge cannot be called on $classDefinition (of type string|array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
266
267
        $mongoCollection = $this->mongoDB->createCollection(
268
            $name,
269
            $classDefinition->getMongoCollectionOptions()
0 ignored issues
show
Bug introduced by
The method getMongoCollectionOptions cannot be called on $classDefinition (of type string|array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
270
        );
271
272
        // create collection
273
        $className = $classDefinition->getClass();
0 ignored issues
show
Bug introduced by
The method getClass cannot be called on $classDefinition (of type string|array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
274
        return new $className(
275
            $this,
276
            $mongoCollection,
277
            $classDefinition
278
        );
279
    }
280
281
    /**
282
     *
283
     * @param string $name name of collection
284
     * @param int $maxElements The maximum number of elements to store in the collection.
285
     * @param int $size Size in bytes.
286
     * @return \Sokil\Mongo\Collection
287
     * @throws Exception
288
     */
289
    public function createCappedCollection($name, $maxElements, $size)
290
    {
291
        $options = array(
292
            'capped'    => true,
293
            'size'      => (int) $size,
294
            'max'       => (int) $maxElements,
295
        );
296
297
        if(!$options['size'] && !$options['max']) {
298
            throw new Exception('Size or number of elements must be defined');
299
        }
300
301
        return $this->createCollection($name, $options);
302
    }
303
304
    /**
305
     *
306
     * @param string $name name of collection
307
     * @return \Sokil\Mongo\Collection
308
     * @throws \Sokil\Mongo\Exception
309
     */
310 View Code Duplication
    public function getCollection($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311
    {
312
        // return from pool
313
        if($this->collectionPoolEnabled && isset($this->collectionPool[$name])) {
314
            return $this->collectionPool[$name];
315
        }
316
317
        // no object in pool - init new
318
        $classDefinition = $this->getCollectionDefinition($name);
319
        $className = $classDefinition->getClass();
0 ignored issues
show
Bug introduced by
The method getClass cannot be called on $classDefinition (of type string|array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
320
321
        // create collection class
322
        $collection = new $className($this, $name, $classDefinition);
323
        if(!$collection instanceof \Sokil\Mongo\Collection) {
324
            throw new Exception('Must be instance of \Sokil\Mongo\Collection');
325
        }
326
327
        // store to pool
328
        if($this->collectionPoolEnabled) {
329
            $this->collectionPool[$name] = $collection;
330
        }
331
332
        // return
333
        return $collection;
334
    }
335
336
    /**
337
     * Get Document instance by it's reference
338
     *
339
     * @param array $ref reference to document
340
     * @param bool  $useDocumentPool try to get document from pool or fetch document from database
341
     *
342
     * @return Document|null
343
     */
344 View Code Duplication
    public function getDocumentByReference(array $ref, $useDocumentPool = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
345
    {
346
        $documentArray = $this->mongoDB->getDBRef($ref);
347
        if (null === $documentArray) {
348
            return null;
349
        }
350
351
        return $this->getCollection($ref['$ref'])->hydrate($documentArray, $useDocumentPool);
352
    }
353
354
    /**
355
     * Get instance of GridFS
356
     *
357
     * @param string $name prefix of files and chunks collection
358
     * @return \Sokil\Mongo\GridFS
359
     * @throws \Sokil\Mongo\Exception
360
     */
361 View Code Duplication
    public function getGridFS($name = 'fs')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
362
    {
363
        // return from pool
364
        if($this->collectionPoolEnabled && isset($this->collectionPool[$name])) {
365
            return $this->collectionPool[$name];
366
        }
367
368
        // no object in pool - init new
369
        $classDefinition = $this->getCollectionDefinition($name, array('gridfs' => true));
370
        $className = $classDefinition->getClass();
0 ignored issues
show
Bug introduced by
The method getClass cannot be called on $classDefinition (of type string|array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
371
372
        // create collection class
373
        $collection = new $className($this, $name, $classDefinition);
374
        if(!$collection instanceof \Sokil\Mongo\GridFS) {
375
            throw new Exception('Must be instance of \Sokil\Mongo\GridFS');
376
        }
377
378
        // store to pool
379
        if($this->collectionPoolEnabled) {
380
            $this->collectionPool[$name] = $collection;
381
        }
382
383
        // return
384
        return $collection;
385
    }
386
387
    /**
388
     *
389
     * @param string $channel name of channel
390
     * @return \Sokil\Mongo\Queue
391
     */
392
    public function getQueue($channel)
393
    {
394
        return new Queue($this, $channel);
395
    }
396
397
    /**
398
     * Get cache
399
     *
400
     * @param string $namespace
401
     * @return \Sokil\Mongo\Cache
402
     */
403
    public function getCache($namespace)
404
    {
405
        return new Cache($this, $namespace);
406
    }
407
408
    public function readPrimaryOnly()
409
    {
410
        $this->mongoDB->setReadPreference(\MongoClient::RP_PRIMARY);
411
        return $this;
412
    }
413
414
    public function readPrimaryPreferred(array $tags = null)
415
    {
416
        $this->mongoDB->setReadPreference(\MongoClient::RP_PRIMARY_PREFERRED, $tags);
417
        return $this;
418
    }
419
420
    public function readSecondaryOnly(array $tags = null)
421
    {
422
        $this->mongoDB->setReadPreference(\MongoClient::RP_SECONDARY, $tags);
423
        return $this;
424
    }
425
426
    public function readSecondaryPreferred(array $tags = null)
427
    {
428
        $this->mongoDB->setReadPreference(\MongoClient::RP_SECONDARY_PREFERRED, $tags);
429
        return $this;
430
    }
431
432
    public function readNearest(array $tags = null)
433
    {
434
        $this->mongoDB->setReadPreference(\MongoClient::RP_NEAREST, $tags);
435
        return $this;
436
    }
437
438
    public function getReadPreference()
439
    {
440
        return $this->mongoDB->getReadPreference();
441
    }
442
443
    /**
444
     * Define write concern.
445
     * May be used only if mongo extension version >=1.5
446
     *
447
     * @param string|integer $w write concern
448
     * @param int $timeout timeout in milliseconds
449
     * @return \Sokil\Mongo\Database
450
     * @throws \Sokil\Mongo\Exception
451
     */
452
    public function setWriteConcern($w, $timeout = 10000)
453
    {
454
        if(!$this->mongoDB->setWriteConcern($w, (int) $timeout)) {
455
            throw new Exception('Error setting write concern');
456
        }
457
458
        return $this;
459
    }
460
461
    /**
462
     * Define unacknowledged write concern.
463
     * May be used only if mongo extension version >=1.5
464
     *
465
     * @param int $timeout timeout in milliseconds
466
     * @return \Sokil\Mongo\Database
467
     */
468
    public function setUnacknowledgedWriteConcern($timeout = 10000)
469
    {
470
        $this->setWriteConcern(0, (int) $timeout);
471
        return $this;
472
    }
473
474
    /**
475
     * Define majority write concern.
476
     * May be used only if mongo extension version >=1.5
477
     *
478
     * @param int $timeout timeout in milliseconds
479
     * @return \Sokil\Mongo\Database
480
     */
481
    public function setMajorityWriteConcern($timeout = 10000)
482
    {
483
        $this->setWriteConcern('majority', (int) $timeout);
484
        return $this;
485
    }
486
487
    /**
488
     * Get current write concern
489
     * May be used only if mongo extension version >=1.5
490
     *
491
     * @return mixed
492
     */
493
    public function getWriteConcern()
494
    {
495
        return $this->mongoDB->getWriteConcern();
496
    }
497
498
    /**
499
     * Execute Mongo command
500
     *
501
     * @param array $command
502
     * @param array $options
503
     * @return array
504
     */
505
    public function executeCommand(array $command, array $options = array())
506
    {
507
        return $this->mongoDB->command($command, $options);
508
    }
509
510
    public function executeJS($code, array $args = array())
511
    {
512
        $response = $this->mongoDB->execute($code, $args);
513
        if($response['ok'] == 1.0) {
514
            return $response['retval'];
515
        } else {
516
            throw new Exception('Error #' . $response['code'] . ': ' . $response['errmsg'], $response['code']);
517
        }
518
    }
519
520
    public function stats()
521
    {
522
        return $this->executeCommand(array(
523
            'dbstats' => 1,
524
        ));
525
    }
526
527
    public function getLastError()
528
    {
529
        return $this->mongoDB->lastError();
530
    }
531
532
    public function getProfilerParams()
533
    {
534
        return $this->executeCommand(array(
535
            'profile'   => -1,
536
        ));
537
    }
538
539
    public function getProfilerLevel()
540
    {
541
        $params = $this->getProfilerParams();
542
        return $params['was'];
543
    }
544
545
    public function getProfilerSlowMs()
546
    {
547
        $params = $this->getProfilerParams();
548
        return $params['slowms'];
549
    }
550
551
    public function disableProfiler()
552
    {
553
        return $this->executeCommand(array(
554
            'profile'   => 0,
555
        ));
556
    }
557
558
    public function profileSlowQueries($slowms = 100)
559
    {
560
        return $this->executeCommand(array(
561
            'profile'   => 1,
562
            'slowms'    => (int) $slowms
563
        ));
564
    }
565
566
    public function profileAllQueries($slowms = null)
567
    {
568
        $command = array(
569
            'profile'   => 2,
570
        );
571
572
        if($slowms) {
573
            $command['slowms'] = (int) $slowms;
574
        }
575
576
        return $this->executeCommand($command);
577
    }
578
579
    /**
580
     *
581
     * @return \Sokil\Mongo\Cursor
582
     */
583
    public function findProfilerRows()
584
    {
585
        return $this
0 ignored issues
show
Bug introduced by
The method asArray does only exist in Sokil\Mongo\Cursor, but not in Sokil\Mongo\Expression.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
586
            ->getCollection('system.profile')
587
            ->find()
588
            ->asArray();
589
    }
590
}
591