Completed
Push — m/0.6.0 ( ff4122 )
by
unknown
08:11 queued 05:23
created

Client::__construct()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.432

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 7
cts 10
cp 0.7
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 3
nop 2
crap 4.432
1
<?php
2
/**
3
 * Licensed to CRATE Technology GmbH("Crate") under one or more contributor
4
 * license agreements.  See the NOTICE file distributed with this work for
5
 * additional information regarding copyright ownership.  Crate licenses
6
 * this file to you under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.  You may
8
 * obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
15
 * License for the specific language governing permissions and limitations
16
 * under the License.
17
 *
18
 * However, if you have executed another commercial license agreement
19
 * with Crate these terms will supersede the license and you may use the
20
 * software solely pursuant to the terms of the relevant commercial agreement.
21
 */
22
23
namespace Crate\PDO\Http;
24
25
use Crate\PDO\Exception\RuntimeException;
26
use Crate\PDO\Exception\UnsupportedException;
27
use Crate\Stdlib\Collection;
28
use GuzzleHttp\Exception\BadResponseException;
29
use GuzzleHttp\Exception\ConnectException;
30
use GuzzleHttp\Exception\ParseException;
31
32
class Client implements ClientInterface
33
{
34
35
    const DEFAULT_SERVER = "localhost:4200";
36
37
    /**
38
     * @var array
39
     */
40
    private $availableServers = [];
41
42
    /**
43
     * @var array
44
     */
45
    private $serverPool = [];
46
47
    /**
48
     * Client constructor.
49
     * @param array $servers
50
     * @param array $options
51
     */
52 1
    public function __construct(array $servers, array $options)
53
    {
54 1
        if ($servers == null || count($servers) == 0) {
55
            $this->serverPool[self::DEFAULT_SERVER] = new Server(self::DEFAULT_SERVER, $options);
56
            $this->availableServers[] = self::DEFAULT_SERVER;
57
        } else {
58 1
            foreach ($servers as &$server) {
59 1
                $this->serverPool[$server] = new Server($server, $options);
60 1
                $this->availableServers[] = $server;
61 1
            }
62
        }
63 1
    }
64
65
    /**
66
     * {@Inheritdoc}
67
     */
68 2
    public function execute($query, array $parameters)
69
    {
70
        $body = [
71 2
            'stmt' => $query,
72
            'args' => $parameters
73 2
        ];
74
75 2
        while (true) {
76 2
            $nextServer = $this->nextServer();
77
            /**
78
             * @var Server $s
79
             */
80 2
            $s = $this->serverPool[$nextServer];
81
82
            try {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
83
84 2
                $response = $s->doRequest($body);
85 1
                $responseBody = json_decode($response->getBody(), true);
86
87 1
                return new Collection(
88 1
                    $responseBody['rows'],
89 1
                    $responseBody['cols'],
90 1
                    $responseBody['duration'],
91 1
                    $responseBody['rowcount']
92 1
                );
93
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
94 1
            } catch (ConnectException $exception) {
95
                // drop the server from the list of available servers
96
                $this->dropServer($nextServer);
97
                // break the loop if no more servers are available
98
                $this->raiseIfNoMoreServers($exception);
99 1
            } catch (BadResponseException $exception) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
100
101
                try {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
102
103 1
                    $json = json_decode($exception->getResponse()->getBody(), true);
104
105 1
                    $errorCode    = $json['error']['code'];
106 1
                    $errorMessage = $json['error']['message'];
107
108 1
                    throw new RuntimeException($errorMessage, $errorCode, $exception);
109
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
110 1
                } catch (ParseException $e) {
0 ignored issues
show
Bug introduced by
The class GuzzleHttp\Exception\ParseException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
111
                    throw new RuntimeException('Server returned non-JSON response.', 0, $exception);
112
                }
113
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
114
            }
115
        }
116
        return null;
117
    }
118
119
    /**
120
     * {@Inheritdoc}
121
     */
122
    public function getServerInfo()
123
    {
124
        return $this->getServerVersion();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getServerVersion(); of type Crate\Stdlib\Collection|null adds the type Crate\Stdlib\Collection to the return on line 124 which is incompatible with the return type declared by the interface Crate\PDO\Http\InternalC...nterface::getServerInfo of type array.
Loading history...
125
    }
126
127
    /**
128
     * {@Inheritdoc}
129
     */
130
    public function getServerVersion()
131
    {
132
        return $this->execute("select version['number'] from sys.nodes limit 1", []);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->execute('select v...des limit 1', array()); of type Crate\Stdlib\Collection|null adds the type Crate\Stdlib\Collection to the return on line 132 which is incompatible with the return type declared by the interface Crate\PDO\Http\InternalC...rface::getServerVersion of type string.
Loading history...
133
    }
134
135
    /**
136
     * {@Inheritdoc}
137
     */
138 1
    public function setTimeout($timeout)
139
    {
140 1
        foreach ($this->serverPool as $k => &$s) {
141
            /**
142
             * @var $s Server
143
             */
144 1
            $s->setTimeout($timeout);
145 1
        }
146 1
    }
147
148
    /**
149
     * {@Inheritdoc}
150
     */
151
    public function setHttpBasicAuth($username, $passwd)
152
    {
153
        foreach ($this->serverPool as $k => &$s) {
154
            /**
155
             * @var $s Server
156
             */
157
            $s->setHttpBasicAuth($username, $passwd);
158
        }
159
    }
160
161
    /**
162
     * {@Inheritdoc}
163
     */
164
    public function setHttpHeader($name, $value)
165
    {
166
        foreach ($this->serverPool as $k => &$s) {
167
            /**
168
             * @var $s Server
169
             */
170
            $s->setHttpHeader($name, $value);
171
        }
172
    }
173
174
    /**
175
     * {@Inheritdoc}
176
     */
177 1
    public function setDefaultSchema($schemaName)
178
    {
179 1
        $this->setHttpHeader("Default-Schema", $schemaName);
180 1
    }
181
182
    /**
183
     * @return string The next available server instance
184
     */
185 3
    private function nextServer()
186
    {
187 3
        $server = $this->availableServers[0];
188 3
        $this->roundRobin();
189 3
        return $server;
190
    }
191
192
    /**
193
     * Very simple round-robin implementation
194
     * Pops the first item of the availableServers array and appends it at the end.
195
     *
196
     * @return void
197
     */
198 3
    private function roundRobin()
199
    {
200
        /**
201
         * Performing round robin on the array only makes sense
202
         * if there are more than 1 available servers.
203
         */
204 3
        if (count($this->availableServers) > 1) {
205 1
            $this->availableServers[] = array_shift($this->availableServers);
206 1
        }
207 3
    }
208
209
    /**
210
     * @param string           $server
211
     */
212 2
    private function dropServer($server)
213
    {
214 2
        if (($idx = array_search($server, $this->availableServers)) !== false) {
215 2
            unset($this->availableServers[$idx]);
216 2
        }
217 2
    }
218
219
    /**
220
     * @param ConnectException $exception
221
     */
222 1
    private function raiseIfNoMoreServers($exception)
223
    {
224 1
        if (count($this->availableServers) == 0) {
225 1
            throw new ConnectException(
226 1
                "No more servers available, exception from last server: " . $exception->getMessage(),
227 1
                $exception->getRequest()
228 1
            );
229
        }
230
    }
231
}
232