Mongodb   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 28
eloc 138
dl 0
loc 333
c 0
b 0
f 0
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A getQuery() 0 8 2
A command() 0 17 2
A update() 0 18 2
A getOptions() 0 9 3
A getInstance() 0 3 1
A getCommand() 0 8 2
A getWrite() 0 8 2
A select() 0 17 2
A delete() 0 18 2
A getBulk() 0 8 2
A connect() 0 24 3
A genDsn() 0 7 1
A getID() 0 8 2
A insert() 0 21 2
1
<?php
2
3
namespace DrMVC\Database\Drivers;
4
5
use MongoDB\BSON\ObjectID;
6
use MongoDB\Driver\Exception\Exception as MongoException;
7
use MongoDB\Driver\Exception\InvalidArgumentException;
8
use MongoDB\Driver\Exception\RuntimeException;
9
use MongoDB\Driver\Exception\BulkWriteException;
10
use MongoDB\Driver\Manager as MongoManager;
11
use MongoDB\Driver\BulkWrite as MongoBulk;
12
use MongoDB\Driver\WriteConcern as MongoWrite;
13
use MongoDB\Driver\Command as MongoCommand;
14
use MongoDB\Driver\Query as MongoQuery;
15
use DrMVC\Database\Exception;
16
use DrMVC\Database\Drivers\Interfaces\MongodbInterface;
17
use DrMVC\Database\Drivers\Interfaces\DriverInterface;
18
19
/**
20
 * Class for work with modern MongoDB php driver (for PHP >= 7.0 only)
21
 *
22
 * @package DrMVC\Database\Drivers
23
 * @since   3.0
24
 */
25
class Mongodb extends NoSQL implements MongodbInterface
26
{
27
    const DEFAULT_HOST = 'localhost';
28
    const DEFAULT_PORT = '27017';
29
30
    /**
31
     * @link http://nl1.php.net/manual/en/mongodb-driver-manager.construct.php
32
     *
33
     * Additional connection string options, which will overwrite any options with
34
     * the same name in the uri parameter.
35
     */
36
    const AVAILABLE_OPTIONS = [
37
        'appname',
38
        'authMechanism',
39
        'authMechanismProperties',
40
        'authSource',
41
        'canonicalizeHostname',
42
        'compressors',
43
        'connectTimeoutMS',
44
        'gssapiServiceName',
45
        'heartbeatFrequencyMS',
46
        'journal',
47
        'localThresholdMS',
48
        'maxStalenessSeconds',
49
        'password',
50
        'readConcernLevel',
51
        'readPreference',
52
        'readPreferenceTags',
53
        'replicaSet',
54
        'retryWrites',
55
        'safe',
56
        'serverSelectionTimeoutMS',
57
        'serverSelectionTryOnce',
58
        'slaveOk',
59
        'socketCheckIntervalMS',
60
        'socketTimeoutMS',
61
        'ssl',
62
        'username',
63
        'w',
64
        'wTimeoutMS',
65
        'zlibCompressionLevel'
66
    ];
67
68
    const AVAILABLE_DRIVER_OPTIONS = [
69
        'allow_invalid_hostname',
70
        'ca_dir',
71
        'ca_file',
72
        'crl_file',
73
        'pem_file',
74
        'pem_pwd',
75
        'context',
76
        'weak_cert_validation'
77
    ];
78
79
    /**
80
     * Get current connection
81
     *
82
     * @return  MongoManager
83
     */
84
    public function getInstance(): MongoManager
85
    {
86
        return $this->_instance;
87
    }
88
89
    /**
90
     * Initiate connection with database
91
     *
92
     * @return  DriverInterface
93
     */
94
    public function connect(): DriverInterface
95
    {
96
        // URL options
97
        $options = $this->getConfig()->get();
98
99
        // TODO: This option should be optional, in addition, it may not be an array
100
        // Driver options
101
        $optionsDriver = $options['driver_options']->get();
102
103
        try {
104
            $connection = new MongoManager(
105
                $this->getDsn(),
106
                $this->getOptions($options, self::AVAILABLE_OPTIONS),
107
                $this->getOptions($optionsDriver, self::AVAILABLE_DRIVER_OPTIONS)
108
            );
109
            $this->setInstance($connection);
110
111
        } catch (RuntimeException $e) {
112
            new Exception('Unable to connect');
113
        } catch (InvalidArgumentException $e) {
114
            new Exception('Invalid argument provided');
115
        }
116
117
        return $this;
118
    }
119
120
    /**
121
     * Generate DSN by parameters in config
122
     *
123
     * @param   array $config
124
     * @return  string
125
     */
126
    public function genDsn($config): string
127
    {
128
        // Get driver of connection
129
        $driver = strtolower($config['driver']);
130
        $url = $config['url'];
131
132
        return "$driver://$url";
133
    }
134
135
    /**
136
     * Generate options array
137
     *
138
     * @param   array $options
139
     * @param   array $allowed
140
     * @return  array
141
     */
142
    private function getOptions(array $options, array $allowed): array
143
    {
144
        $result = [];
145
        foreach ($options as $key => $value) {
146
            if (\in_array($key, $allowed, false)) {
147
                $result[$key] = $value;
148
            }
149
        }
150
        return $result;
151
    }
152
153
    /**
154
     * @return MongoBulk
155
     */
156
    private function getBulk(): MongoBulk
157
    {
158
        try {
159
            $bulk = new MongoBulk();
160
        } catch (InvalidArgumentException $e) {
161
            new Exception('Unable to create Bulk object');
162
        }
163
        return $bulk;
164
    }
165
166
    /**
167
     * @return ObjectID
168
     */
169
    private function getID(): ObjectID
170
    {
171
        try {
172
            $objectID = new ObjectID();
173
        } catch (InvalidArgumentException $e) {
174
            new Exception('ObjectID could not to be generated');
175
        }
176
        return $objectID;
177
    }
178
179
    /**
180
     * @return MongoWrite
181
     */
182
    private function getWrite(): MongoWrite
183
    {
184
        try {
185
            $write = new MongoWrite(MongoWrite::MAJORITY, 1000);
186
        } catch (InvalidArgumentException $e) {
187
            new Exception('WriteConcern could not to be initiated');
188
        }
189
        return $write;
190
    }
191
192
    /**
193
     * Insert in database and return of inserted element
194
     *
195
     * @param   array $data array of columns and values
196
     * @return  mixed
197
     */
198
    public function insert(array $data): string
199
    {
200
        // Set object ID as id of item
201
        $data['_id'] = $this->getID();
202
203
        // Set statement of bulk object
204
        $bulk = $this->getBulk();
205
        $bulk->insert($data);
206
207
        try {
208
            $this->getInstance()->executeBulkWrite(
209
                $this->getParam('database') . '.' . $this->getCollection(),
210
                $bulk,
211
                $this->getWrite()
212
            );
213
214
        } catch (BulkWriteException $e) {
215
            new Exception('Unable to write in database');
216
        }
217
218
        return (string) $data['_id'];
219
    }
220
221
    /**
222
     * Create query object from filter and option arrays
223
     *
224
     * @param   array $where
225
     * @param   array $options
226
     * @return  MongoQuery
227
     */
228
    private function getQuery(array $where, array $options): MongoQuery
229
    {
230
        try {
231
            $query = new MongoQuery($where, $options);
232
        } catch (InvalidArgumentException $e) {
233
            new Exception('WriteConcern could not to be initiated');
234
        }
235
        return $query;
236
    }
237
238
    /**
239
     * Execute MongoQuery
240
     *
241
     * @param   array $filter
242
     * @param   array $options
243
     * @return  mixed
244
     */
245
    public function select(array $filter = [], array $options = [])
246
    {
247
        // Create query object from filter and option arrays
248
        $query = $this->getQuery($filter, $options);
249
250
        try {
251
            $cursor = $this->getInstance()->executeQuery(
252
                $this->getParam('database') . '.' . $this->getCollection(),
253
                $query
254
            );
255
            $response = $cursor->toArray();
256
257
        } catch (MongoException $e) {
258
            new Exception('Unable to execute query');
259
        }
260
261
        return $response ?? false;
262
    }
263
264
    /**
265
     * Update data in database
266
     *
267
     * @param   array $data
268
     * @param   array $filter
269
     * @param   array $updateOptions
270
     * @return  mixed
271
     */
272
    public function update(array $data, array $filter = [], array $updateOptions = [])
273
    {
274
        // Set statement of bulk object
275
        $bulk = $this->getBulk();
276
        $bulk->update($filter, $data, $updateOptions);
277
278
        try {
279
            $response = $this->getInstance()->executeBulkWrite(
280
                $this->getParam('database') . '.' . $this->getCollection(),
281
                $bulk,
282
                $this->getWrite()
283
            );
284
285
        } catch (BulkWriteException $e) {
286
            new Exception('Unable to write in database');
287
        }
288
289
        return $response ?? false;
290
    }
291
292
    /**
293
     * Delete data from table/collection
294
     *
295
     * @param   array $filter
296
     * @param   array $deleteOptions
297
     * @return  mixed
298
     */
299
    public function delete(array $filter, array $deleteOptions = [])
300
    {
301
        // Set statement of bulk object
302
        $bulk = $this->getBulk();
303
        $bulk->delete($filter, $deleteOptions);
304
305
        try {
306
            $response = $this->getInstance()->executeBulkWrite(
307
                $this->getParam('database') . '.' . $this->getCollection(),
308
                $bulk,
309
                $this->getWrite()
310
            );
311
312
        } catch (BulkWriteException $e) {
313
            new Exception('Unable to write in database');
314
        }
315
316
        return $response ?? false;
317
    }
318
319
    /**
320
     * Create command from query
321
     *
322
     * @param   array $query
323
     * @return  MongoCommand
324
     */
325
    private function getCommand($query): MongoCommand
326
    {
327
        try {
328
            $command = new MongoCommand($query);
329
        } catch (InvalidArgumentException $e) {
330
            new Exception('WriteConcern could not to be initiated');
331
        }
332
        return $command;
333
    }
334
335
    /**
336
     * Execute MongoCommand
337
     *
338
     * @param   array $query should be like new MongoDB\Driver\Query($filter, $options);
339
     * @return  mixed
340
     */
341
    public function command(array $query)
342
    {
343
        // Create command from query
344
        $command = $this->getCommand($query);
345
346
        try {
347
            $cursor = $this->getInstance()->executeCommand(
348
                $this->getParam('database'),
349
                $command
350
            );
351
            $response = $cursor->toArray();
352
353
        } catch (MongoException $e) {
354
            new Exception('Unable to execute command');
355
        }
356
357
        return $response ?? false;
358
    }
359
360
}
361