These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Doctrine\ODM\MongoDB\Aggregation\Stage; |
||
6 | |||
7 | use Doctrine\ODM\MongoDB\Aggregation\Builder; |
||
8 | use GeoJson\Geometry\Point; |
||
9 | use function is_array; |
||
10 | |||
11 | /** |
||
12 | * Fluent interface for adding a $geoNear stage to an aggregation pipeline. |
||
13 | */ |
||
14 | class GeoNear extends Match |
||
15 | { |
||
16 | /** @var string */ |
||
17 | private $distanceField; |
||
18 | |||
19 | /** @var float */ |
||
20 | private $distanceMultiplier; |
||
21 | |||
22 | /** @var string */ |
||
23 | private $includeLocs; |
||
24 | |||
25 | /** @var float */ |
||
26 | private $maxDistance; |
||
27 | |||
28 | /** @var float */ |
||
29 | private $minDistance; |
||
30 | |||
31 | /** @var array */ |
||
32 | private $near; |
||
33 | |||
34 | /** @var int */ |
||
35 | private $num; |
||
36 | |||
37 | /** @var bool */ |
||
38 | private $spherical = false; |
||
39 | |||
40 | /** @var bool */ |
||
41 | private $uniqueDocs; |
||
42 | |||
43 | /** |
||
44 | * @param float|array|Point $x |
||
45 | * @param float $y |
||
46 | */ |
||
47 | 11 | public function __construct(Builder $builder, $x, $y = null) |
|
48 | { |
||
49 | 11 | parent::__construct($builder); |
|
50 | |||
51 | 11 | $this->near($x, $y); |
|
52 | 11 | } |
|
53 | |||
54 | /** |
||
55 | * {@inheritdoc} |
||
56 | */ |
||
57 | 11 | public function getExpression() : array |
|
58 | { |
||
59 | $geoNear = [ |
||
60 | 11 | 'near' => $this->near, |
|
61 | 11 | 'spherical' => $this->spherical, |
|
62 | 11 | 'distanceField' => $this->distanceField, |
|
63 | 11 | 'query' => $this->query->getQuery(), |
|
64 | 11 | 'distanceMultiplier' => $this->distanceMultiplier, |
|
65 | 11 | 'includeLocs' => $this->includeLocs, |
|
66 | 11 | 'maxDistance' => $this->maxDistance, |
|
67 | 11 | 'minDistance' => $this->minDistance, |
|
68 | 11 | 'num' => $this->num, |
|
69 | 11 | 'uniqueDocs' => $this->uniqueDocs, |
|
70 | ]; |
||
71 | |||
72 | 11 | foreach (['distanceMultiplier', 'includeLocs', 'maxDistance', 'minDistance', 'num', 'uniqueDocs'] as $option) { |
|
73 | 11 | if ($geoNear[$option]) { |
|
74 | 8 | continue; |
|
75 | } |
||
76 | |||
77 | 11 | unset($geoNear[$option]); |
|
78 | } |
||
79 | |||
80 | 11 | return ['$geoNear' => $geoNear]; |
|
81 | } |
||
82 | |||
83 | /** |
||
84 | * The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. |
||
85 | */ |
||
86 | 3 | public function distanceField(string $distanceField) : self |
|
87 | { |
||
88 | 3 | $this->distanceField = $distanceField; |
|
89 | |||
90 | 3 | return $this; |
|
91 | } |
||
92 | |||
93 | /** |
||
94 | * The factor to multiply all distances returned by the query. |
||
95 | */ |
||
96 | 1 | public function distanceMultiplier(float $distanceMultiplier) : self |
|
97 | { |
||
98 | 1 | $this->distanceMultiplier = $distanceMultiplier; |
|
99 | |||
100 | 1 | return $this; |
|
101 | } |
||
102 | |||
103 | /** |
||
104 | * This specifies the output field that identifies the location used to calculate the distance. |
||
105 | */ |
||
106 | 1 | public function includeLocs(string $includeLocs) : self |
|
107 | { |
||
108 | 1 | $this->includeLocs = $includeLocs; |
|
109 | |||
110 | 1 | return $this; |
|
111 | } |
||
112 | |||
113 | /** |
||
114 | * The maximum number of documents to return. |
||
115 | * |
||
116 | * @return $this |
||
117 | */ |
||
118 | 2 | public function limit(int $limit) |
|
119 | { |
||
120 | 2 | return $this->num($limit); |
|
0 ignored issues
–
show
|
|||
121 | } |
||
122 | |||
123 | /** |
||
124 | * The maximum distance from the center point that the documents can be. |
||
125 | * |
||
126 | * @return $this |
||
127 | */ |
||
128 | 1 | public function maxDistance(float $maxDistance) |
|
129 | { |
||
130 | 1 | $this->maxDistance = $maxDistance; |
|
131 | |||
132 | 1 | return $this; |
|
133 | } |
||
134 | |||
135 | /** |
||
136 | * The minimum distance from the center point that the documents can be. |
||
137 | * |
||
138 | * @return $this |
||
139 | */ |
||
140 | 1 | public function minDistance(float $minDistance) |
|
141 | { |
||
142 | 1 | $this->minDistance = $minDistance; |
|
143 | |||
144 | 1 | return $this; |
|
145 | } |
||
146 | |||
147 | /** |
||
148 | * The point for which to find the closest documents. |
||
149 | * |
||
150 | * A GeoJSON point may be provided as the first and only argument for |
||
151 | * 2dsphere queries. This single parameter may be a GeoJSON point object or |
||
152 | * an array corresponding to the point's JSON representation. If GeoJSON is |
||
153 | * used, the "spherical" option will default to true. |
||
154 | * |
||
155 | * @param float|array|Point $x |
||
156 | * @param float $y |
||
157 | * |
||
158 | * @return $this |
||
159 | */ |
||
160 | 11 | public function near($x, $y = null) : self |
|
161 | { |
||
162 | 11 | if ($x instanceof Point) { |
|
163 | $x = $x->jsonSerialize(); |
||
164 | } |
||
165 | |||
166 | 11 | $this->near = is_array($x) ? $x : [$x, $y]; |
|
167 | 11 | $this->spherical = is_array($x) && isset($x['type']); |
|
168 | |||
169 | 11 | return $this; |
|
170 | } |
||
171 | |||
172 | /** |
||
173 | * The maximum number of documents to return. |
||
174 | * |
||
175 | * @return $this |
||
176 | */ |
||
177 | 3 | public function num(int $num) : self |
|
178 | { |
||
179 | 3 | $this->num = $num; |
|
180 | |||
181 | 3 | return $this; |
|
182 | } |
||
183 | |||
184 | /** |
||
185 | * Required if using a 2dsphere index. Determines how MongoDB calculates the distance. |
||
186 | */ |
||
187 | public function spherical(bool $spherical = true) : self |
||
188 | { |
||
189 | $this->spherical = $spherical; |
||
190 | |||
191 | return $this; |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * If this value is true, the query returns a matching document once, even if more than one of the document’s location fields match the query. |
||
196 | * |
||
197 | * @return $this |
||
198 | */ |
||
199 | 1 | public function uniqueDocs(bool $uniqueDocs = true) : self |
|
200 | { |
||
201 | 1 | $this->uniqueDocs = $uniqueDocs; |
|
202 | |||
203 | 1 | return $this; |
|
204 | } |
||
205 | } |
||
206 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.