ApiConnection::getApiHost()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
4
namespace TomHart\Database\Database;
5
6
use GuzzleHttp\Client;
7
use Illuminate\Database\Connection;
8
use Illuminate\Database\Grammar;
9
use TomHart\Database\Database\Query\Grammars\ApiGrammar;
10
11
class ApiConnection extends Connection
12
{
13
14
    /**
15
     * Get the default query grammar instance.
16
     *
17
     * @return Grammar
18
     */
19
    protected function getDefaultQueryGrammar()
20
    {
21
        $grammar = app(ApiGrammar::class);
22
        if ($query = $this->getConfig('query')) {
23
            $grammar->setDefaultQueryString($query);
24
        }
25
        return $this->withTablePrefix($grammar);
26
    }
27
28
    /**
29
     * Return the host we should be connecting to.
30
     * @return string
31
     */
32
    private function getApiHost()
33
    {
34
        return $this->getDatabaseName();
35
    }
36
37
    /**
38
     * Extract what key in the response the data is held in (if applicable).
39
     * @param string $query
40
     * @return string|null
41
     */
42
    private function extractJsonKey(string &$query): ?string
43
    {
44
        preg_match('/@([a-zA-Z]+)/', $query, $matches);
45
        $match = array_shift($matches);
46
47
        if ($match) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $match of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
48
            $query = str_replace($match, '', $query);
49
            return $matches[0];
50
        }
51
52
        return 'data';
53
    }
54
55
    /**
56
     * @param string $query
57
     * @param mixed[] $bindings
58
     * @param bool $useReadPdo
59
     * @return mixed[]
60
     */
61
    public function select($query, $bindings = [], $useReadPdo = true)
62
    {
63
        return $this->run($query, $bindings, function ($query) {
64
            $key = $this->extractJsonKey($query);
65
66
            $url = $this->getApiHost() . $query;
67
68
            /** @var Client $client */
69
            $client = app(Client::class);
70
            $json = $this->getResponse($client, $url);
71
72
            if (!$key || !isset($json[$key])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
73
                return $json;
74
            }
75
76
            return $json[$key];
77
        });
78
    }
79
80
81
    /**
82
     * @param Client $client
83
     * @param string $url
84
     * @return mixed[]
85
     */
86
    private function getResponse(Client $client, string $url): array
87
    {
88
        $response = $client->request('GET', $url, [
89
            'headers' => config('api-database.headers')
90
        ]);
91
92
        $body = $response->getBody()->getContents();
93
        $json = \GuzzleHttp\json_decode($body, true);
94
95
        if ($this->isPaginatedResponse($json) && $json['current_page'] < $json['last_page']) {
96
            $json2 = $this->getResponse($client, $json['next_page_url']);
97
98
            $json['data'] = array_merge($json['data'], $json2['data']);
99
100
            return $json;
101
        }
102
103
        return $json;
104
    }
105
106
107
    /**
108
     * Is the JSON responses a paginatable one?
109
     * @param mixed[] $json
110
     * @return bool
111
     */
112
    private function isPaginatedResponse(array $json): bool
113
    {
114
        return empty(array_diff([
115
            'current_page',
116
            'data',
117
            'first_page_url',
118
            'from',
119
            'last_page',
120
            'last_page_url',
121
            'next_page_url',
122
            'path',
123
            'per_page',
124
            'prev_page_url',
125
            'to',
126
            'total'
127
        ], array_keys($json)));
128
    }
129
}
130