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 | namespace izzum\statemachine\persistence; |
||
3 | use izzum\statemachine\loader\Loader; |
||
4 | use izzum\statemachine\StateMachine; |
||
5 | use izzum\statemachine\Context; |
||
6 | use izzum\statemachine\loader\LoaderArray; |
||
7 | use izzum\statemachine\loader\LoaderData; |
||
8 | use izzum\statemachine\Exception; |
||
9 | use izzum\statemachine\Identifier; |
||
10 | use izzum\statemachine\Transition; |
||
11 | use izzum\statemachine\loader\JSON; |
||
12 | use izzum\statemachine\State; |
||
13 | /** |
||
14 | * MongoDB (from humongous) is a cross-platform document-oriented database. |
||
15 | * MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling. |
||
16 | * MongoDB obviates the need for an Object Relational Mapping (ORM) to facilitate development. |
||
17 | * |
||
18 | * start macosx: mongod --config /usr/local/etc/mongod.conf |
||
19 | * mongo shell: mongo |
||
20 | * |
||
21 | * |
||
22 | * @link https://www.mongodb.org/ |
||
23 | * @link https://www.mongodb.org/downloads for the downloads for your system |
||
24 | * @link http://docs.mongodb.org/ecosystem/drivers/php/ for the php driver you need to install |
||
25 | * @link https://github.com/mongodb/mongo-php-driver for the source code of the php driver |
||
26 | * @link https://php.net/mongo the official documentation for the driver on php.net |
||
27 | * @link http://docs.mongodb.org/manual/reference/program/mongo/#bin.mongo the mongo client |
||
28 | * @link https://en.wikipedia.org/wiki/MongoDB |
||
29 | * |
||
30 | */ |
||
31 | class MongoDB extends Adapter implements Loader { |
||
32 | |||
33 | /** |
||
34 | * the data source name for a mongo connection |
||
35 | * @var string |
||
36 | */ |
||
37 | protected $dns; |
||
38 | /** |
||
39 | * connection options |
||
40 | * @var array |
||
41 | */ |
||
42 | protected $options; |
||
43 | /** |
||
44 | * the php driver specific options |
||
45 | * @var array |
||
46 | */ |
||
47 | protected $driver_options; |
||
48 | |||
49 | /** |
||
50 | * the (settable) mongo client |
||
51 | * @var \MongoClient |
||
52 | */ |
||
53 | private $client; |
||
54 | |||
55 | /** |
||
56 | * constructor. a connection to mongodb via the mongoclient will be lazily created. |
||
57 | * an existing mongoclient can also be set on this class (reuse a client accross your application) |
||
58 | * @param string $dns the data source name. mongodb://[username:password@]host1[:port1][,host2[:port2:],...] |
||
59 | * @param array $options server options (usable for authentication, replicasets etc) |
||
60 | * @param array $driver_options php specifif driver options |
||
61 | * @link https://php.net/manual/en/mongoclient.construct.php |
||
62 | */ |
||
63 | 1 | public function __construct($dns = 'mongodb://localhost:27017', $options = array("connect" => true), $driver_options = array()) { |
|
64 | 1 | $this->dns = $dns; |
|
65 | 1 | $this->options = $options; |
|
66 | 1 | $this->driver_options = $driver_options; |
|
67 | 1 | } |
|
68 | |||
69 | /** |
||
70 | * A hook to use in a subclass. |
||
71 | * you can do you initial setup here if you like. |
||
72 | */ |
||
73 | 1 | protected function onConnect() { |
|
74 | //override if necessary |
||
75 | 1 | } |
|
76 | |||
77 | |||
78 | /** |
||
79 | * Gets a lazy loaded \MongoClient instance. |
||
80 | * |
||
81 | * @throws Exception |
||
82 | * @return \MongoClient |
||
83 | */ |
||
84 | 1 | public function getClient() |
|
85 | { |
||
86 | 1 | if(!isset($this->client)) { |
|
87 | 1 | $client = new \MongoClient($this->dns, $this->options, $this->driver_options); |
|
88 | 1 | $this->client = $client; |
|
89 | 1 | $this->onConnect(); |
|
90 | 1 | } |
|
91 | 1 | return $this->client; |
|
92 | } |
||
93 | |||
94 | /** |
||
95 | * since we do not want to burden a client of this code with the responsiblity of |
||
96 | * creating indexes, we take a statistical approach to check if we need to |
||
97 | * create an index in the background. This will only be done once. |
||
98 | * @param number $check_index_once_in check for index creation. on average, every <x> times |
||
99 | * the index should be created if it is not there already |
||
100 | */ |
||
101 | 1 | protected function checkAndCreateIndexesIfNecessary($check_index_once_in = 1000) |
|
102 | { |
||
103 | //statistical approach to building the index on average once every x times |
||
104 | 1 | $check_index_once_in = min(1000, $check_index_once_in); |
|
105 | 1 | if(rand(1, $check_index_once_in) % $check_index_once_in === 0) { |
|
106 | $this->createIndexes(); |
||
107 | } |
||
108 | 1 | } |
|
109 | |||
110 | /** |
||
111 | * create indexes in the background for the collections used. this will only be done by |
||
112 | * mongo if they do not exist already. |
||
113 | */ |
||
114 | protected function createIndexes() |
||
115 | { |
||
116 | //http://docs.mongodb.org/manual/tutorial/create-a-compound-index/ |
||
117 | |||
118 | //querying the history could use different indexes, depending on what you want to know |
||
119 | //db.history.createIndex({entity_id: 1, machine: 1}, {background: true}); |
||
0 ignored issues
–
show
|
|||
120 | $index = array("entity_id" => 1, "machine" => 1); |
||
121 | $options = array ("background" => true); |
||
122 | $this->getClient()->izzum->history->createIndex($index, $options); |
||
123 | //getting the state for an entity_id/machine should be fast |
||
124 | //db.states.createIndex({entity_id: 1, machine: 1}, {background: true}); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
48% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
125 | $index = array("entity_id" => 1, "machine" => 1); |
||
126 | $options = array ("background" => true); |
||
127 | $this->getClient()->izzum->states->createIndex($index, $options); |
||
128 | |||
129 | //show the existing indexes |
||
130 | //db.system.indexes.find() |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * sets a mongoclient. this can be useful if your application already has |
||
135 | * a mongoclient instantiated and you want to reuse it. |
||
136 | * @param \MongoClient $client |
||
137 | */ |
||
138 | public function setClient(\MongoClient $client) |
||
139 | { |
||
140 | $this->client = $client; |
||
141 | } |
||
142 | |||
143 | |||
144 | /** |
||
145 | * {@inheritDoc} |
||
146 | */ |
||
147 | 1 | protected function addHistory(Identifier $identifier, $state, $message = null, $is_exception = false) |
|
148 | { |
||
149 | //find in history from mongo shell: db.history.find({"machine" : "test-machine", "state": "done"},{entity_id: 1, state: 1, datetime: 1}) |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
40% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
150 | try { |
||
151 | 1 | $data = new \stdClass(); |
|
152 | 1 | $data->entity_id = $identifier->getEntityId(); |
|
153 | 1 | $data->machine = $identifier->getMachine(); |
|
154 | 1 | $data->state = $state; |
|
155 | 1 | if($message) { |
|
156 | 1 | if(is_string($message)) { |
|
157 | 1 | $info = new \stdClass(); |
|
158 | 1 | $info->message = $message; |
|
159 | 1 | $message = $info; |
|
160 | 1 | } |
|
161 | 1 | } |
|
162 | 1 | $data->message = $message; |
|
163 | 1 | $timestamp = time(); |
|
164 | 1 | $data->timestamp = $timestamp; |
|
165 | 1 | $data->datetime = date('Y-m-d H:i:s', $timestamp);//ISO_8601 |
|
166 | 1 | $data->is_exception = $is_exception; |
|
167 | //insert into the 'history' collection |
||
168 | 1 | $this->getClient()->izzum->history->insert($data); |
|
169 | 1 | } catch (\Exception $e) { |
|
170 | throw new Exception(sprintf('adding history failed: [%s]', |
||
171 | $e->getMessage()), |
||
172 | Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
173 | } |
||
174 | 1 | } |
|
175 | |||
176 | /** |
||
177 | * {@inheritDoc} |
||
178 | */ |
||
179 | 1 | protected function insertState(Identifier $identifier, $state, $message = null) |
|
180 | { |
||
181 | try { |
||
182 | 1 | $data = new \stdClass(); |
|
183 | 1 | $data->timestamp = time(); |
|
184 | 1 | $data->state = $state; |
|
185 | 1 | $data->entity_id = $identifier->getEntityId(); |
|
186 | 1 | $data->machine = $identifier->getMachine(); |
|
187 | //insert into the 'states' collection |
||
188 | //https://php.net/manual/en/mongocollection.insert.php |
||
189 | 1 | $this->getClient()->izzum->states->insert($data); |
|
190 | 1 | } catch (\Exception $e) { |
|
191 | throw new Exception(sprintf('query for inserting state failed: [%s]', |
||
192 | $e->getMessage()), |
||
193 | Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
194 | } |
||
195 | 1 | } |
|
196 | |||
197 | /** |
||
198 | * {@inheritDoc} |
||
199 | */ |
||
200 | 1 | protected function updateState(Identifier $identifier, $state, $message = null) |
|
201 | { |
||
202 | try { |
||
203 | 1 | $client = $this->getClient(); |
|
204 | //find the state |
||
205 | //https://php.net/manual/en/mongocollection.findone.php |
||
206 | 1 | $query = array("machine" => $identifier->getMachine(), "entity_id" => $identifier->getEntityId()); |
|
207 | 1 | $data = $client->izzum->states->findOne($query); |
|
208 | 1 | if($data) { |
|
209 | //update the state and timestamp |
||
210 | //$_id = $data['_id']; |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
67% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
211 | 1 | $data['timestamp'] = time(); |
|
212 | 1 | $data['state'] = $state; |
|
213 | //save into the 'states' collection |
||
214 | //https://php.net/manual/en/mongocollection.save.php |
||
215 | 1 | $client->izzum->states->save($data); |
|
216 | 1 | } else { |
|
217 | throw new Exception(sprintf('no state found for [%s]. Did you "$machine->add()" it to the persistence layer?', |
||
218 | $identifier->getId(true)), |
||
219 | Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
220 | } |
||
221 | 1 | } catch (\Exception $e) { |
|
222 | throw new Exception(sprintf('updating state failed: [%s]', |
||
223 | $e->getMessage()), |
||
224 | Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
225 | } |
||
226 | 1 | } |
|
227 | |||
228 | /** |
||
229 | * {@inheritDoc} |
||
230 | */ |
||
231 | 1 | public function processGetState(Identifier $identifier) |
|
232 | { |
||
233 | 1 | $state = null; |
|
234 | try { |
||
235 | //check if indexes exists every x times this method is called |
||
236 | 1 | $this->checkAndCreateIndexesIfNecessary(500); |
|
237 | |||
238 | //find the state |
||
239 | //https://php.net/manual/en/mongocollection.findone.php |
||
240 | 1 | $query = array("entity_id" => $identifier->getEntityId(), "machine" => $identifier->getMachine()); |
|
241 | 1 | $data = $this->getClient()->izzum->states->findOne($query); |
|
242 | 1 | if($data) { |
|
243 | 1 | $state = $data['state']; |
|
244 | 1 | } |
|
245 | 1 | } catch (\Exception $e) { |
|
246 | throw new Exception(sprintf('getting current state failed: [%s]', |
||
247 | $e->getMessage()), Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
248 | } |
||
249 | 1 | if(!$state) { |
|
250 | throw new Exception(sprintf('no state found for [%s]. Did you "$machine->add()" it to the persistence layer?', |
||
251 | $identifier->getId(true)), |
||
252 | Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
253 | } |
||
254 | 1 | return $state; |
|
255 | } |
||
256 | |||
257 | /** |
||
258 | * {@inheritDoc} |
||
259 | */ |
||
260 | 1 | public function isPersisted(Identifier $identifier) |
|
261 | { |
||
262 | 1 | $is_persisted = false; |
|
263 | try { |
||
264 | //https://php.net/manual/en/mongocollection.findone.php |
||
265 | 1 | $query = array("entity_id" => $identifier->getEntityId(), "machine" => $identifier->getMachine()); |
|
266 | 1 | $data = $this->getClient()->izzum->states->findOne($query); |
|
267 | 1 | if($data) { |
|
268 | 1 | $is_persisted = true; |
|
269 | 1 | } |
|
270 | 1 | } catch (\Exception $e) { |
|
271 | throw new Exception( |
||
272 | sprintf('getting persistence info failed: [%s]', |
||
273 | $e->getMessage()), Exception::PERSISTENCE_LAYER_EXCEPTION); |
||
274 | } |
||
275 | 1 | return $is_persisted; |
|
276 | } |
||
277 | |||
278 | /** |
||
279 | * {@inheritDoc} |
||
280 | */ |
||
281 | 1 | public function getEntityIds($machine, $state = null) |
|
282 | { |
||
283 | 1 | $output = array(); |
|
284 | try { |
||
285 | 1 | $client = $this->getClient(); |
|
286 | 1 | $query = array("machine" => $machine); |
|
287 | 1 | if($state !== null) { |
|
288 | 1 | $query["state"] = $state; |
|
289 | 1 | } |
|
290 | 1 | $projection = array("entity_id" => 1); |
|
291 | //find all in the 'states' collection |
||
292 | 1 | $found = $client->izzum->states->find($query, $projection); |
|
293 | 1 | foreach($found as $data) { |
|
294 | 1 | $output[] = $data['entity_id']; |
|
295 | 1 | } |
|
296 | 1 | } catch (\Exception $e) { |
|
297 | throw new Exception($e->getMessage(), |
||
298 | Exception::PERSISTENCE_LAYER_EXCEPTION, $e); |
||
299 | } |
||
300 | 1 | return $output; |
|
301 | } |
||
302 | |||
303 | |||
304 | |||
305 | /** |
||
306 | * {@inheritDoc} |
||
307 | * Load the statemachine via a document in a mongodb collection. |
||
308 | * |
||
309 | * The document, originally loaded as a json string (see JSON::getJSONSchema) |
||
310 | * is stored at the mongodb collection 'configuration' by default. |
||
311 | * multiple machine definitions can be provided in a single document, or in multiple documents in the collection. |
||
312 | * The first document containing the 'machines.name' key with the value matching |
||
313 | * the name of the $statemachine is used. |
||
314 | * |
||
315 | * You could use the ReaderWriterDelegator to use another source to load the configuration from. |
||
316 | */ |
||
317 | 1 | public function load(StateMachine $statemachine) { |
|
318 | //use the JSON loader to load the configuration (see the json schema we expect in JSON::getJSONSchema) |
||
319 | //mongodb does not store JSON but documents (converts the json structure) and the mongodb |
||
320 | //php library returns these documents as php objects. |
||
321 | //therefore, we json_encode it again, so it can be json_decoded in the JSON class :-( |
||
322 | //alternatively, we could write a PHP Loader, but the assumption is that the speed gain is not worth it. |
||
323 | 1 | $loader = new JSON( |
|
324 | 1 | json_encode( |
|
325 | 1 | $this->getClient()->izzum->configuration->findOne( |
|
326 | 1 | array("machines.name" => $statemachine->getContext()->getMachine()) |
|
327 | 1 | ) |
|
328 | 1 | ) |
|
329 | 1 | ); |
|
330 | 1 | $count = $loader->load($statemachine); |
|
331 | 1 | return $count; |
|
332 | } |
||
333 | |||
334 | 1 | public function toString() |
|
335 | { |
||
336 | 1 | return get_class($this) . ' ' . $this->dns;; |
|
337 | } |
||
338 | |||
339 | 1 | public function __toString() |
|
340 | { |
||
341 | 1 | return $this->toString(); |
|
342 | } |
||
343 | } |
||
344 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.