Passed
Pull Request — master (#23)
by
unknown
15:03
created

Client::blockIP()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 9
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
namespace Sebdesign\ArtisanCloudflare;
4
5
use GuzzleHttp\Client as GuzzleClient;
6
use GuzzleHttp\Exception\ClientException;
7
use GuzzleHttp\Exception\RequestException;
8
use GuzzleHttp\Promise\Each;
9
use GuzzleHttp\Promise\PromiseInterface;
10
use Illuminate\Support\Collection;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Log\LoggerInterface;
13
14
class Client
15
{
16
    /**
17
     * Base URI.
18
     */
19
    const BASE_URI = 'https://api.cloudflare.com/client/v4/';
20
21
    /**
22
     * @var \GuzzleHttp\Client
23
     */
24
    protected $client;
25
26
    /**
27
     * @var \Psr\Log\LoggerInterface
28
     */
29
    protected $logger;
30
31
    /**
32
     * Constructor.
33
     */
34 51
    public function __construct(GuzzleClient $client, LoggerInterface $logger)
35
    {
36 51
        $this->client = $client;
37 51
        $this->logger = $logger;
38 17
    }
39
40
    /**
41
     * Delete all the given zones with their parameters.
42
     *
43
     * All the requests are asynchronous and sent concurrently.
44
     *
45
     * The promise waits until all the promises have been resolved or rejected
46
     * and returns the results of each request.
47
     *
48
     * @param  \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>  $zones
49
     * @return \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>
50
     */
51 39
    public function purge(Collection $zones): Collection
52
    {
53 26
        return $zones->map(function (Zone $zone, $identifier) {
54 39
            return $this->delete($identifier, $zone);
55 26
        })->pipe(function ($promises) {
56 39
            return $this->settle($promises);
57 39
        })->wait();
58
    }
59
60 39
    /**
61
     * Block the given IP address.
62 39
     * @param  \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>  $zones
63 39
     * @return \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>
64 26
     */
65
    public function blockIP($zones): Collection
66
    {
67
        return $zones->map(function (Zone $zone, $identifier) {
68
            return $this->client->postAsync("zones/{$identifier}/firewall/access_rules/rules", [
69
                \GuzzleHttp\RequestOptions::JSON => $zone,
70
            ]);
71
        })->pipe(function ($promises) {
72
            return $this->settle($promises);
73
        })->wait();
74
    }
75 39
76
    protected function delete(string $identifier, Zone $zone): PromiseInterface
77 39
    {
78
        return $this->client->deleteAsync("zones/{$identifier}/purge_cache", [
79 39
            \GuzzleHttp\RequestOptions::JSON => $zone,
80 39
        ]);
81 39
    }
82 39
83 26
    /**
84 39
     * Returns a promise that is fulfilled when all of the provided promises have
85 39
     * been fulfilled or rejected.
86
     *
87
     * The returned promise is fulfilled with a collection of results.
88
     *
89
     * @param  \Illuminate\Support\Collection<string,\GuzzleHttp\Promise\PromiseInterface>  $promises
90
     */
91
    protected function settle(Collection $promises): PromiseInterface
92
    {
93
        $results = new Collection();
94 39
95
        return Each::of(
96
            $promises->getIterator(),
97
            $this->onFulfilled($results),
98
            $this->onRejected($results)
99
        )->then(function () use ($results) {
100
            return $results;
101 26
        });
102 27
    }
103 39
104
    /**
105
     * Put the body of the fulfilled promise into the results.
106
     *
107
     * @param  \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>  $results
108
     * @return \Closure
109
     */
110
    protected function onFulfilled(Collection $results)
111
    {
112 39
        /*
113
         * @param  \Psr\Http\Message\ResponseInterface $response
114
         * @param  string                              $identifier
115
         * @return \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>
116
         */
117
        return function ($response, $identifier) use ($results) {
118
            return $results->put($identifier, $this->getBody($response));
119 26
        };
120 12
    }
121 12
122 12
    /**
123 8
     * Handle the rejected promise and put the errors into the results.
124
     *
125 12
     * @param  \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>  $results
126 39
     * @return \Closure
127
     */
128
    protected function onRejected(Collection $results)
129
    {
130
        /*
131
         * @param  \GuzzleHttp\Exception\RequestException $reason
132 12
         * @param  string                                 $identifier
133
         * @return \Illuminate\Support\Collection<string,\Sebdesign\ArtisanCloudflare\Zone>
134 12
         */
135
        return function ($reason, $identifier) use ($results) {
136 12
            $this->logger->error($reason->getMessage(), [
137
                'zone' => $identifier,
138 12
                'exception' => $reason,
139 6
            ]);
140
141
            return $results->put($identifier, $this->handleException($reason));
142 6
        };
143
    }
144 6
145
    /**
146
     * Transform a request exception into a result object.
147 6
     */
148 6
    protected function handleException(RequestException $e): Zone
149 4
    {
150 4
        if ($e->hasResponse()) {
151 6
            /** @var \Psr\Http\Message\ResponseInterface $response */
152 6
            $response = $e->getResponse();
153 4
154 4
            if ($e instanceof ClientException) {
155 4
                return $this->getBody($response);
156
            }
157
158
            $message = (string) $response->getBody();
159
        } else {
160
            $message = $e->getMessage();
161 33
        }
162
163 33
        return new Zone([
164
            'success' => false,
165
            'errors' => [
166
                [
167
                    'code' => $e->getCode(),
168
                    'message' => $message,
169 9
                ],
170
            ],
171 9
        ]);
172
    }
173
174
    /**
175
     * Transform the response body into a result object.
176
     */
177
    protected function getBody(ResponseInterface $response): Zone
178
    {
179
        return new Zone(json_decode($response->getBody(), true));
180
    }
181
182
    /**
183
     * Get the Guzzle client.
184
     */
185
    public function getClient(): GuzzleClient
186
    {
187
        return $this->client;
188
    }
189
}
190