HttpAdapter::send()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 3
nop 0
dl 0
loc 26
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace JustSteveKing\Graph\Connection\Adapters\Neo4j\Http;
6
7
use RuntimeException;
8
use GuzzleHttp\Client;
9
use JustSteveKing\Graph\Connection\Adapters\AdapterInterface;
10
11
class HttpAdapter implements AdapterInterface
12
{
13
    /**
14
     * @var string
15
     */
16
    protected string $database = '';
17
18
    /**
19
     * @var Pipeline
20
     */
21
    protected Pipeline $pipeline;
22
23
    /**
24
     * @var Client
25
     */
26
    protected Client $client;
27
28
    /**
29
     * HttpAdapter constructor.
30
     * @param string $connectionString
31
     * @return void
32
     */
33
    protected function __construct(string $connectionString, ?string $database)
34
    {
35
        $uri = parse_url($connectionString);
36
37
        if (! is_null($database)) {
38
            $this->database = $database;
39
        }
40
41
        $this->pipeline = new Pipeline();
42
43
        $this->client = new Client([
44
            'base_uri' => $uri['scheme'] . '://' . $uri['host'] . ':' . $uri['port'],
45
            'timeout' => 3,
46
            'headers' => [
47
                'Accept' => 'application/json;charset=UTF-8',
48
                'Authorization' => 'Basic ' . base64_encode($uri['user'] . ':' . $uri['pass']),
49
                'Content-Type' => 'application/json'
50
            ]
51
        ]);
52
    }
53
54
    /**
55
     * Returns the alias name of the adapter
56
     *
57
     * @return string
58
     */
59
    public static function getName(): string
60
    {
61
        return 'neo-http';
62
    }
63
64
    /**
65
     * Builds the adapter using a connection string
66
     *
67
     * @param string $connectionString
68
     * @param string|null $database
69
     * @return static
70
     */
71
    public static function build(string $connectionString, ?string $database): self
72
    {
73
        $uri = parse_url($connectionString);
74
75
        if (! preg_match('/http(s?)/i', $uri['scheme'])) {
76
            $scheme = $uri['scheme'];
77
            throw new \RuntimeException("The HttpAdapter only accepts http or https schemes, you sent {$scheme}");
78
        }
79
80
        return new self($connectionString, $database);
81
    }
82
83
    /**
84
     * Send the request to the neo4j API
85
     *
86
     * @throws RuntimeException
87
     *
88
     * @return mixed
89
     */
90
    public function send()
91
    {
92
        if (empty($this->database)) {
93
            throw new RuntimeException(
94
                "no database has been selected to perform your queries on, please use the 'on(string \$database\)' method first"
95
            );
96
        }
97
        
98
        $request = $this->prepareStatements();
99
100
        try {
101
            $response = $this->client->request(
102
                'POST',
103
                "/db/$this->database/tx",
104
                [
105
                    'json' => json_decode($request)
106
                ]
107
            );
108
        } catch (\Exception $e) {
109
            throw new \RuntimeException($e->getMessage());
110
        }
111
112
        $this->database = '';
113
        $this->pipeline = new Pipeline();
114
115
        return json_decode((string) $response->getBody(), true);
116
    }
117
118
    /**
119
     * Set the database you want to query on
120
     *
121
     * @param string $database
122
     *
123
     * @return self
124
     */
125
    public function on(string $database): self
126
    {
127
        $this->database = $database;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Push a query onto the transaction pipeline
134
     *
135
     * @param string $query
136
     *
137
     * @return self
138
     */
139
    public function query(string $query): self
140
    {
141
        $this->pipeline->push($query);
142
143
        return $this;
144
    }
145
146
    /**
147
     * Prepare statements to be sent
148
     *
149
     * @return string
150
     */
151
    public function prepareStatements(): string
152
    {
153
        $statements = [];
154
155
        foreach ($this->pipeline->queries() as $statement) {
156
            $statement = [
157
                'statement' => $statement,
158
                'resultDataContents' => ['REST', 'GRAPH'],
159
                'includeStats' => true,
160
            ];
161
162
            $statements[] = $statement;
163
        }
164
165
        return json_encode([
166
            'statements' => $statements
167
        ]);
168
    }
169
170
    /**
171
     * A helper method for seeing if a database is selected
172
     *
173
     * @return string
174
     */
175
    public function getDatabase(): string
176
    {
177
        return $this->database;
178
    }
179
180
    /**
181
     * A helper method to work with the current Pipeline
182
     *
183
     * @return Pipeline
184
     */
185
    public function getPipeline(): Pipeline
186
    {
187
        return $this->pipeline;
188
    }
189
190
    /**
191
     * A helper method to work with the Guzzle Client for any reason.
192
     *
193
     * @return Client
194
     */
195
    public function getClient(): Client
196
    {
197
        return $this->client;
198
    }
199
200
    /**
201
     * A helper method mainly for testing purposes
202
     *
203
     * @return self
204
     */
205
    public function setClient(Client $client): self
206
    {
207
        $this->client = $client;
208
209
        return $this;
210
    }
211
}
212