MaintenanceCommand::getPayload()   A
last analyzed

Complexity

Conditions 4
Paths 8

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 4
eloc 17
c 3
b 0
f 0
nc 8
nop 0
dl 0
loc 25
rs 9.7
1
<?php
2
3
/**
4
 * Platine Framework
5
 *
6
 * Platine Framework is a lightweight, high-performance, simple and elegant
7
 * PHP Web framework
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine Framework
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file MaintenanceCommand.php
34
 *
35
 *  The Maintenance management command class
36
 *
37
 *  @package    Platine\Framework\Console\Command
38
 *  @author Platine Developers team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   https://www.platine-php.com
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Framework\Console\Command;
49
50
use Platine\Config\Config;
51
use Platine\Console\Command\Command;
52
use Platine\Framework\App\Application;
53
use RuntimeException;
54
use Throwable;
55
56
/**
57
 * @class MaintenanceCommand
58
 * @package Platine\Framework\Console\Command
59
 * @template T
60
 */
61
class MaintenanceCommand extends Command
62
{
63
    /**
64
     * Create new instance
65
     * @param Application $application
66
     * @param Config<T> $config
67
     */
68
    public function __construct(
69
        protected Application $application,
70
        protected Config $config
71
    ) {
72
73
74
        $this->setName('maintenance')
75
             ->setDescription('Command to manage application maintenance');
76
77
        $this->addArgument('type', 'type of action [up|down|status]', 'status', true, false, function ($val) {
78
            if (!in_array($val, ['up', 'down', 'status'])) {
79
                throw new RuntimeException(sprintf(
80
                    'Invalid argument type [%s], must be one of [up, down, status]',
81
                    $val
82
                ));
83
            }
84
85
             return $val;
86
        });
87
88
        $this->addOption(
89
            '-t|--template',
90
            'The template that should be rendered for display during maintenance mode',
91
            null,
92
            false,
93
        );
94
95
        $this->addOption(
96
            '-r|--retry',
97
            'The number of seconds after which the request may be retried',
98
            3600,
99
            false,
100
            false,
101
            function ($val) {
102
                if (strlen($val) > 0 && (!is_numeric($val) || (int) $val <= 0)) {
103
                    throw new RuntimeException(sprintf(
104
                        'Invalid retry value [%s], must be an integer greather than zero',
105
                        $val
106
                    ));
107
                }
108
109
                return $val;
110
            }
111
        );
112
        $this->addOption(
113
            '-e|--refresh',
114
            'The number of seconds after which the browser may refresh',
115
            3600,
116
            false,
117
            false,
118
            function ($val) {
119
                if (strlen($val) > 0 && (!is_numeric($val) || (int) $val <= 0)) {
120
                    throw new RuntimeException(sprintf(
121
                        'Invalid refresh value [%s], must be an integer greather than zero',
122
                        $val
123
                    ));
124
                }
125
126
                return $val;
127
            }
128
        );
129
        $this->addOption(
130
            '-s|--secret',
131
            'The secret phrase that may be used to bypass maintenance mode',
132
            null,
133
            false,
134
        );
135
136
        $this->addOption(
137
            '-c|--status',
138
            'The status code that should be used when returning the maintenance mode response',
139
            503,
140
            false,
141
            false,
142
            function ($val) {
143
                if (strlen($val) > 0 && (!is_numeric($val) || (int) $val < 200 || (int) $val > 505)) {
144
                    throw new RuntimeException(sprintf(
145
                        'Invalid HTTP status value [%s], must be between 200 and 505',
146
                        $val
147
                    ));
148
                }
149
150
                return $val;
151
            }
152
        );
153
        $this->addOption(
154
            '-m|--message',
155
            'The message that will be shown to user during maintenance mode',
156
            null,
157
            false,
158
        );
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164
    public function execute(): mixed
165
    {
166
        $type = $this->getArgumentValue('type');
167
168
        $io = $this->io();
169
        $writer = $io->writer();
170
        $writer->boldYellow('APPLICATION MAINTENANCE MANAGEMENT', true)->eol();
171
172
        if ($type === 'up') {
173
            $this->online();
174
        } elseif ($type === 'down') {
175
            $this->down();
176
        } else {
177
            $this->status();
178
        }
179
180
        return true;
181
    }
182
183
    /**
184
     * Put application online
185
     * @return void
186
     */
187
    public function online(): void
188
    {
189
        $writer = $this->io()->writer();
190
191
        try {
192
            if ($this->application->isInMaintenance() === false) {
193
                $writer->boldRed('Application already online')->eol();
194
                return;
195
            }
196
197
            $this->application->maintenance()->deactivate();
198
199
            $writer->boldGreen('Application is now online')->eol();
200
        } catch (Throwable $ex) {
201
            $writer->boldRed(sprintf(
202
                'Failed to disable maintenance mode: %s.',
203
                $ex->getMessage()
204
            ))->eol();
205
        }
206
    }
207
208
    /**
209
     * Put application in maintenance mode
210
     * @return void
211
     */
212
    public function down(): void
213
    {
214
        $writer = $this->io()->writer();
215
216
        try {
217
            if ($this->application->isInMaintenance()) {
218
                $writer->boldRed('Application is already down.')->eol();
219
                return;
220
            }
221
222
            $data = $this->getPayload();
223
            $this->application->maintenance()->activate($data);
224
225
            $writer->boldGreen('Application is now in maintenance mode.')->eol();
226
        } catch (Throwable $ex) {
227
            $writer->boldRed(sprintf(
228
                'Failed to enable maintenance mode: %s.',
229
                $ex->getMessage()
230
            ))->eol();
231
        }
232
    }
233
234
    /**
235
     * Check application maintenance mode
236
     * @return void
237
     */
238
    public function status(): void
239
    {
240
        $writer = $this->io()->writer();
241
242
        if ($this->application->isInMaintenance()) {
243
            $writer->boldYellow('Application is down.')->eol();
244
        } else {
245
            $writer->boldGreen('Application is online.')->eol();
246
        }
247
    }
248
249
    /**
250
     * Get the payload to be placed in the maintenance file.
251
     * @return array<string, mixed>
252
     */
253
    protected function getPayload(): array
254
    {
255
        $retry = $this->getOptionValue('retry') ?? 3600;
256
        if ($retry) {
257
            $retry = (int) $retry;
258
        }
259
260
        $refresh = $this->getOptionValue('refresh') ?? 3600;
261
        if ($refresh) {
262
            $refresh = (int) $refresh;
263
        }
264
265
        $status = $this->getOptionValue('status') ?? 503;
266
        if ($status) {
267
            $status = (int) $status;
268
        }
269
270
        return [
271
            'except' => $this->config->get('maintenance.url_whitelist', []),
272
            'template' => $this->getOptionValue('template'),
273
            'retry' => $retry,
274
            'refresh' => $refresh,
275
            'secret' => $this->getOptionValue('secret'),
276
            'status' => $status,
277
            'message' => $this->getOptionValue('message'),
278
        ];
279
    }
280
}
281