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 ( 290193...d482c6 )
by De
04:24
created

Expression::whereText()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 26
rs 8.5806
c 2
b 0
f 0
cc 4
eloc 14
nc 8
nop 4
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\Structure\Arrayable;
15
use GeoJson\Geometry\Geometry;
16
use GeoJson\Geometry\Point;
17
18
/**
19
 * This class represents all expressions used to query document from collection
20
 *
21
 * @link http://docs.mongodb.org/manual/reference/operator/query/
22
 * @author Dmytro Sokil <[email protected]>
23
 */
24
class Expression implements Arrayable
25
{
26
    protected $_expression = array();
27
28
    /**
29
     * Create new instance of expression
30
     * @return \Sokil\Mongo\Expression
31
     */
32
    public function expression()
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
33
    {
34
        return new self;
35
    }
36
    /**
37
     * Return a expression
38
     * @return \Sokil\Mongo\Cursor|\Sokil\Mongo\Expression
39
     */
40
    public function where($field, $value)
41
    {
42
        if(!isset($this->_expression[$field]) || !is_array($value) || !is_array($this->_expression[$field])) {
43
            $this->_expression[$field] = $value;
44
        }
45
        else {
46
            $this->_expression[$field] = array_merge_recursive($this->_expression[$field], $value);
47
        }
48
49
        return $this;
50
    }
51
52 View Code Duplication
    public function whereEmpty($field)
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...
53
    {
54
        return $this->where('$or', array(
55
            array($field => null),
56
            array($field => ''),
57
            array($field => array()),
58
            array($field => array('$exists' => false))
59
        ));
60
    }
61
62 View Code Duplication
    public function whereNotEmpty($field)
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...
63
    {
64
        return $this->where('$nor', array(
65
            array($field => null),
66
            array($field => ''),
67
            array($field => array()),
68
            array($field => array('$exists' => false))
69
        ));
70
    }
71
72
    public function whereGreater($field, $value)
73
    {
74
        return $this->where($field, array('$gt' => $value));
75
    }
76
77
    public function whereGreaterOrEqual($field, $value)
78
    {
79
        return $this->where($field, array('$gte' => $value));
80
    }
81
82
    public function whereLess($field, $value)
83
    {
84
        return $this->where($field, array('$lt' => $value));
85
    }
86
87
    public function whereLessOrEqual($field, $value)
88
    {
89
        return $this->where($field, array('$lte' => $value));
90
    }
91
92
    public function whereNotEqual($field, $value)
93
    {
94
        return $this->where($field, array('$ne' => $value));
95
    }
96
97
    /**
98
     * Selects the documents where the value of a
99
     * field equals any value in the specified array.
100
     *
101
     * @param string $field
102
     * @param array $values
103
     * @return \Sokil\Mongo\Expression
104
     */
105
    public function whereIn($field, array $values)
106
    {
107
        return $this->where($field, array('$in' => $values));
108
    }
109
110
    public function whereNotIn($field, array $values)
111
    {
112
        return $this->where($field, array('$nin' => $values));
113
    }
114
115
    public function whereExists($field)
116
    {
117
        return $this->where($field, array('$exists' => true));
118
    }
119
120
    public function whereNotExists($field)
121
    {
122
        return $this->where($field, array('$exists' => false));
123
    }
124
125
    public function whereHasType($field, $type)
126
    {
127
        return $this->where($field, array('$type' => (int) $type));
128
    }
129
130
    public function whereDouble($field)
131
    {
132
        return $this->whereHasType($field, Document::FIELD_TYPE_DOUBLE);
133
    }
134
135
    public function whereString($field)
136
    {
137
        return $this->whereHasType($field, Document::FIELD_TYPE_STRING);
138
    }
139
140
    public function whereObject($field)
141
    {
142
        return $this->whereHasType($field, Document::FIELD_TYPE_OBJECT);
143
    }
144
145
    public function whereBoolean($field)
146
    {
147
        return $this->whereHasType($field, Document::FIELD_TYPE_BOOLEAN);
148
    }
149
150
    public function whereArray($field)
151
    {
152
        return $this->whereJsCondition('Array.isArray(this.' . $field . ')');
153
    }
154
155
    public function whereArrayOfArrays($field)
156
    {
157
        return $this->whereHasType($field, Document::FIELD_TYPE_ARRAY);
158
    }
159
160
    public function whereObjectId($field)
161
    {
162
        return $this->whereHasType($field, Document::FIELD_TYPE_OBJECT_ID);
163
    }
164
165
    public function whereDate($field)
166
    {
167
        return $this->whereHasType($field, Document::FIELD_TYPE_DATE);
168
    }
169
170
    public function whereNull($field)
171
    {
172
        return $this->whereHasType($field, Document::FIELD_TYPE_NULL);
173
    }
174
175
    public function whereJsCondition($condition)
176
    {
177
        return $this->where('$where', $condition);
178
    }
179
180
    public function whereLike($field, $regex, $caseInsensitive = true)
181
    {
182
        // regex
183
        $expression = array(
184
            '$regex'    => $regex,
185
        );
186
187
        // options
188
        $options = '';
189
190
        if($caseInsensitive) {
191
            $options .= 'i';
192
        }
193
194
        $expression['$options'] = $options;
195
196
        // query
197
        return $this->where($field, $expression);
198
    }
199
200
    /**
201
     * Find documents where the value of a field is an array
202
     * that contains all the specified elements.
203
     * This is equivalent of logical AND.
204
     *
205
     * @link http://docs.mongodb.org/manual/reference/operator/query/all/
206
     *
207
     * @param string $field point-delimited field name
208
     * @param array $values
209
     * @return \Sokil\Mongo\Expression
210
     */
211
    public function whereAll($field, array $values)
212
    {
213
        return $this->where($field, array('$all' => $values));
214
    }
215
216
    /**
217
     * Find documents where the value of a field is an array
218
     * that contains none of the specified elements.
219
     * This is equivalent of logical AND.
220
     *
221
     * @link http://docs.mongodb.org/manual/reference/operator/query/all/
222
     *
223
     * @param string $field point-delimited field name
224
     * @param array $values
225
     * @return \Sokil\Mongo\Expression
226
     */
227
    public function whereNoneOf($field, array $values)
228
    {
229
        return $this->where($field, array(
230
            '$not' => array(
231
                '$all' => $values
232
            ),
233
        ));
234
    }
235
236
    /**
237
     * Find documents where the value of a field is an array
238
     * that contains any of the specified elements.
239
     * This is equivalent of logical AND.
240
     *
241
     * @param string $field point-delimited field name
242
     * @param array $values
243
     * @return \Sokil\Mongo\Expression
244
     */
245
    public function whereAny($field, array $values)
246
    {
247
        return $this->whereIn($field, $values);
248
    }
249
250
    /**
251
     * Matches documents in a collection that contain an array field with at
252
     * least one element that matches all the specified query criteria.
253
     *
254
     * @param string $field point-delimited field name
255
     * @param \Sokil\Mongo\Expression|callable|array $expression
256
     * @return \Sokil\Mongo\Expression
257
     */
258 View Code Duplication
    public function whereElemMatch($field, $expression)
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...
259
    {
260
        if(is_callable($expression)) {
261
            $expression = call_user_func($expression, $this->expression());
262
        }
263
264
        if($expression instanceof Expression) {
265
            $expression = $expression->toArray();
266
        } elseif(!is_array($expression)) {
267
            throw new Exception('Wrong expression passed');
268
        }
269
270
        return $this->where($field, array('$elemMatch' => $expression));
271
    }
272
273
    /**
274
     * Matches documents in a collection that contain an array field with elements
275
     * that do not matches all the specified query criteria.
276
     *
277
     * @param type $field
278
     * @param \Sokil\Mongo\Expression|callable|array $expression
279
     * @return \Sokil\Mongo\Expression
280
     */
281
    public function whereElemNotMatch($field, $expression)
282
    {
283
        return $this->whereNot($this->expression()->whereElemMatch($field, $expression));
284
    }
285
286
    /**
287
     * Selects documents if the array field is a specified size.
288
     *
289
     * @param string $field
290
     * @param integer $length
291
     * @return \Sokil\Mongo\Expression
292
     */
293
    public function whereArraySize($field, $length)
294
    {
295
        return $this->where($field, array('$size' => (int) $length));
296
    }
297
298
    /**
299
     * Selects the documents that satisfy at least one of the expressions
300
     *
301
     * @param array|\Sokil\Mongo\Expression $expressions Array of Expression instances or comma delimited expression list
302
     * @return \Sokil\Mongo\Expression
303
     */
304 View Code Duplication
    public function whereOr($expressions = null /**, ...**/)
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...
305
    {
306
        if($expressions instanceof Expression) {
307
            $expressions = func_get_args();
308
        }
309
310
        return $this->where('$or', array_map(function(Expression $expression) {
311
            return $expression->toArray();
312
        }, $expressions));
313
    }
314
315
    /**
316
     * Select the documents that satisfy all the expressions in the array
317
     *
318
     * @param array|\Sokil\Mongo\Expression $expressions Array of Expression instances or comma delimited expression list
319
     * @return \Sokil\Mongo\Expression
320
     */
321 View Code Duplication
    public function whereAnd($expressions = null /**, ...**/)
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...
322
    {
323
        if($expressions instanceof Expression) {
324
            $expressions = func_get_args();
325
        }
326
327
        return $this->where('$and', array_map(function(Expression $expression) {
328
            return $expression->toArray();
329
        }, $expressions));
330
    }
331
332
    /**
333
     * Selects the documents that fail all the query expressions in the array
334
     *
335
     * @param array|\Sokil\Mongo\Expression $expressions Array of Expression instances or comma delimited expression list
336
     * @return \Sokil\Mongo\Expression
337
     */
338 View Code Duplication
    public function whereNor($expressions = null /**, ...**/)
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...
339
    {
340
        if($expressions instanceof Expression) {
341
            $expressions = func_get_args();
342
        }
343
344
        return $this->where('$nor', array_map(function(Expression $expression) {
345
            return $expression->toArray();
346
        }, $expressions));
347
    }
348
349
    public function whereNot(Expression $expression)
350
    {
351
        foreach($expression->toArray() as $field => $value) {
352
            // $not acceptable only for operators-expressions
353
            if(is_array($value) && is_string(key($value))) {
354
                $this->where($field, array('$not' => $value));
355
            }
356
            // for single values use $ne
357
            else {
358
                $this->whereNotEqual($field, $value);
359
            }
360
        }
361
362
        return $this;
363
    }
364
365
    /**
366
     * Select documents where the value of a field divided by a divisor has the specified remainder (i.e. perform a modulo operation to select documents)
367
     *
368
     * @param string $field
369
     * @param int $divisor
370
     * @param int $remainder
371
     */
372
    public function whereMod($field, $divisor, $remainder)
373
    {
374
        $this->where($field, array(
375
            '$mod' => array((int) $divisor, (int) $remainder),
376
        ));
377
378
        return $this;
379
    }
380
381
    /**
382
     * Perform fulltext search
383
     *
384
     * @link https://docs.mongodb.org/manual/reference/operator/query/text/
385
     * @link https://docs.mongodb.org/manual/tutorial/specify-language-for-text-index/
386
     *
387
     * If a collection contains documents or embedded documents that are in different languages,
388
     * include a field named language in the documents or embedded documents and specify as its value the language
389
     * for that document or embedded document.
390
     *
391
     * The specified language in the document overrides the default language for the text index.
392
     * The specified language in an embedded document override the language specified in an enclosing document or
393
     * the default language for the index.
394
     *
395
     * Case Insensitivity:
396
     * @link https://docs.mongodb.org/manual/reference/operator/query/text/#text-operator-case-sensitivity
397
     *
398
     * Diacritic Insensitivity:
399
     * @link https://docs.mongodb.org/manual/reference/operator/query/text/#text-operator-diacritic-sensitivity
400
     *
401
     * @param $search A string of terms that MongoDB parses and uses to query the text index. MongoDB performs a
402
     *  logical OR search of the terms unless specified as a phrase.
403
     * @param $language Optional. The language that determines the list of stop words for the search and the
404
     *  rules for the stemmer and tokenizer. If not specified, the search uses the default language of the index.
405
     *  If you specify a language value of "none", then the text search uses simple tokenization
406
     *  with no list of stop words and no stemming.
407
     * @param bool|false $caseSensitive Allowed from v.3.2 A boolean flag to enable or disable case
408
     *  sensitive search. Defaults to false; i.e. the search defers to the case insensitivity of the text index.
409
     * @param bool|false $diacriticSensitive Allowed from v.3.2 A boolean flag to enable or disable diacritic
410
     *  sensitive search against version 3 text indexes. Defaults to false; i.e. the search defers to the diacritic
411
     *  insensitivity of the text index. Text searches against earlier versions of the text index are inherently
412
     *  diacritic sensitive and cannot be diacritic insensitive. As such, the $diacriticSensitive option has no
413
     *  effect with earlier versions of the text index.
414
     * @return $this
415
     */
416
    public function whereText(
417
        $search,
418
        $language = null,
419
        $caseSensitive = null,
420
        $diacriticSensitive = null
421
    ) {
422
        $this->_expression['$text'] = array(
423
            '$search' => $search,
424
        );
425
426
        if ($language) {
427
            $this->_expression['$text']['$language'] = $language;
428
        }
429
430
        // Version 3.2 feature
431
        if ($caseSensitive) {
432
            $this->_expression['$text']['$caseSensitive'] = (bool) $caseSensitive;
433
        }
434
435
        // Version 3.2 feature
436
        if ($diacriticSensitive) {
437
            $this->_expression['$text']['$diacriticSensitive'] = (bool) $diacriticSensitive;
438
        }
439
440
        return $this;
441
    }
442
443
    /**
444
     * Find document near points in flat surface
445
     *
446
     * @param string $field
447
     * @param float $longitude
448
     * @param float $latitude
449
     * @param int|array $distance distance from point in meters. Array distance
450
     *  allowed only in MongoDB 2.6
451
     * @return \Sokil\Mongo\Expression
452
     */
453 View Code Duplication
    public function nearPoint($field, $longitude, $latitude, $distance)
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...
454
    {
455
        $point = new \GeoJson\Geometry\Point(array(
456
            (float) $longitude,
457
            (float) $latitude
458
        ));
459
460
        $near = array(
461
            '$geometry' => $point->jsonSerialize(),
462
        );
463
464
        if(is_array($distance)) {
465
            if(!empty($distance[0])) {
466
                $near['$minDistance'] = (int) $distance[0];
467
            }
468
            if(!empty($distance[1])) {
469
                $near['$maxDistance'] = (int) $distance[1];
470
            }
471
        } else {
472
            $near['$maxDistance'] = (int) $distance;
473
        }
474
475
        $this->where($field, array('$near' => $near));
476
477
        return $this;
478
    }
479
480
    /**
481
     * Find document near points in spherical surface
482
     *
483
     * @param string $field
484
     * @param float $longitude
485
     * @param float $latitude
486
     * @param int|array $distance distance from point in meters. Array distance
487
     *  allowed only in MongoDB 2.6
488
     * @return \Sokil\Mongo\Expression
489
     */
490 View Code Duplication
    public function nearPointSpherical($field, $longitude, $latitude, $distance)
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...
491
    {
492
        $point = new Point(array(
493
            (float) $longitude,
494
            (float) $latitude
495
        ));
496
497
        $near = array(
498
            '$geometry' => $point->jsonSerialize(),
499
        );
500
501
        if(is_array($distance)) {
502
            if(!empty($distance[0])) {
503
                $near['$minDistance'] = (int) $distance[0];
504
            }
505
            if(!empty($distance[1])) {
506
                $near['$maxDistance'] = (int) $distance[1];
507
            }
508
        } else {
509
            $near['$maxDistance'] = (int) $distance;
510
        }
511
512
        $this->where($field, array('$nearSphere' => $near));
513
514
        return $this;
515
    }
516
517
    /**
518
     * Selects documents whose geospatial data intersects with a specified
519
     * GeoJSON object; i.e. where the intersection of the data and the
520
     * specified object is non-empty. This includes cases where the data
521
     * and the specified object share an edge. Uses spherical geometry.
522
     *
523
     * @link http://docs.mongodb.org/manual/reference/operator/query/geoIntersects/
524
     *
525
     * @param string $field
526
     * @param Geometry $geometry
527
     * @return \Sokil\Mongo\Expression
528
     */
529
    public function intersects($field, Geometry $geometry)
530
    {
531
        $this->where($field, array(
532
            '$geoIntersects' => array(
533
                '$geometry' => $geometry->jsonSerialize(),
534
            ),
535
        ));
536
537
        return $this;
538
    }
539
540
    /**
541
     * Selects documents with geospatial data that exists entirely within a specified shape.
542
     *
543
     * @link http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
544
     * @param string $field
545
     * @param Geometry $geometry
546
     * @return \Sokil\Mongo\Expression
547
     */
548
    public function within($field, Geometry $geometry)
549
    {
550
        $this->where($field, array(
551
            '$geoWithin' => array(
552
                '$geometry' => $geometry->jsonSerialize(),
553
            ),
554
        ));
555
556
        return $this;
557
    }
558
559
    /**
560
     * Select documents with geospatial data within circle defined
561
     * by center point and radius in flat surface
562
     *
563
     * @param string $field
564
     * @param float $longitude
565
     * @param float $latitude
566
     * @param float $radius
567
     * @return \Sokil\Mongo\Expression
568
     */
569
    public function withinCircle($field, $longitude, $latitude, $radius)
570
    {
571
        $this->where($field, array(
572
            '$geoWithin' => array(
573
                '$center' => array(
574
                    array($longitude, $latitude),
575
                    $radius,
576
                ),
577
            ),
578
        ));
579
580
        return $this;
581
    }
582
583
    /**
584
     * Select documents with geospatial data within circle defined
585
     * by center point and radius in spherical surface
586
     *
587
     * To calculate distance in radians
588
     * @see http://docs.mongodb.org/manual/tutorial/calculate-distances-using-spherical-geometry-with-2d-geospatial-indexes/
589
     *
590
     * @param string $field
591
     * @param float $longitude
592
     * @param float $latitude
593
     * @param float $radiusInRadians in radians.
594
     * @return \Sokil\Mongo\Expression
595
     */
596
    public function withinCircleSpherical($field, $longitude, $latitude, $radiusInRadians)
597
    {
598
        $this->where($field, array(
599
            '$geoWithin' => array(
600
                '$centerSphere' => array(
601
                    array($longitude, $latitude),
602
                    $radiusInRadians,
603
                ),
604
            ),
605
        ));
606
607
        return $this;
608
    }
609
610
    /**
611
     * Return documents that are within the bounds of the rectangle, according
612
     * to their point-based location data.
613
     *
614
     * Based on grid coordinates and does not query for GeoJSON shapes.
615
     *
616
     * Use planar geometry, so 2d index may be used but not required
617
     *
618
     * @param string $field
619
     * @param array $bottomLeftCoordinate Bottom left coordinate of box
620
     * @param array $upperRightCoordinate Upper right coordinate of box
621
     * @return \Sokil\Mongo\Expression
622
     */
623
    public function withinBox($field, array $bottomLeftCoordinate, array $upperRightCoordinate)
624
    {
625
        $this->where($field, array(
626
            '$geoWithin' => array(
627
                '$box' => array(
628
                    $bottomLeftCoordinate,
629
                    $upperRightCoordinate,
630
                ),
631
            ),
632
        ));
633
634
        return $this;
635
    }
636
637
    /**
638
     * Return documents that are within the polygon, according
639
     * to their point-based location data.
640
     *
641
     * Based on grid coordinates and does not query for GeoJSON shapes.
642
     *
643
     * Use planar geometry, so 2d index may be used but not required
644
     *
645
     * @param string $field
646
     * @param array $points array of coordinates
647
     * @return \Sokil\Mongo\Expression
648
     */
649
    public function withinPolygon($field, array $points)
650
    {
651
        $this->where($field, array(
652
            '$geoWithin' => array(
653
                '$polygon' => $points,
654
            ),
655
        ));
656
657
        return $this;
658
    }
659
660
    public function toArray()
661
    {
662
        return $this->_expression;
663
    }
664
665
    public function merge(Expression $expression)
666
    {
667
        $this->_expression = array_merge_recursive($this->_expression, $expression->toArray());
668
        return $this;
669
    }
670
671
    /**
672
     * Transform extression in different formats to canonical array form
673
     *
674
     * @param mixed $mixed
675
     * @return array
676
     * @throws \Sokil\Mongo\Exception
677
     */
678 View Code Duplication
    public static function convertToArray($mixed)
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...
679
    {
680
        // get expression from callable
681
        if(is_callable($mixed)) {
682
            $callable = $mixed;
683
            $mixed = new self();
684
            call_user_func($callable, $mixed);
685
        }
686
687
        // get expression array
688
        if($mixed instanceof Arrayable && $mixed instanceof self) {
689
            $mixed = $mixed->toArray();
690
        } elseif(!is_array($mixed)) {
691
            throw new Exception('Mixed must be instance of Expression');
692
        }
693
694
        return $mixed;
695
    }
696
}
697