This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Wikibase\EntityStore\MongoDB; |
||
4 | |||
5 | use Ask\Language\Description\AnyValue; |
||
6 | use Ask\Language\Description\Conjunction; |
||
7 | use Ask\Language\Description\Description; |
||
8 | use Ask\Language\Description\Disjunction; |
||
9 | use Ask\Language\Description\SomeProperty; |
||
10 | use Ask\Language\Description\ValueDescription; |
||
11 | use Ask\Language\Option\QueryOptions; |
||
12 | use DataValues\DataValue; |
||
13 | use DataValues\StringValue; |
||
14 | use DataValues\TimeValue; |
||
15 | use Doctrine\MongoDB\Cursor; |
||
16 | use Doctrine\MongoDB\Database; |
||
17 | use Doctrine\MongoDB\Query\Expr; |
||
18 | use Iterator; |
||
19 | use MongoRegex; |
||
20 | use Wikibase\DataModel\Entity\EntityIdValue; |
||
21 | use Wikibase\DataModel\Entity\ItemId; |
||
22 | use Wikibase\DataModel\Entity\PropertyId; |
||
23 | use Wikibase\EntityStore\FeatureNotSupportedException; |
||
24 | use Wikibase\EntityStore\Internal\EntityIdForQueryLookup; |
||
25 | |||
26 | /** |
||
27 | * Internal class |
||
28 | * |
||
29 | * @licence GPLv2+ |
||
30 | * @author Thomas Pellissier Tanon |
||
31 | */ |
||
32 | class MongoDBEntityIdForQueryLookup implements EntityIdForQueryLookup { |
||
33 | |||
34 | /** |
||
35 | * @var Database |
||
36 | */ |
||
37 | private $database; |
||
38 | |||
39 | /** |
||
40 | * @var MongoDBDocumentBuilder |
||
41 | */ |
||
42 | private $documentBuilder; |
||
43 | |||
44 | /** |
||
45 | * @var int|null |
||
46 | */ |
||
47 | private $timeLimit; |
||
48 | |||
49 | /** |
||
50 | * @param Database $database |
||
51 | * @param MongoDBDocumentBuilder $documentBuilder |
||
52 | * @param int|null $timeLimit |
||
53 | */ |
||
54 | 16 | public function __construct( Database $database, MongoDBDocumentBuilder $documentBuilder, $timeLimit = null ) { |
|
55 | 16 | $this->database = $database; |
|
56 | 16 | $this->documentBuilder = $documentBuilder; |
|
57 | 16 | $this->timeLimit = $timeLimit; |
|
58 | 16 | } |
|
59 | |||
60 | /** |
||
61 | * @see EntityForQueryLookup::getEntityIdsForQuery |
||
62 | */ |
||
63 | 16 | public function getEntityIdsForQuery( Description $queryDescription, QueryOptions $queryOptions = null, $entityType ) { |
|
64 | 16 | return $this->formatResults( $this->doQuery( $queryDescription, $queryOptions, $entityType ) ); |
|
65 | } |
||
66 | |||
67 | 16 | private function doQuery( Description $queryDescription, QueryOptions $queryOptions = null, $entityType ) { |
|
68 | 16 | $cursor = $this->database |
|
69 | 16 | ->selectCollection( $entityType ) |
|
70 | 16 | ->find( |
|
71 | 16 | $this->buildQueryForDescription( $queryDescription, new Expr() )->getQuery(), |
|
72 | 9 | $this->buildQueryModifiers() |
|
73 | 9 | ); |
|
74 | |||
75 | 9 | if( $queryOptions === null ) { |
|
76 | 1 | return $cursor; |
|
77 | } |
||
78 | |||
79 | 8 | return $this->applyOptionsToCursor( $cursor, $queryOptions ); |
|
80 | } |
||
81 | |||
82 | 16 | private function buildQueryForDescription( Description $description, Expr $expr, PropertyId $currentProperty = null ) { |
|
83 | 16 | if( $description instanceof AnyValue ) { |
|
84 | 4 | return $expr; |
|
85 | 14 | } elseif( $description instanceof Conjunction ) { |
|
86 | 2 | return $this->buildQueryForConjunction( $description, $expr, $currentProperty ); |
|
87 | 14 | } elseif( $description instanceof Disjunction ) { |
|
88 | 2 | return $this->buildQueryForDisjunction( $description, $expr, $currentProperty ); |
|
89 | 14 | } elseif( $description instanceof SomeProperty ) { |
|
90 | 13 | return $this->buildQueryForSomeProperty( $description, $expr ); |
|
91 | 11 | } elseif( $description instanceof ValueDescription ) { |
|
92 | 10 | return $this->buildQueryForValueDescription( $description, $expr, $currentProperty ); |
|
93 | } else { |
||
94 | 1 | throw new FeatureNotSupportedException( 'Unknown description type: ' . $description->getType() ); |
|
95 | } |
||
96 | } |
||
97 | |||
98 | 2 | private function buildQueryForConjunction( Conjunction $conjunction, Expr $expr, PropertyId $currentProperty = null ) { |
|
99 | 2 | foreach( $conjunction->getDescriptions() as $description ) { |
|
100 | 2 | $expr->addAnd( $this->buildQueryForDescription( $description, new Expr(), $currentProperty ) ); |
|
101 | 2 | } |
|
102 | 2 | return $expr; |
|
103 | } |
||
104 | |||
105 | 2 | private function buildQueryForDisjunction( Disjunction $disjunction, Expr $expr, PropertyId $currentProperty = null ) { |
|
106 | 2 | foreach( $disjunction->getDescriptions() as $description ) { |
|
107 | 2 | $expr->addOr( $this->buildQueryForDescription( $description, new Expr(), $currentProperty ) ); |
|
108 | 2 | } |
|
109 | 2 | return $expr; |
|
110 | } |
||
111 | |||
112 | 13 | private function buildQueryForSomeProperty( SomeProperty $someProperty, Expr $expr ) { |
|
113 | 13 | if( $someProperty->isSubProperty() ) { |
|
114 | 1 | throw new FeatureNotSupportedException( 'Sub-properties are not supported yet' ); |
|
115 | } |
||
116 | |||
117 | 13 | $propertyIdValue = $someProperty->getPropertyId(); |
|
118 | 13 | if( !( $propertyIdValue instanceof EntityIdValue ) ) { |
|
119 | 1 | throw new FeatureNotSupportedException( 'PropertyId should be an EntityIdValue' ); |
|
120 | } |
||
121 | |||
122 | 12 | $propertyId = $propertyIdValue->getEntityId(); |
|
123 | 12 | if( !( $propertyId instanceof PropertyId ) ) { |
|
124 | 1 | throw new FeatureNotSupportedException( 'PropertyId should be a PropertyId' ); |
|
125 | } |
||
126 | |||
127 | 11 | return $this->buildQueryForDescription( $someProperty->getSubDescription(), $expr, $propertyId ); |
|
128 | } |
||
129 | |||
130 | 10 | private function buildQueryForValueDescription( |
|
131 | ValueDescription $valueDescription, |
||
132 | Expr $expr, |
||
133 | PropertyId $currentProperty = null |
||
134 | ) { |
||
135 | 10 | $value = $valueDescription->getValue(); |
|
136 | |||
137 | 10 | switch( $valueDescription->getComparator() ) { |
|
138 | 10 | case ValueDescription::COMP_EQUAL: |
|
139 | 10 | case ValueDescription::COMP_LIKE: |
|
140 | 9 | $expr->field( 'sclaims.' . $value->getType() )->equals( $this->buildPropertyValueForSearch( $currentProperty, $value ) ); |
|
0 ignored issues
–
show
|
|||
141 | 7 | return $expr; |
|
142 | |||
143 | 1 | default: |
|
144 | 1 | throw new FeatureNotSupportedException( 'Unsupported ValueDescription comparator' ); |
|
145 | 1 | } |
|
146 | } |
||
147 | |||
148 | 9 | private function buildPropertyValueForSearch( PropertyId $propertyId, DataValue $dataValue ) { |
|
149 | 9 | if( $dataValue instanceof EntityIdValue ) { |
|
150 | 5 | return $this->buildEntityIdValueForSearch( $propertyId, $dataValue ); |
|
151 | 7 | } elseif( $dataValue instanceof StringValue ) { |
|
152 | 4 | return $this->buildStringValueForSearch( $propertyId, $dataValue ); |
|
153 | 3 | } elseif( $dataValue instanceof TimeValue ) { |
|
154 | 2 | return $this->buildTimeValueForSearch( $propertyId, $dataValue ); |
|
155 | } else { |
||
156 | 1 | throw new FeatureNotSupportedException( 'Not supported DataValue type: ' . $dataValue->getType() ); |
|
157 | } |
||
158 | } |
||
159 | |||
160 | 5 | private function buildEntityIdValueForSearch( PropertyId $propertyId, EntityIdValue $entityIdValue ) { |
|
161 | 5 | $entityId = $entityIdValue->getEntityId(); |
|
162 | |||
163 | 5 | if( !( $entityId instanceof ItemId || $entityId instanceof PropertyId ) ) { |
|
164 | 1 | throw new FeatureNotSupportedException( 'Not supported entity type: ' . $entityId->getEntityType() ); |
|
165 | } |
||
166 | |||
167 | 4 | return $propertyId->getSerialization() . '-' . $entityIdValue->getEntityId()->getSerialization(); |
|
168 | } |
||
169 | |||
170 | 4 | private function buildStringValueForSearch( PropertyId $propertyId, StringValue $stringValue ) { |
|
171 | 4 | return $propertyId->getSerialization() . '-' . |
|
172 | 4 | $this->documentBuilder->buildSearchedStringValue( $stringValue->getValue() ); |
|
173 | } |
||
174 | |||
175 | 2 | private function buildTimeValueForSearch( PropertyId $propertyId, TimeValue $timeValue ) { |
|
176 | 2 | $significantTimePart = preg_replace( '/(-00)*T00:00:00Z$/', '', $timeValue->getTime() ); |
|
177 | |||
178 | 2 | return new MongoRegex( '/^' . preg_quote( $propertyId->getSerialization() . '-' . $significantTimePart, '/' ) . '/' ); |
|
179 | } |
||
180 | |||
181 | 9 | private function buildQueryModifiers() { |
|
182 | 9 | $modifiers = [ '_id' => 1 ]; |
|
183 | |||
184 | 9 | if( $this->timeLimit !== null ) { |
|
185 | 1 | $modifiers['$maxTimeMS'] = $this->timeLimit; |
|
186 | 1 | } |
|
187 | |||
188 | 9 | return $modifiers; |
|
189 | } |
||
190 | |||
191 | 8 | private function applyOptionsToCursor( Cursor $cursor, QueryOptions $options ) { |
|
192 | 8 | if( $this->timeLimit !== null ) { |
|
193 | 1 | $cursor->timeout( $this->timeLimit ); |
|
194 | 1 | } |
|
195 | |||
196 | return $cursor |
||
197 | 8 | ->skip( $options->getOffset() ) |
|
198 | 8 | ->limit( $options->getLimit() ); |
|
199 | } |
||
200 | |||
201 | 9 | private function formatResults( Iterator $cursor ) { |
|
202 | 9 | $entityIds = []; |
|
203 | |||
204 | 9 | foreach( $cursor as $document ) { |
|
205 | 9 | $entityIds[] = $this->documentBuilder->buildEntityIdForDocument( $document ); |
|
206 | 9 | } |
|
207 | |||
208 | 9 | return $entityIds; |
|
209 | } |
||
210 | } |
||
211 |
It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.
We recommend to add an additional type check (or disallow null for the parameter):