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 | * File was created 29.02.2016 17:08 |
||
4 | */ |
||
5 | |||
6 | namespace PeekAndPoke\Component\Slumber\Data\MongoDb; |
||
7 | |||
8 | use MongoDB\Collection; |
||
9 | use MongoDB\Driver\Exception; |
||
10 | use MongoDB\Model\IndexInfo; |
||
11 | use PeekAndPoke\Component\Psi\Psi; |
||
12 | use PeekAndPoke\Component\Slumber\Annotation\CompoundIndexDefinition; |
||
13 | use PeekAndPoke\Component\Slumber\Annotation\IndexDefinition; |
||
14 | use PeekAndPoke\Component\Slumber\Annotation\PropertyStorageIndexMarker; |
||
15 | use PeekAndPoke\Component\Slumber\Annotation\Slumber\AsObject; |
||
16 | use PeekAndPoke\Component\Slumber\Annotation\Slumber\Store\AsDbReference; |
||
17 | use PeekAndPoke\Component\Slumber\Core\LookUp\PropertyMarkedForSlumber; |
||
18 | use PeekAndPoke\Component\Slumber\Data\LookUp\PropertyMarkedForIndexing; |
||
19 | use Psr\Log\LoggerInterface; |
||
20 | |||
21 | /** |
||
22 | * @author Karsten J. Gerber <[email protected]> |
||
23 | */ |
||
24 | class MongoDbIndexer |
||
25 | { |
||
26 | /** @var MongoDbEntityConfigReader */ |
||
27 | private $lookUp; |
||
28 | /** @var LoggerInterface */ |
||
29 | private $logger; |
||
30 | |||
31 | /** |
||
32 | * MongoDbIndexer constructor. |
||
33 | * |
||
34 | * @param MongoDbEntityConfigReader $lookUp |
||
35 | * @param LoggerInterface $logger |
||
36 | */ |
||
37 | public function __construct(MongoDbEntityConfigReader $lookUp, LoggerInterface $logger) |
||
38 | { |
||
39 | $this->lookUp = $lookUp; |
||
40 | $this->logger = $logger; |
||
41 | } |
||
42 | |||
43 | /** |
||
44 | * @param Collection $collection |
||
45 | * @param \ReflectionClass $class |
||
46 | * |
||
47 | * @return array |
||
48 | */ |
||
49 | public function ensureIndexes(Collection $collection, \ReflectionClass $class) |
||
50 | { |
||
51 | $createdIndexes = $this->ensureIndexesRecursive([], $class, $collection); |
||
52 | |||
53 | // delete all indexes that are no longer needed |
||
54 | $indexInfos = $collection->listIndexes(); |
||
55 | $deletedIndexes = []; |
||
56 | |||
57 | /** @var IndexInfo $indexInfo */ |
||
58 | foreach ($indexInfos as $indexInfo) { |
||
59 | |||
60 | $indexInfoName = $indexInfo->getName(); |
||
61 | |||
62 | if ($indexInfoName !== '_id_' && ! \in_array($indexInfoName, $createdIndexes, true)) { |
||
63 | $collection->dropIndex($indexInfoName); |
||
64 | $deletedIndexes[] = $indexInfoName; |
||
65 | } |
||
66 | } |
||
67 | |||
68 | $this->logger->debug( |
||
69 | 'Creating indexes for repository ' . $collection->getCollectionName() . ' - ' . |
||
70 | 'Ensured indexes: ' . implode(', ', $createdIndexes) . ' - ' . |
||
71 | 'Deleted indexes: ' . implode(', ', $deletedIndexes) |
||
72 | ); |
||
73 | |||
74 | return Psi::it($collection->listIndexes())->toArray(); |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * @param string[] $prefixes |
||
79 | * @param \ReflectionClass $entity |
||
80 | * @param Collection $collection |
||
81 | * |
||
82 | * @return array |
||
83 | */ |
||
84 | private function ensureIndexesRecursive($prefixes, \ReflectionClass $entity, Collection $collection) |
||
85 | { |
||
86 | $entityConfig = $this->lookUp->getEntityConfig($entity); |
||
87 | |||
88 | $createdIndexes = array_merge( |
||
89 | $this->createCompoundIndexes($prefixes, $collection, $entityConfig->getCompoundIndexes()), |
||
90 | $this->createPropertyIndexes($prefixes, $collection, $entityConfig->getIndexedProperties()) |
||
91 | ); |
||
92 | |||
93 | // also index child objects |
||
94 | Psi::it($entityConfig->getMarkedProperties()) |
||
95 | ->filter(new Psi\IsInstanceOf(PropertyMarkedForSlumber::class)) |
||
96 | // we also look into child objects |
||
97 | ->filter(function (PropertyMarkedForSlumber $p) { |
||
98 | return $p->getFirstMarkerOf(AsObject::class) !== null; |
||
99 | }) |
||
100 | // but NOT if they are db-references |
||
101 | ->filter(function (PropertyMarkedForSlumber $p) { |
||
102 | return $p->getFirstMarkerOf(AsDbReference::class) === null; |
||
103 | }) |
||
104 | ->each(function (PropertyMarkedForSlumber $p) use ($prefixes, $collection, &$createdIndexes) { |
||
105 | /** @var AsObject $asObject */ |
||
106 | $asObject = $p->getFirstMarkerOf(AsObject::class); |
||
107 | |||
108 | /** @noinspection NullPointerExceptionInspection */ |
||
109 | $subCreated = $this->ensureIndexesRecursive( |
||
110 | array_merge($prefixes, [$p->alias]), |
||
111 | new \ReflectionClass($asObject->value), |
||
112 | $collection |
||
113 | ); |
||
114 | |||
115 | $createdIndexes = array_merge($createdIndexes, $subCreated); |
||
116 | })->toArray(); |
||
117 | |||
118 | return $createdIndexes; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * @param string[] $prefixes |
||
123 | * @param Collection $collection |
||
124 | * @param CompoundIndexDefinition[] $compoundIndexes |
||
125 | * |
||
126 | * @return string[] The names of all indexes that where created |
||
127 | */ |
||
128 | private function createCompoundIndexes($prefixes, Collection $collection, $compoundIndexes) |
||
129 | { |
||
130 | $createdIndexes = []; |
||
131 | |||
132 | foreach ($compoundIndexes as $compoundIndex) { |
||
133 | |||
134 | $definition = []; |
||
135 | // append the prefixes to all fields |
||
136 | foreach ($compoundIndex->getDefinition() as $k => $v) { |
||
137 | $definition[$this->buildFieldName($prefixes, $k)] = $v; |
||
138 | } |
||
139 | |||
140 | $name = $this->buildCompoundIndexName($prefixes, $definition); |
||
141 | $options = $this->assembleOptions($name, $compoundIndex); |
||
142 | |||
143 | $createdIndexes[] = $this->createIndex($collection, $definition, $options); |
||
144 | } |
||
145 | |||
146 | return $createdIndexes; |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * @param string[] $prefixes |
||
151 | * @param Collection $collection |
||
152 | * @param PropertyMarkedForIndexing[] $indexedProperties |
||
153 | * |
||
154 | * @return string[] The names of all indexes that where created |
||
155 | */ |
||
156 | private function createPropertyIndexes($prefixes, Collection $collection, $indexedProperties) |
||
157 | { |
||
158 | $createdIndexes = []; |
||
159 | |||
160 | foreach ($indexedProperties as $indexedProperty) { |
||
161 | |||
162 | foreach ($indexedProperty->markers as $marker) { |
||
163 | |||
164 | $definition = [ |
||
165 | // append the prefixes to the field |
||
166 | $this->buildFieldName($prefixes, $indexedProperty->propertyName) => $this->mapDirection($marker), |
||
167 | ]; |
||
168 | $name = $this->buildPropertyIndexName($prefixes, $indexedProperty->propertyName, $marker); |
||
169 | $options = $this->assembleOptions($name, $marker); |
||
170 | |||
171 | $createdIndexes[] = $this->createIndex($collection, $definition, $options); |
||
172 | } |
||
173 | } |
||
174 | |||
175 | return $createdIndexes; |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * @param Collection $collection |
||
180 | * @param array $fields |
||
181 | * @param array $options |
||
182 | * |
||
183 | * @return string The resulting index names |
||
184 | */ |
||
185 | private function createIndex(Collection $collection, array $fields, array $options) |
||
186 | { |
||
187 | $debugInfo = 'collection "' . $collection->getCollectionName() . '" for fields: ' . json_encode($fields) . ' - Options: ' . json_encode($options); |
||
188 | |||
189 | try { |
||
190 | $collection->createIndex($fields, $options); |
||
191 | } catch (Exception\RuntimeException $e) { |
||
0 ignored issues
–
show
|
|||
192 | |||
193 | // Do we have a duplicate key problem? |
||
194 | if ($e->getCode() === 11000 || strpos($e->getMessage(), 'E11000') !== false) { |
||
195 | throw new \RuntimeException('Duplicate key problems on ' . $debugInfo, 0, $e); |
||
196 | } |
||
197 | |||
198 | // Have the options changes? So we try to drop the index and then create it again |
||
199 | if ($e->getCode() === 85 || strpos($e->getMessage(), 'already exists with different options') === false) { |
||
200 | // drop index by name |
||
201 | $collection->dropIndex($options['name']); |
||
202 | |||
203 | // and try the creation again |
||
204 | try { |
||
205 | $collection->createIndex($fields, $options); |
||
206 | } catch (Exception\RuntimeException $e) { |
||
0 ignored issues
–
show
The class
MongoDB\Driver\Exception\RuntimeException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
207 | throw new \RuntimeException('Cannot create index - even after dropping it - on ' . $debugInfo, 0, $e); |
||
208 | } |
||
209 | } |
||
210 | |||
211 | // something else has happened |
||
212 | throw new \RuntimeException('Unknown problem on ' . $debugInfo, 0, $e); |
||
213 | } |
||
214 | |||
215 | return $options['name']; |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * @param string $indexName |
||
220 | * @param IndexDefinition $marker |
||
221 | * |
||
222 | * @return array |
||
223 | */ |
||
224 | private function assembleOptions($indexName, IndexDefinition $marker) |
||
225 | { |
||
226 | $options = [ |
||
227 | 'name' => (string) $indexName, |
||
228 | 'background' => (bool) $marker->isBackground(), |
||
229 | 'unique' => (bool) $marker->isUnique(), |
||
230 | 'dropDups' => (bool) $marker->isDropDups(), |
||
231 | 'sparse' => (bool) $marker->isSparse(), |
||
232 | ]; |
||
233 | |||
234 | if ($marker->getExpireAfterSeconds() >= 0) { |
||
235 | $options['expireAfterSeconds'] = $marker->getExpireAfterSeconds(); |
||
236 | } |
||
237 | |||
238 | return $options; |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * @param string[] $prefixes |
||
243 | * @param string $fieldName |
||
244 | * |
||
245 | * @return string |
||
246 | */ |
||
247 | private function buildFieldName($prefixes, $fieldName) |
||
248 | { |
||
249 | if (\count($prefixes) === 0) { |
||
250 | return $fieldName; |
||
251 | } |
||
252 | |||
253 | return implode('.', $prefixes) . '.' . $fieldName; |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * @param string[] $prefixes |
||
258 | * @param string $propertyName |
||
259 | * @param IndexDefinition $marker |
||
260 | * |
||
261 | * @return string |
||
262 | */ |
||
263 | private function buildPropertyIndexName($prefixes, $propertyName, IndexDefinition $marker) |
||
264 | { |
||
265 | // is the name overridden by the user ? |
||
266 | if (! empty($marker->getName())) { |
||
267 | $rest = $marker->getName(); |
||
268 | } else { |
||
269 | $rest = $propertyName . '_' . $this->mapDirection($marker); |
||
270 | } |
||
271 | |||
272 | if (\count($prefixes) > 0) { |
||
273 | return implode('.', $prefixes) . '.' . $rest; |
||
274 | } |
||
275 | |||
276 | return $rest; |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * @param string[] $prefixes |
||
281 | * @param array $definition |
||
282 | * |
||
283 | * @return string |
||
284 | */ |
||
285 | private function buildCompoundIndexName($prefixes, $definition) |
||
286 | { |
||
287 | $parts = []; |
||
288 | |||
289 | foreach ($definition as $k => $v) { |
||
290 | $parts[] = ((string) $k) . '_' . ((string) $v); |
||
291 | } |
||
292 | |||
293 | $rest = implode('_', $parts); |
||
294 | |||
295 | if (\count($prefixes) > 0) { |
||
296 | return implode('.', $prefixes) . '.' . $rest; |
||
297 | } |
||
298 | |||
299 | return $rest; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * @param IndexDefinition $marker |
||
304 | * |
||
305 | * @return int |
||
306 | */ |
||
307 | private function mapDirection(IndexDefinition $marker) |
||
308 | { |
||
309 | return $marker->getDirection() === PropertyStorageIndexMarker::ASCENDING ? 1 : -1; |
||
310 | } |
||
311 | } |
||
312 |
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.