Completed
Push — master ( 8ad0a5...af5d94 )
by yuuki
10s
created

CouchbaseConnection::disconnect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
/**
4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10
 * THE SOFTWARE.
11
 */
12
13
namespace Ytake\LaravelCouchbase\Database;
14
15
use Closure;
16
use CouchbaseBucket;
17
use Illuminate\Database\Connection;
18
use Ytake\LaravelCouchbase\Query\View;
19
use Ytake\LaravelCouchbase\Schema\Builder;
20
use Ytake\LaravelCouchbase\Query\Grammar;
21
use Ytake\LaravelCouchbase\Query\Processor;
22
use Ytake\LaravelCouchbase\Events\QueryPrepared;
23
use Ytake\LaravelCouchbase\Events\ResultReturning;
24
use Ytake\LaravelCouchbase\Query\Builder as QueryBuilder;
25
use Ytake\LaravelCouchbase\Exceptions\NotSupportedException;
26
27
/**
28
 * Class CouchbaseConnection.
29
 *
30
 * @author Yuuki Takezawa<[email protected]>
31
 */
32
class CouchbaseConnection extends Connection
33
{
34
    /** @var string */
35
    protected $bucket;
36
37
    /** @var \CouchbaseCluster */
38
    protected $connection;
39
40
    /** @var */
41
    protected $managerUser;
42
43
    /** @var */
44
    protected $managerPassword;
45
46
    /** @var array */
47
    protected $options = [];
48
49
    /** @var int */
50
    protected $fetchMode = 0;
51
52
    /** @var array */
53
    protected $enableN1qlServers = [];
54
55
    /** @var string */
56
    protected $bucketPassword = '';
57
58
    /** @var string[] */
59
    protected $metrics;
60
61
    /** @var int  default consistency */
62
    protected $consistency = \CouchbaseN1qlQuery::NOT_BOUNDED;
63
64
    /** @var string[]  function to handle the retrieval of various properties. */
65
    private $properties = [
66
        'operationTimeout',
67
        'viewTimeout',
68
        'durabilityInterval',
69
        'durabilityTimeout',
70
        'httpTimeout',
71
        'configTimeout',
72
        'configDelay',
73
        'configNodeTimeout',
74
        'htconfigIdleTimeout',
75
    ];
76
77
    /** @var array */
78
    protected $config = [];
79
80
    /** @var string */
81
    protected $name;
82
83
    /**
84
     * @param array  $config
85
     * @param string $name
86
     */
87 7
    public function __construct(array $config, $name)
88
    {
89 7
        $this->config = $config;
90 7
        $this->name = $name;
91 7
        $this->getManagedConfigure($config);
92 7
93
        $this->useDefaultQueryGrammar();
94 7
95
        $this->useDefaultPostProcessor();
96 7
    }
97 7
98
    /**
99
     * @param $password
100
     *
101
     * @return $this
102
     */
103
    public function setBucketPassword($password)
104
    {
105
        $this->bucketPassword = $password;
106
107
        return $this;
108
    }
109
110
    /**
111
     * @param string $name
112
     *
113
     * @return \CouchbaseBucket
114
     *
115
     * @throws \CouchbaseException
116 2
     */
117
    public function openBucket($name)
118 2
    {
119
        return $this->getCouchbase()->openBucket($name, $this->bucketPassword);
120
    }
121
122
    /**
123
     * @return \CouchbaseClusterManager
124
     */
125
    public function manager()
126 1
    {
127
        return $this->getCouchbase()->manager($this->managerUser, $this->managerPassword);
128 1
    }
129 1
130 1
    /**
131
     * @param CouchbaseBucket $bucket
132
     *
133 1
     * @return string[]
134
     */
135
    public function getOptions(\CouchbaseBucket $bucket)
136
    {
137
        $options = [];
138
        foreach ($this->properties as $property) {
139
            $options[$property] = $bucket->$property;
140
        }
141
142
        return $options;
143
    }
144
145
    /**
146
     * @param CouchbaseBucket $bucket
147
     */
148
    protected function registerOption(\CouchbaseBucket $bucket)
149
    {
150
        if (count($this->options)) {
151 7
            foreach ($this->options as $option => $value) {
152
                $bucket->$option = $value;
153 7
            }
154
        }
155
    }
156
157
    /**
158
     * @return Processor
159 7
     */
160
    protected function getDefaultPostProcessor()
161 7
    {
162
        return new Processor();
163
    }
164
165
    /**
166
     * @return Grammar
167 7
     */
168
    protected function getDefaultQueryGrammar()
169 7
    {
170 7
        return new Grammar();
171 7
    }
172 7
173 7
    /**
174 7
     * @return Builder|\Illuminate\Database\Schema\Builder
175
     */
176 7
    public function getSchemaBuilder()
177
    {
178
        return new Builder($this);
179
    }
180
181
    /**
182
     *
183
     * @param array $config enable(array), options(array), administrator(array), bucket_password(string)
184
     */
185
    protected function getManagedConfigure(array $config)
186
    {
187 7
        $this->enableN1qlServers = (isset($config['enables'])) ? $config['enables'] : [];
188
        $this->options = (isset($config['options'])) ? $config['options'] : [];
189 7
        $manager = (isset($config['administrator'])) ? $config['administrator'] : null;
190
        $this->managerUser = '';
191
        $this->managerPassword = '';
192
        if (!is_null($manager)) {
193
            $this->managerUser = $config['administrator']['user'];
194
            $this->managerPassword = $config['administrator']['password'];
195
        }
196
        $this->bucketPassword = (isset($config['bucket_password'])) ? $config['bucket_password'] : '';
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202
    public function getName()
203
    {
204
        return $this->name;
205
    }
206
207
    /**
208
     * @return \CouchbaseCluster
209
     */
210
    protected function createConnection()
211
    {
212
        $this->setReconnector(function () {
213
            $this->connection = (new CouchbaseConnector)->connect($this->config);
214
215
            return $this;
216
        });
217
218
        return (new CouchbaseConnector)->connect($this->config);
219
    }
220
221
    /**
222
     * {@inheritdoc}
223
     */
224
    public function getDriverName()
225
    {
226
        return 'couchbase';
227
    }
228
229
    /**
230
     * @return \CouchbaseCluster
231
     */
232
    public function getCouchbase()
233
    {
234 1
        if (is_null($this->connection)) {
235
            $this->connection = $this->createConnection();
236 1
        }
237 1
238
        return $this->connection;
239 1
    }
240
241
    /**
242
     * @param string $table
243
     *
244
     * @return QueryBuilder
245
     */
246
    public function table($table)
247
    {
248
        return $this->bucket($table)->query()->from($table);
249
    }
250
251
    /**
252
     * @param int      $consistency
253
     * @param callable $callback
254
     *
255
     * @return mixed
256
     */
257
    public function callableConsistency($consistency, callable $callback)
258
    {
259
        $clone = clone $this;
260
        $clone->consistency = $consistency;
261
262
        return call_user_func_array($callback, [$clone]);
263
    }
264
265
    /**
266
     * @param int $consistency
267
     *
268
     * @return $this
269
     */
270
    public function consistency($consistency)
271
    {
272
        $this->consistency = $consistency;
273
274
        return $this;
275
    }
276
277
    /**
278
     * @param string $bucket
279
     *
280
     * @return $this
281
     */
282
    public function bucket($bucket)
283
    {
284
        $this->bucket = $bucket;
285
286
        return $this;
287
    }
288
289
    /**
290
     * @param \CouchbaseN1qlQuery $query
291
     *
292
     * @return mixed
293
     */
294
    protected function executeQuery(\CouchbaseN1qlQuery $query)
295
    {
296
        $bucket = $this->openBucket($this->bucket);
297
        $this->registerOption($bucket);
298
        $this->firePreparedQuery($query);
299
        $result = $bucket->query($query);
300
        $this->fireReturning($result);
301
302
        return $result;
303
    }
304
305
    /**
306
     * {@inheritdoc}
307
     */
308
    public function select($query, $bindings = [], $useReadPdo = true)
309
    {
310
        return $this->run($query, $bindings, function ($me, $query, $bindings) {
311
            if ($me->pretending()) {
312
                return [];
313
            }
314
            $query = \CouchbaseN1qlQuery::fromString($query);
315
            $query->consistency($this->consistency);
316
            $query->positionalParams($bindings);
317
            $result = $this->executeQuery($query);
318
            $this->metrics = (isset($result->metrics)) ? $result->metrics : [];
319
320
            return (isset($result->rows)) ? $result->rows : [];
321
        });
322
    }
323
324
    /**
325
     * @param string $query
326
     * @param array  $bindings
327
     *
328
     * @return int|mixed
329
     */
330
    public function insert($query, $bindings = [])
331
    {
332
        return $this->affectingStatement($query, $bindings);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->affectingS...ent($query, $bindings); (integer) is incompatible with the return type declared by the interface Illuminate\Database\ConnectionInterface::insert of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
333
    }
334
335
    /**
336
     * {@inheritdoc}
337
     */
338 View Code Duplication
    public function affectingStatement($query, $bindings = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
339
    {
340
        return $this->run($query, $bindings, function ($me, $query, $bindings) {
341
            if ($me->pretending()) {
342
                return 0;
343
            }
344
            $query = \CouchbaseN1qlQuery::fromString($query);
345
            $query->consistency($this->consistency);
346
            $query->namedParams(['parameters' => $bindings]);
347
            $result = $this->executeQuery($query);
348
            $this->metrics = (isset($result->metrics)) ? $result->metrics : [];
349
350
            return (isset($result->rows[0])) ? $result->rows[0] : false;
351
        });
352
    }
353
354
    /**
355
     * @param       $query
356
     * @param array $bindings
357
     *
358
     * @return mixed
359
     */
360 View Code Duplication
    public function positionalStatement($query, array $bindings = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
361
    {
362
        return $this->run($query, $bindings, function ($me, $query, $bindings) {
363
            if ($me->pretending()) {
364
                return 0;
365
            }
366
            $query = \CouchbaseN1qlQuery::fromString($query);
367
            $query->consistency($this->consistency);
368
            $query->positionalParams($bindings);
369
            $result = $this->executeQuery($query);
370
            $this->metrics = (isset($result->metrics)) ? $result->metrics : [];
371
372
            return (isset($result->rows[0])) ? $result->rows[0] : false;
373
        });
374
    }
375
376
    /**
377
     * {@inheritdoc}
378
     */
379
    public function transaction(Closure $callback)
380
    {
381
        throw new NotSupportedException(__METHOD__);
382
    }
383
384
    /**
385
     * {@inheritdoc}
386
     */
387
    public function beginTransaction()
388 1
    {
389
        throw new NotSupportedException(__METHOD__);
390 1
    }
391
392
    /**
393
     * {@inheritdoc}
394
     */
395
    public function commit()
396 1
    {
397
        throw new NotSupportedException(__METHOD__);
398 1
    }
399
400
    /**
401
     * {@inheritdoc}
402
     */
403
    public function rollBack()
404 1
    {
405
        throw new NotSupportedException(__METHOD__);
406 1
    }
407
408
    /**
409
     * {@inheritdoc}
410
     */
411
    protected function reconnectIfMissingConnection()
412 1
    {
413
        if (is_null($this->connection)) {
414 1
            $this->reconnect();
415
        }
416
    }
417
418
    /**
419
     * {@inheritdoc}
420
     */
421
    public function disconnect()
422
    {
423
        $this->connection = null;
424
    }
425
426
    /**
427
     * @param CouchbaseBucket $bucket
428
     *
429
     * @return CouchbaseBucket
430
     */
431
    protected function enableN1ql(CouchbaseBucket $bucket)
432
    {
433
        if (!count($this->enableN1qlServers)) {
434
            return $bucket;
435
        }
436
        $bucket->enableN1ql($this->enableN1qlServers);
437
438
        return $bucket;
439
    }
440
441
    /**
442
     * N1QL upsert query.
443
     *
444
     * @param string $query
445
     * @param array  $bindings
446
     *
447
     * @return int
448
     */
449
    public function upsert($query, $bindings = [])
450
    {
451
        return $this->affectingStatement($query, $bindings);
452
    }
453
454
    /**
455
     * Get a new query builder instance.
456
     *
457
     * @return QueryBuilder
458
     */
459
    public function query()
460
    {
461
        return new QueryBuilder(
462
            $this, $this->getQueryGrammar(), $this->getPostProcessor()
463
        );
464
    }
465
466
    /**
467
     * @param string|null $bucket
468
     *
469
     * @return View
470
     */
471
    public function view($bucket = null)
472
    {
473
        $bucket = is_null($bucket) ? $this->bucket : $bucket;
474
475
        return new View($this->openBucket($bucket), $this->events);
476
    }
477
478
    /**
479
     * Run an update statement against the database.
480
     *
481
     * @param string $query
482
     * @param array  $bindings
483
     *
484
     * @return int|\stdClass
485
     */
486
    public function update($query, $bindings = [])
487
    {
488
        return $this->positionalStatement($query, $bindings);
489
    }
490
491
    /**
492
     * Run a delete statement against the database.
493
     *
494
     * @param string $query
495
     * @param array  $bindings
496
     *
497
     * @return int|\stdClass
498
     */
499
    public function delete($query, $bindings = [])
500
    {
501
        return $this->positionalStatement($query, $bindings);
502
    }
503
504
    /**
505
     * @return \string[]
506
     */
507
    public function metrics()
508
    {
509
        return $this->metrics;
510
    }
511
512
    /**
513
     * @param \CouchbaseN1qlQuery $queryObject
514
     */
515
    protected function firePreparedQuery(\CouchbaseN1qlQuery $queryObject)
516
    {
517
        if (isset($this->events)) {
518
            $this->events->fire(new QueryPrepared($queryObject));
519
        }
520
    }
521
522
    /**
523
     * @param mixed $returning
524
     */
525
    protected function fireReturning($returning)
526
    {
527
        if (isset($this->events)) {
528
            $this->events->fire(new ResultReturning($returning));
529
        }
530
    }
531
532
    /**
533
     * @param null|\PDO $pdo
534
     *
535
     * @return $this
536
     */
537
    public function setPdo($pdo)
538
    {
539
        $this->connection = $this->createConnection($this->config);
0 ignored issues
show
Unused Code introduced by
The call to CouchbaseConnection::createConnection() has too many arguments starting with $this->config.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
540
        $this->getManagedConfigure($this->config);
541
        $this->useDefaultQueryGrammar();
542
        $this->useDefaultPostProcessor();
543
        return $this;
544
    }
545
}
546