Completed
Pull Request — master (#37)
by Eugene
03:00
created

Dsn::isTcp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Tarantool Client package.
7
 *
8
 * (c) Eugene Leonovich <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Tarantool\Client;
15
16
final class Dsn
17
{
18
    private $host;
19
    private $port;
20
    private $path;
21
    private $connectionUri;
22
    private $username;
23
    private $password;
24
    private $isTcp = false;
25
    private $options;
26
27 128
    private function __construct(string $connectionUri)
28
    {
29 128
        $this->connectionUri = $connectionUri;
30 128
    }
31
32 150
    public static function parse(string $dsn) : self
33
    {
34 150
        if (0 === \strpos($dsn, 'unix://') && isset($dsn[7])) {
35 58
            return self::parseUds($dsn);
36
        }
37
38 92
        if (false === $parsed = \parse_url($dsn)) {
39 4
            self::throwParseError($dsn);
40
        }
41 88
        if (!isset($parsed['scheme'], $parsed['host']) || 'tcp' !== $parsed['scheme']) {
42 16
            self::throwParseError($dsn);
43
        }
44 72
        if (isset($parsed['path']) && '/' !== $parsed['path']) {
45
            self::throwParseError($dsn);
46
        }
47
48 72
        $self = new self('tcp://'.$parsed['host'].':'.($parsed['port'] ?? '3301'));
49 72
        $self->host = $parsed['host'];
50 72
        $self->port = $parsed['port'] ?? 3301;
51 72
        $self->isTcp = true;
52
53 72
        if (isset($parsed['user'])) {
54 6
            $self->username = rawurldecode($parsed['user']);
55 6
            $self->password = isset($parsed['pass']) ? rawurldecode($parsed['pass']) : '';
56
        }
57
58 72
        if (isset($parsed['query'])) {
59 48
            \parse_str($parsed['query'], $self->options);
60
        }
61
62 72
        return $self;
63
    }
64
65 58
    private static function parseUds(string $dsn) : self
66
    {
67 58
        $parts = explode('@', substr($dsn, 7), 2);
68 58
        if (isset($parts[1])) {
69 8
            $parsed = \parse_url($parts[1]);
70 8
            $authority = explode(':', $parts[0]);
71
        } else {
72 50
            $parsed = \parse_url($parts[0]);
73
        }
74
75 58
        if (false === $parsed) {
76
            self::throwParseError($dsn);
77
        }
78 58
        if (isset($parsed['host'])) {
79 2
            self::throwParseError($dsn);
80
        }
81
82 56
        $self = new self('unix://'.$parsed['path']);
83 56
        $self->path = rawurldecode($parsed['path']);
84
85 56
        if (isset($authority)) {
86 8
            $self->username = rawurldecode($authority[0]);
87 8
            $self->password = isset($authority[1]) ? rawurldecode($authority[1]) : '';
88
        }
89 56
        if (isset($parsed['query'])) {
90 42
            \parse_str($parsed['query'], $self->options);
91
        }
92
93 56
        return $self;
94
    }
95
96 34
    public function getConnectionUri() : string
97
    {
98 34
        return $this->connectionUri;
99
    }
100
101 34
    public function getHost() : ?string
102
    {
103 34
        return $this->host;
104
    }
105
106 34
    public function getPort() : ?int
107
    {
108 34
        return $this->port;
109
    }
110
111 34
    public function getPath() : ?string
112
    {
113 34
        return $this->path;
114
    }
115
116 14
    public function getUsername() : ?string
117
    {
118 14
        return $this->username;
119
    }
120
121 14
    public function getPassword() : ?string
122
    {
123 14
        return $this->password;
124
    }
125
126
    public function isTcp() : bool
127
    {
128
        return $this->isTcp;
129
    }
130
131 22
    public function getString(string $name, ?string $default = null) : ?string
132
    {
133 22
        return $this->options[$name] ?? $default;
134
    }
135
136 42
    public function getBool(string $name, ?bool $default = null) : ?bool
137
    {
138 42
        if (!isset($this->options[$name])) {
139 6
            return $default;
140
        }
141
142 36
        if (null === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE)) {
143 8
            throw new \TypeError(sprintf('DSN option "%s" must be of the type bool.', $name));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with sprintf('DSN option "%s"...the type bool.', $name).

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...
144
        }
145
146 28
        return $value;
147
    }
148
149 30
    public function getInt(string $name, ?int $default = null) : ?int
150
    {
151 30
        if (!isset($this->options[$name])) {
152 6
            return $default;
153
        }
154
155 24
        if (null === $value = \filter_var($this->options[$name], \FILTER_VALIDATE_INT, \FILTER_NULL_ON_FAILURE)) {
156 16
            throw new \TypeError(sprintf('DSN option "%s" must be of the type int.', $name));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with sprintf('DSN option "%s"... the type int.', $name).

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...
157
        }
158
159 8
        return $value;
160
    }
161
162 22
    private static function throwParseError(string $dsn) : void
163
    {
164 22
        throw new \InvalidArgumentException(\sprintf('Unable to parse DSN "%s".', $dsn));
165
    }
166
}
167