Completed
Push — master ( a0a464...9c0da3 )
by Mr
02:05
created

Mongodb::delete()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 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
17
/**
18
 * Class for work with modern MongoDB php driver (for PHP >= 7.0)
19
 * @package DrMVC\Database\Drivers
20
 */
21
class Mongodb extends NoSQL
22
{
23
    const DEFAULT_HOST = 'localhost';
24
    const DEFAULT_PORT = '27017';
25
26
    /**
27
     * @link http://nl1.php.net/manual/en/mongodb-driver-manager.construct.php
28
     *
29
     * Additional connection string options, which will overwrite any options with
30
     * the same name in the uri parameter.
31
     */
32
    const AVAILABLE_OPTIONS = [
33
        'appname',
34
        'authMechanism',
35
        'authMechanismProperties',
36
        'authSource',
37
        'canonicalizeHostname',
38
        'compressors',
39
        'connectTimeoutMS',
40
        'gssapiServiceName',
41
        'heartbeatFrequencyMS',
42
        'journal',
43
        'localThresholdMS',
44
        'maxStalenessSeconds',
45
        'password',
46
        'readConcernLevel',
47
        'readPreference',
48
        'readPreferenceTags',
49
        'replicaSet',
50
        'retryWrites',
51
        'safe',
52
        'serverSelectionTimeoutMS',
53
        'serverSelectionTryOnce',
54
        'slaveOk',
55
        'socketCheckIntervalMS',
56
        'socketTimeoutMS',
57
        'ssl',
58
        'username',
59
        'w',
60
        'wTimeoutMS',
61
        'zlibCompressionLevel'
62
    ];
63
64
    const AVAILABLE_DRIVER_OPTIONS = [
65
        'allow_invalid_hostname',
66
        'ca_dir',
67
        'ca_file',
68
        'crl_file',
69
        'pem_file',
70
        'pem_pwd',
71
        'context',
72
        'weak_cert_validation'
73
    ];
74
75
    /**
76
     * Initiate connection with database
77
     *
78
     * @return  DriverInterface
79
     */
80
    public function connect(): DriverInterface
81
    {
82
        // URL options
83
        $options = $this->getConfig()->get();
84
85
        // Driver options
86
        $optionsDriver = $options['driver_options']->get();
87
88
        try {
89
            $connection = new MongoManager(
90
                $this->getDsn(),
91
                $this->getOptions($options, self::AVAILABLE_OPTIONS),
92
                $this->getOptions($optionsDriver, self::AVAILABLE_DRIVER_OPTIONS)
93
            );
94
            $this->setConnection($connection);
95
96
        } catch (RuntimeException $e) {
97
            new Exception('Unable to connect');
98
        } catch (InvalidArgumentException $e) {
99
            new Exception('Invalid argument provided');
100
        }
101
102
        return $this;
103
    }
104
105
    /**
106
     * Generate DSN by parameters in config
107
     *
108
     * @param   array $config
109
     * @return  string
110
     */
111
    public function genDsn($config): string
112
    {
113
        // Get driver of connection
114
        $driver = strtolower($config['driver']);
115
        $url = $config['url'];
116
117
        return "$driver://$url";
118
    }
119
120
    /**
121
     * Generate options array
122
     *
123
     * @param   array $options
124
     * @param   array $allowed
125
     * @return  array
126
     */
127
    private function getOptions(array $options, array $allowed): array
128
    {
129
        $result = [];
130
        foreach ($options as $key => $value) {
131
            if (\in_array($key, $allowed, false)) {
132
                $result[$key] = $value;
133
            }
134
        }
135
        return $result;
136
    }
137
138
    /**
139
     * @return MongoBulk
140
     */
141
    private function getBulk(): MongoBulk
142
    {
143
        try {
144
            $bulk = new MongoBulk();
145
        } catch (InvalidArgumentException $e) {
146
            new Exception('Unable to create Bulk object');
147
        }
148
        return $bulk;
149
    }
150
151
    /**
152
     * @return ObjectID
153
     */
154
    private function getID(): ObjectID
155
    {
156
        try {
157
            $objectID = new ObjectID();
158
        } catch (InvalidArgumentException $e) {
159
            new Exception('ObjectID could not to be generated');
160
        }
161
        return $objectID;
162
    }
163
164
    /**
165
     * @return MongoWrite
166
     */
167
    private function getWrite(): MongoWrite
168
    {
169
        try {
170
            $write = new MongoWrite(MongoWrite::MAJORITY, 1000);
171
        } catch (InvalidArgumentException $e) {
172
            new Exception('WriteConcern could not to be initiated');
173
        }
174
        return $write;
175
    }
176
177
    /**
178
     * Insert in database and return of inserted element
179
     *
180
     * @param   array $data array of columns and values
181
     * @return  mixed
182
     */
183
    public function insert(array $data): string
184
    {
185
        // Set bulk object
186
        $bulk = $this->getBulk();
187
188
        // Set object ID as id of item
189
        $query['_id'] = $this->getID();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$query was never initialized. Although not strictly required by PHP, it is generally a good practice to add $query = array(); before regardless.
Loading history...
190
191
        // Set statement
192
        $bulk->insert($query);
193
194
        try {
195
            $this->getConnection()->executeBulkWrite(
0 ignored issues
show
Bug introduced by
The method executeBulkWrite() does not exist on PDO. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

195
            $this->getConnection()->/** @scrutinizer ignore-call */ executeBulkWrite(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
196
                $this->getParam('database') . '.' . $this->getCollection(),
197
                $bulk,
198
                $this->getWrite()
199
            );
200
201
        } catch (BulkWriteException $e) {
202
            new Exception('Unable to write in database');
203
        }
204
205
        return (string)$query['_id'];
206
    }
207
208
    /**
209
     * Update data in database
210
     *
211
     * @param   array $data
212
     * @param   array $filter
213
     * @param   array $updateOptions
214
     * @return  mixed
215
     */
216
    public function update(array $data, array $filter = [], array $updateOptions = [])
217
    {
218
        // Set bulk object
219
        $bulk = $this->getBulk();
220
221
        // Set statement
222
        $bulk->update($filter, $data, $updateOptions);
223
224
        try {
225
            $response = $this->getConnection()->executeBulkWrite(
226
                $this->getParam('database') . '.' . $this->getCollection(),
227
                $bulk,
228
                $this->getWrite()
229
            );
230
231
        } catch (BulkWriteException $e) {
232
            new Exception('Unable to write in database');
233
        }
234
235
        return $response;
236
    }
237
238
    /**
239
     * Delete data from table/collection
240
     *
241
     * @param   array $filter
242
     * @param   array $deleteOptions
243
     * @return  mixed
244
     */
245
    public function delete(array $filter, array $deleteOptions = [])
246
    {
247
        // Set bulk object
248
        $bulk = $this->getBulk();
249
250
        // Set statement
251
        $bulk->delete($filter, $deleteOptions);
252
253
        try {
254
            $response = $this->getConnection()->executeBulkWrite(
255
                $this->getParam('database') . '.' . $this->getCollection(),
256
                $bulk,
257
                $this->getWrite()
258
            );
259
260
        } catch (BulkWriteException $e) {
261
            new Exception('Unable to write in database');
262
        }
263
264
        return $response;
265
    }
266
267
    /**
268
     * Create query object from filter and option arrays
269
     *
270
     * @param   array $where
271
     * @param   array $options
272
     * @return  MongoQuery
273
     */
274
    private function getQuery(array $where, array $options): MongoQuery
275
    {
276
        try {
277
            $query = new MongoQuery($where, $options);
278
        } catch (InvalidArgumentException $e) {
279
            new Exception('WriteConcern could not to be initiated');
280
        }
281
        return $query;
282
    }
283
284
    /**
285
     * Execute MongoQuery
286
     *
287
     * @param   array $where
288
     * @param   array $options
289
     * @return  mixed
290
     */
291
    public function select(array $where = [], array $options = [])
292
    {
293
        // Create query object from filter and option arrays
294
        $query = $this->getQuery($where, $options);
295
296
        try {
297
            $cursor = $this->getConnection()->executeQuery(
0 ignored issues
show
Bug introduced by
The method executeQuery() does not exist on PDO. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

297
            $cursor = $this->getConnection()->/** @scrutinizer ignore-call */ executeQuery(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
298
                $this->getParam('database') . '.' . $this->getCollection(),
299
                $query
300
            );
301
            $response = $cursor->toArray();
302
303
        } catch (MongoException $e) {
304
            new Exception('Unable to execute query');
305
        }
306
307
        return $response;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.
Loading history...
308
    }
309
310
    /**
311
     * Create command from query
312
     *
313
     * @param   array $query
314
     * @return  MongoCommand
315
     */
316
    private function getCommand($query): MongoCommand
317
    {
318
        try {
319
            $command = new MongoCommand($query);
320
        } catch (InvalidArgumentException $e) {
321
            new Exception('WriteConcern could not to be initiated');
322
        }
323
        return $command;
324
    }
325
326
    /**
327
     * Execute MongoCommand
328
     *
329
     * @param   array $query should be like new MongoDB\Driver\Query($filter, $options);
330
     * @return  mixed
331
     */
332
    public function command(array $query)
333
    {
334
        // Create command from query
335
        $command = $this->getCommand($query);
336
337
        try {
338
            $cursor = $this->getConnection()->executeCommand(
0 ignored issues
show
Bug introduced by
The method executeCommand() does not exist on PDO. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

338
            $cursor = $this->getConnection()->/** @scrutinizer ignore-call */ executeCommand(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
339
                $this->getParam('database'),
340
                $command
341
            );
342
            $response = $cursor->toArray();
343
344
        } catch (MongoException $e) {
345
            new Exception('Unable to execute command');
346
        }
347
348
        return $response;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.
Loading history...
349
    }
350
351
}
352