Completed
Push — master ( 19aa63...a831b2 )
by Sébastien
07:57
created

Purge::applyParameters()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 1
1
<?php
2
3
namespace Sebdesign\ArtisanCloudflare\Commands\Cache;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Collection;
7
use Sebdesign\ArtisanCloudflare\Client;
8
use Symfony\Component\Console\Helper\TableCell;
9
use Symfony\Component\HttpFoundation\ParameterBag;
10
use Symfony\Component\Console\Helper\TableSeparator;
11
12
class Purge extends Command
13
{
14
    /**
15
     * The name of the console command.
16
     *
17
     * @var string
18
     */
19
    protected $name = 'cloudflare:cache:purge';
20
21
    /**
22
     * The name and signature of the console command.
23
     *
24
     * @var string
25
     */
26
    protected $signature = 'cloudflare:cache:purge {zone? : A zone identifier.}
27
      {--file=* : One or more files that should be removed from the cache.}
28
      {--tag=* : One or more tags that should be removed from the cache.}
29
      {--host=* : One or more hosts that should be removed from the cache.}';
30
31
    /**
32
     * The name and signature of the console command.
33
     *
34
     * @var string
35
     */
36
    protected $description = 'Purge files/tags from CloudFlare\'s cache.';
37
38
    /**
39
     * CloudFlare API client.
40
     *
41
     * @var \Sebdesign\ArtisanCloudflare\Client
42
     */
43
    private $client;
44
45
    /**
46
     * API item identifier tags.
47
     *
48
     * @var \Illuminate\Support\Collection<string, \Symfony\Component\HttpFoundation\ParameterBag>
49
     */
50
    private $zones;
51
52
    /**
53
     * Purge constructor.
54
     *
55
     * @param \Sebdesign\ArtisanCloudflare\Client $client
56
     * @param array                               $zones
57
     */
58
    public function __construct(Client $client, array $zones)
59
    {
60
        parent::__construct();
61
62
        $this->client = $client;
63
64
        $this->zones = collect($zones)->map(function ($zone) {
65
            return new ParameterBag(array_filter($zone));
66
        });
67
    }
68
69
    /**
70
     * Execute the console command.
71
     *
72
     * @return int
73
     */
74
    public function handle()
75
    {
76
        $zones = $this->getZones();
77
78
        if ($zones->isEmpty()) {
79
            $this->error('Please supply a valid zone identifier in the input argument or the cloudflare config.');
80
81
            return 1;
82
        }
83
84
        $zones = $this->applyParameters($zones);
85
86
        $results = $this->purge($zones);
87
88
        $this->displayResults($zones, $results);
89
90
        return $this->getExitCode($results);
91
    }
92
93
    /**
94
     * Apply the paremeters for each zone.
95
     *
96
     * Use the config for each zone, unless options are passed in the command.
97
     *
98
     * @param  \Illuminate\Support\Collection<string, \Symfony\Component\HttpFoundation\ParameterBag> $zones
99
     * @return \Illuminate\Support\Collection<string, \Symfony\Component\HttpFoundation\ParameterBag>
0 ignored issues
show
Documentation introduced by
The doc-type \Illuminate\Support\Collection<string, could not be parsed: Expected "|" or "end of type", but got "<" at position 30. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
100
     */
101
    private function applyParameters(Collection $zones)
102
    {
103
        $defaults = array_filter([
104
            'files' => $this->option('file'),
105
            'tags' => $this->option('tag'),
106
            'hosts' => $this->option('host'),
107
        ]);
108
109
        if (empty($defaults)) {
110
            return $zones;
111
        }
112
113
        return $zones->each(function ($zone) use ($defaults) {
114
            $zone->replace($defaults);
115
        });
116
    }
117
118
    /**
119
     * Execute the purging operations and return each result.
120
     *
121
     * @param  \Illuminate\Support\Collection<string, \Symfony\Component\HttpFoundation\ParameterBag> $zones
122
     * @return \Illuminate\Support\Collection<string, object>
0 ignored issues
show
Documentation introduced by
The doc-type \Illuminate\Support\Collection<string, could not be parsed: Expected "|" or "end of type", but got "<" at position 30. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
123
     */
124
    private function purge(Collection $zones)
125
    {
126
        $parameters = $zones->map(function ($zone) {
127
            if ($zone->count()) {
128
                return $zone->all();
129
            }
130
131
            return ['purge_everything' => true];
132
        });
133
134
        $results = $this->client->purge($parameters);
135
136
        return $results->reorder($zones->keys());
137
    }
138
139
    /**
140
     * Display a table with the results.
141
     *
142
     * @param  \Illuminate\Support\Collection<string, \Symfony\Component\HttpFoundation\ParameterBag> $zones
143
     * @param  \Illuminate\Support\Collection<string, object> $results
144
     * @return void
145
     */
146
    private function displayResults(Collection $zones, Collection $results)
147
    {
148
        $headers = ['Status', 'Zone', 'Files', 'Tags', 'Hosts', 'Errors'];
149
150
        $title = [
151
            new TableCell(
152
                'The following zones have been purged from CloudFlare.',
153
                ['colspan' => count($headers)]
154
            ),
155
        ];
156
157
        // Get the status emoji
158
        $emoji = $results->pluck('success')->map(function ($success) {
159
            return $success ? '✅' : '❌';
160
        });
161
162
        // Get the zone identifiers
163
        $identifiers = $zones->keys();
164
165
        // Get the files as multiline strings
166
        $files = $zones->map(function ($zones) {
167
            return $this->formatItems($zones->get('files'));
168
        });
169
170
        // Get the tags as multiline strings
171
        $tags = $zones->map(function ($zones) {
172
            return $this->formatItems($zones->get('tags'));
173
        });
174
175
        // Get the hosts as multiline strings
176
        $hosts = $zones->map(function ($zones) {
177
            return $this->formatItems($zones->get('hosts'));
178
        });
179
180
        // Get the errors as red multiline strings
181
        $errors = $results->map(function ($result) {
182
            return $this->formatErrors($result->errors);
183
        })->map(function ($errors) {
184
            return $this->formatItems($errors);
185
        });
186
187
        $columns = collect([
188
            'status' => $emoji,
189
            'identifier' => $identifiers,
190
            'files' => $files,
191
            'tags' => $tags,
192
            'hosts' => $hosts,
193
            'errors' => $errors,
194
        ]);
195
196
        $rows = $columns->_transpose()->insertBetween(new TableSeparator());
197
198
        $this->table([$title, $headers], $rows);
199
    }
200
201
    /**
202
     * Format an array into a multiline string.
203
     *
204
     * @param  array|null  $items
205
     * @return string
206
     */
207
    private function formatItems(array $items = null)
208
    {
209
        return implode("\n", (array) $items);
210
    }
211
212
    /**
213
     * Format the errors.
214
     *
215
     * @param  object[] $errors
216
     * @return string[]
217
     */
218
    private function formatErrors(array $errors)
219
    {
220
        return array_map(function ($error) {
221
            if ($error->code) {
222
                return "<fg=red>{$error->code}: {$error->message}</>";
223
            }
224
225
            return "<fg=red>{$error->message}</>";
226
        }, $errors);
227
    }
228
229
    /**
230
     * Get the zone identifier from the input argument or the configuration.
231
     *
232
     * @return \Illuminate\Support\Collection<string, \Symfony\Component\HttpFoundation\ParameterBag>
0 ignored issues
show
Documentation introduced by
The doc-type \Illuminate\Support\Collection<string, could not be parsed: Expected "|" or "end of type", but got "<" at position 30. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
233
     */
234
    private function getZones()
235
    {
236
        if (! $zone = $this->argument('zone')) {
237
            return $this->zones;
238
        }
239
240
        $zones = $this->zones->only($zone);
241
242
        if ($zones->count()) {
243
            return $zones;
244
        }
245
246
        return collect([
247
            $zone => new ParameterBag(),
248
        ]);
249
    }
250
251
    /**
252
     * Return 1 if all successes are false, otherwise return 0.
253
     *
254
     * @param  \Illuminate\Support\Collection $results
255
     * @return int
256
     */
257
    private function getExitCode(Collection $results)
258
    {
259
        return (int) $results->pluck('success')->filter()->isEmpty();
260
    }
261
}
262