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 ( 2fe4c0...31af9d )
by De
04:35
created

Database::defineCollectionNamespace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 6
rs 9.4285
c 1
b 0
f 0
cc 1
eloc 3
nc 1
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('*', [
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->getMongoDB()->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 instance of GridFS
338
     *
339
     * @param string $name prefix of files and chunks collection
340
     * @return \Sokil\Mongo\GridFS
341
     * @throws \Sokil\Mongo\Exception
342
     */
343 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...
344
    {
345
        // return from pool
346
        if($this->collectionPoolEnabled && isset($this->collectionPool[$name])) {
347
            return $this->collectionPool[$name];
348
        }
349
350
        // no object in pool - init new
351
        $classDefinition = $this->getCollectionDefinition($name, array('gridfs' => true));
352
        $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...
353
354
        // create collection class
355
        $collection = new $className($this, $name, $classDefinition);
356
        if(!$collection instanceof \Sokil\Mongo\GridFS) {
357
            throw new Exception('Must be instance of \Sokil\Mongo\GridFS');
358
        }
359
360
        // store to pool
361
        if($this->collectionPoolEnabled) {
362
            $this->collectionPool[$name] = $collection;
363
        }
364
365
        // return
366
        return $collection;
367
    }
368
369
    /**
370
     *
371
     * @param string $channel name of channel
372
     * @return \Sokil\Mongo\Queue
373
     */
374
    public function getQueue($channel)
375
    {
376
        return new Queue($this, $channel);
377
    }
378
379
    /**
380
     * Get cache
381
     *
382
     * @param string $namespace
383
     * @return \Sokil\Mongo\Cache
384
     */
385
    public function getCache($namespace)
386
    {
387
        return new Cache($this, $namespace);
388
    }
389
390
    public function readPrimaryOnly()
391
    {
392
        $this->mongoDB->setReadPreference(\MongoClient::RP_PRIMARY);
393
        return $this;
394
    }
395
396
    public function readPrimaryPreferred(array $tags = null)
397
    {
398
        $this->mongoDB->setReadPreference(\MongoClient::RP_PRIMARY_PREFERRED, $tags);
399
        return $this;
400
    }
401
402
    public function readSecondaryOnly(array $tags = null)
403
    {
404
        $this->mongoDB->setReadPreference(\MongoClient::RP_SECONDARY, $tags);
405
        return $this;
406
    }
407
408
    public function readSecondaryPreferred(array $tags = null)
409
    {
410
        $this->mongoDB->setReadPreference(\MongoClient::RP_SECONDARY_PREFERRED, $tags);
411
        return $this;
412
    }
413
414
    public function readNearest(array $tags = null)
415
    {
416
        $this->mongoDB->setReadPreference(\MongoClient::RP_NEAREST, $tags);
417
        return $this;
418
    }
419
420
    public function getReadPreference()
421
    {
422
        return $this->mongoDB->getReadPreference();
423
    }
424
425
    /**
426
     * Define write concern.
427
     * May be used only if mongo extension version >=1.5
428
     *
429
     * @param string|integer $w write concern
430
     * @param int $timeout timeout in milliseconds
431
     * @return \Sokil\Mongo\Database
432
     * @throws \Sokil\Mongo\Exception
433
     */
434
    public function setWriteConcern($w, $timeout = 10000)
435
    {
436
        if(!$this->mongoDB->setWriteConcern($w, (int) $timeout)) {
437
            throw new Exception('Error setting write concern');
438
        }
439
440
        return $this;
441
    }
442
443
    /**
444
     * Define unacknowledged write concern.
445
     * May be used only if mongo extension version >=1.5
446
     *
447
     * @param int $timeout timeout in milliseconds
448
     * @return \Sokil\Mongo\Database
449
     */
450
    public function setUnacknowledgedWriteConcern($timeout = 10000)
451
    {
452
        $this->setWriteConcern(0, (int) $timeout);
453
        return $this;
454
    }
455
456
    /**
457
     * Define majority write concern.
458
     * May be used only if mongo extension version >=1.5
459
     *
460
     * @param int $timeout timeout in milliseconds
461
     * @return \Sokil\Mongo\Database
462
     */
463
    public function setMajorityWriteConcern($timeout = 10000)
464
    {
465
        $this->setWriteConcern('majority', (int) $timeout);
466
        return $this;
467
    }
468
469
    /**
470
     * Get current write concern
471
     * May be used only if mongo extension version >=1.5
472
     *
473
     * @return mixed
474
     */
475
    public function getWriteConcern()
476
    {
477
        return $this->mongoDB->getWriteConcern();
478
    }
479
480
    /**
481
     * Execute Mongo command
482
     *
483
     * @param array $command
484
     * @param array $options
485
     * @return array
486
     */
487
    public function executeCommand(array $command, array $options = array())
488
    {
489
        return $this->getMongoDB()->command($command, $options);
490
    }
491
492
    public function executeJS($code, array $args = array())
493
    {
494
        $response = $this->getMongoDB()->execute($code, $args);
495
        if($response['ok'] == 1.0) {
496
            return $response['retval'];
497
        } else {
498
            throw new Exception('Error #' . $response['code'] . ': ' . $response['errmsg'], $response['code']);
499
        }
500
    }
501
502
    public function stats()
503
    {
504
        return $this->executeCommand(array(
505
            'dbstats' => 1,
506
        ));
507
    }
508
509
    public function getLastError()
510
    {
511
        return $this->getMongoDB()->lastError();
512
    }
513
514
    public function getProfilerParams()
515
    {
516
        return $this->executeCommand(array(
517
            'profile'   => -1,
518
        ));
519
    }
520
521
    public function getProfilerLevel()
522
    {
523
        $params = $this->getProfilerParams();
524
        return $params['was'];
525
    }
526
527
    public function getProfilerSlowMs()
528
    {
529
        $params = $this->getProfilerParams();
530
        return $params['slowms'];
531
    }
532
533
    public function disableProfiler()
534
    {
535
        return $this->executeCommand(array(
536
            'profile'   => 0,
537
        ));
538
    }
539
540
    public function profileSlowQueries($slowms = 100)
541
    {
542
        return $this->executeCommand(array(
543
            'profile'   => 1,
544
            'slowms'    => (int) $slowms
545
        ));
546
    }
547
548
    public function profileAllQueries($slowms = null)
549
    {
550
        $command = array(
551
            'profile'   => 2,
552
        );
553
554
        if($slowms) {
555
            $command['slowms'] = (int) $slowms;
556
        }
557
558
        return $this->executeCommand($command);
559
    }
560
561
    /**
562
     *
563
     * @return \Sokil\Mongo\Cursor
564
     */
565
    public function findProfilerRows()
566
    {
567
        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...
568
            ->getCollection('system.profile')
569
            ->find()
570
            ->asArray();
571
    }
572
}
573