Completed
Pull Request — master (#1808)
by Tobias
05:20
created

ClientConfiguration::fromDsn()   B

Complexity

Conditions 9
Paths 12

Size

Total Lines 37

Duplication

Lines 11
Ratio 29.73 %

Importance

Changes 0
Metric Value
dl 11
loc 37
rs 7.7724
c 0
b 0
f 0
cc 9
nc 12
nop 1
1
<?php
2
3
namespace Elastica;
4
5
use Elastica\Exception\InvalidException;
6
use Nyholm\Dsn\Configuration\Url;
7
use Nyholm\Dsn\DsnParser;
8
use Nyholm\Dsn\Exception\ExceptionInterface as DsnException;
9
use Nyholm\Dsn\Exception\FunctionNotSupportedException;
10
11
/**
12
 * Elastica client configuration.
13
 *
14
 * @author Antoine Lamirault <[email protected]>
15
 */
16
class ClientConfiguration
17
{
18
    /**
19
     * Config with defaults.
20
     *
21
     * retryOnConflict: Use in \Elastica\Client::updateDocument
22
     * bigintConversion: Set to true to enable the JSON bigint to string conversion option (see issue #717)
23
     *
24
     * @var array
25
     */
26
    protected $configuration = [
27
        'host' => null,
28
        'port' => null,
29
        'path' => null,
30
        'url' => null,
31
        'proxy' => null,
32
        'transport' => null,
33
        'persistent' => true,
34
        'timeout' => null,
35
        'connections' => [], // host, port, path, transport, compression, persistent, timeout, username, password, auth_type, config -> (curl, headers, url)
36
        'roundRobin' => false,
37
        'retryOnConflict' => 0,
38
        'bigintConversion' => false,
39
        'username' => null,
40
        'password' => null,
41
        'auth_type' => null, //basic, digest, gssnegotiate, ntlm
42
    ];
43
44
    /**
45
     * Create configuration.
46
     *
47
     * @param array $config Additional config
48
     *
49
     * @return ClientConfiguration
50
     */
51
    public static function fromArray(array $config): self
52
    {
53
        $clientConfiguration = new static();
54
        foreach ($config as $key => $value) {
55
            $clientConfiguration->set($key, $value);
56
        }
57
58
        return $clientConfiguration;
59
    }
60
61
    /**
62
     * Create configuration from Dsn string. Example of valid DSN strings:
63
     * - http://localhost
64
     * - http://foo:bar@localhost:1234?timeout=4&persistant=false
65
     * - pool(http://127.0.0.1 http://127.0.0.2/bar?timeout=4)
66
     *
67
     * @return ClientConfiguration
68
     */
69
    public static function fromDsn(string $dsnString): self
70
    {
71
        try {
72
            $func = DsnParser::parseFunc($dsnString);
73
        } catch (DsnException $e) {
74
            throw new InvalidException(sprintf('DSN "%s" is invalid.', $dsnString), 0, $e);
75
        }
76
77
        if ($func->getName() == 'dsn') {
78
            /** @var Url $dsn */
79
            $dsn = $func->first();
80
            $clientConfiguration = self::fromArray(self::parseDsn($dsn));
81
        } elseif ($func->getName() == 'pool') {
82
            $connections = [];
83
            $clientConfiguration = new static();
84
            foreach ($func->getArguments() as $arg) {
85
                $connections[] = self::parseDsn($arg);
0 ignored issues
show
Documentation introduced by
$arg is of type object<Nyholm\Dsn\Config...\Dsn\Configuration\Dsn>, but the function expects a object<Nyholm\Dsn\Configuration\Url>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
86
            }
87
            $clientConfiguration->set('connections', $connections);
88
        } else {
89
            throw new FunctionNotSupportedException($dsnString, $func->getName());
90
        }
91
92 View Code Duplication
        foreach ($func->getParameters() as $optionName => $optionValue) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
93
            if ('false' === $optionValue) {
94
                $optionValue = false;
95
            } elseif ('true' === $optionValue) {
96
                $optionValue = true;
97
            } elseif (\is_numeric($optionValue)) {
98
                $optionValue = (int)$optionValue;
99
            }
100
101
            $clientConfiguration->set($optionName, $optionValue);
102
        }
103
104
        return $clientConfiguration;
105
    }
106
107
    private static function parseDsn(Url $dsn): array
108
    {
109
        $data = ['host' => $dsn->getHost(),];
110
111
        if (null !== $dsn->getScheme()) {
112
            $data['transport'] = $dsn->getScheme();
113
        }
114
115
        if (null !== $dsn->getUser()) {
116
            $data['username'] = $dsn->getUser();
117
        }
118
119
        if (null !== $dsn->getPassword()) {
120
            $data['password'] = $dsn->getPassword();
121
        }
122
123
        if (null !== $dsn->getUser() && null !== $dsn->getPassword()) {
124
            $data['auth_type'] = 'basic';
125
        }
126
127
        if (null !== $dsn->getPort()) {
128
            $data['port'] = $dsn->getPort();
129
        }
130
131
        if (null !== $dsn->getPath()) {
132
            $data['path'] = $dsn->getPath();
133
        }
134
135 View Code Duplication
        foreach ($dsn->getParameters() as $optionName => $optionValue) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
136
            if ('false' === $optionValue) {
137
                $optionValue = false;
138
            } elseif ('true' === $optionValue) {
139
                $optionValue = true;
140
            } elseif (\is_numeric($optionValue)) {
141
                $optionValue = (int) $optionValue;
142
            }
143
144
            $data[$optionName] = $optionValue;
145
        }
146
147
        return $data;
148
    }
149
150
    /**
151
     * Returns a specific config key or the whole config array if not set.
152
     *
153
     * @throws InvalidException if the given key is not found in the configuration
154
     *
155
     * @return mixed Config value
156
     */
157
    public function get(string $key)
158
    {
159
        if (empty($key)) {
160
            return $this->configuration;
161
        }
162
163
        if (!$this->has($key)) {
164
            throw new InvalidException('Config key is not set: '.$key);
165
        }
166
167
        return $this->configuration[$key];
168
    }
169
170
    /**
171
     * Returns boolean indicates if configuration has key.
172
     */
173
    public function has(string $key): bool
174
    {
175
        return \array_key_exists($key, $this->configuration);
176
    }
177
178
    /**
179
     * Return all configuration.
180
     */
181
    public function getAll(): array
182
    {
183
        return $this->configuration;
184
    }
185
186
    /**
187
     * @param string $key   Key to set
188
     * @param mixed  $value Value
189
     */
190
    public function set(string $key, $value): void
191
    {
192
        $this->configuration[$key] = $value;
193
    }
194
195
    /**
196
     * Add value to a key. If original value is not an array, value is wrapped.
197
     *
198
     * @param string $key   Key to add
199
     * @param mixed  $value Value
200
     */
201
    public function add(string $key, $value): void
202
    {
203
        if (!\array_key_exists($key, $this->configuration)) {
204
            $this->configuration[$key] = [$value];
205
        } else {
206
            if (\is_array($this->configuration[$key])) {
207
                $this->configuration[$key][] = $value;
208
            } else {
209
                $this->configuration[$key] = [$this->configuration[$key], $value];
210
            }
211
        }
212
    }
213
}
214