Passed
Push — master ( abd2be...1dc290 )
by BENOIT
02:33
created

ServeCommand::configure()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 74
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 61
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 74
ccs 0
cts 62
cp 0
crap 2
rs 8.8509

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace BenTools\MercurePHP\Command;
4
5
use BenTools\MercurePHP\Configuration\Configuration;
6
use BenTools\MercurePHP\Hub\HubFactory;
7
use Psr\Log\LoggerInterface;
8
use Psr\Log\LogLevel;
9
use React\EventLoop\Factory;
10
use React\EventLoop\LoopInterface;
11
use Symfony\Component\Console\Command\Command;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Logger\ConsoleLogger;
15
use Symfony\Component\Console\Output\OutputInterface;
16
use Symfony\Component\Console\Style\SymfonyStyle;
17
18
use function BenTools\MercurePHP\nullify;
19
20
final class ServeCommand extends Command
21
{
22
    protected static $defaultName = 'mercure:serve';
23
24
    private LoopInterface $loop;
25
    private ?LoggerInterface $logger;
26
27
    public function __construct(?LoopInterface $loop = null, ?LoggerInterface $logger = null)
28
    {
29
        parent::__construct();
30
        $this->loop = $loop ?? Factory::create();
31
        $this->logger = $logger;
32
    }
33
34
    protected function execute(InputInterface $input, OutputInterface $output): int
35
    {
36
        $loop = $this->loop;
37
        $output = new SymfonyStyle($input, $output);
38
        $logger = $this->logger ?? new ConsoleLogger($output, [LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL]);
39
        try {
40
            $config = (new Configuration())
41
                ->overrideWith($_SERVER)
42
                ->overrideWith($this->getInputOptions($input))
43
                ->asArray();
44
45
            $loop->futureTick(function () use ($config, $output) {
46
                $this->displayConfiguration($config, $output);
47
            });
48
49
            $hub = (new HubFactory($config, $logger))->create($loop);
50
            $hub->run($loop);
51
52
            if (\SIGINT === $hub->getShutdownSignal()) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $hub->getShutdownSignal() targeting BenTools\MercurePHP\Hub\Hub::getShutdownSignal() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
introduced by
The condition SIGINT === $hub->getShutdownSignal() is always false.
Loading history...
53
                $output->newLine(2);
54
                $output->writeln('SIGINT received. 😢');
55
                $output->writeln('Goodbye! 👋');
56
57
                return 0;
58
            }
59
60
            $output->error('Server process was killed unexpectedly.');
61
62
            return 1;
63
        } catch (\Exception $e) {
64
            $output->error($e->getMessage());
65
66
            return 1;
67
        }
68
    }
69
70
    protected function configure(): void
71
    {
72
        $this->setDescription('Runs the Mercure Hub as a standalone application.');
73
        $this->addOption(
74
            'addr',
75
            null,
76
            InputOption::VALUE_OPTIONAL,
77
            'The address to listen on.',
78
        )
79
        ->addOption(
80
            'transport-url',
81
            null,
82
            InputOption::VALUE_OPTIONAL,
83
            'The DSN to transport messages.',
84
        )
85
        ->addOption(
86
            'storage-url',
87
            null,
88
            InputOption::VALUE_OPTIONAL,
89
            'The DSN to store messages.',
90
        )
91
        ->addOption(
92
            'metrics-url',
93
            null,
94
            InputOption::VALUE_OPTIONAL,
95
            'The DSN to store metrics.',
96
        )
97
        ->addOption(
98
            'cors-allowed-origins',
99
            null,
100
            InputOption::VALUE_OPTIONAL,
101
            'A list of allowed CORS origins, can be * for all.',
102
        )
103
        ->addOption(
104
            'jwt-key',
105
            null,
106
            InputOption::VALUE_OPTIONAL,
107
            'The JWT key to use for both publishers and subscribers',
108
        )
109
        ->addOption(
110
            'jwt-algorithm',
111
            null,
112
            InputOption::VALUE_OPTIONAL,
113
            'The JWT verification algorithm to use for both publishers and subscribers, e.g. HS256 (default) or RS512.',
114
        )
115
        ->addOption(
116
            'publisher-jwt-key',
117
            null,
118
            InputOption::VALUE_OPTIONAL,
119
            'Must contain the secret key to valid publishers\' JWT, can be omitted if jwt_key is set.',
120
        )
121
        ->addOption(
122
            'publisher-jwt-algorithm',
123
            null,
124
            InputOption::VALUE_OPTIONAL,
125
            'The JWT verification algorithm to use for publishers, e.g. HS256 (default) or RS512.',
126
        )
127
        ->addOption(
128
            'subscriber-jwt-key',
129
            null,
130
            InputOption::VALUE_OPTIONAL,
131
            'Must contain the secret key to valid subscribers\' JWT, can be omitted if jwt_key is set.',
132
        )
133
        ->addOption(
134
            'subscriber-jwt-algorithm',
135
            null,
136
            InputOption::VALUE_OPTIONAL,
137
            'The JWT verification algorithm to use for subscribers, e.g. HS256 (default) or RS512.',
138
        )
139
        ->addOption(
140
            'allow-anonymous',
141
            null,
142
            InputOption::VALUE_NONE,
143
            'Allows subscribers with no valid JWT to connect.',
144
        );
145
    }
146
147
    private function displayConfiguration(array $config, SymfonyStyle $output): void
148
    {
149
        if (!$output->isVeryVerbose()) {
150
            return;
151
        }
152
153
        $rows = [];
154
        foreach ($config as $key => $value) {
155
            if (null === $value) {
156
                $value = '<fg=yellow>null</>';
157
            }
158
            if (\is_bool($value)) {
159
                $value = $value ? '<fg=green>true</>' : '<fg=red>false</>';
160
            }
161
            $rows[] = [$key, $value];
162
        }
163
164
        $output->table(['Key', 'Value'], $rows);
165
    }
166
167
    private function getInputOptions(InputInterface $input): array
168
    {
169
        return \array_filter(
170
            $input->getOptions(),
171
            fn($value) => null !== nullify($value) && false !== $value
172
        );
173
    }
174
}
175