Skip to content

Commit b39d3e9

Browse files
committed
[Console] Rework the signal integration
1 parent f99f774 commit b39d3e9

File tree

4 files changed

+62
-26
lines changed

4 files changed

+62
-26
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Console\Command\Command;
1515
use Symfony\Component\Console\Command\HelpCommand;
1616
use Symfony\Component\Console\Command\ListCommand;
17+
use Symfony\Component\Console\Command\SignalableCommandInterface;
1718
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
1819
use Symfony\Component\Console\Event\ConsoleCommandEvent;
1920
use Symfony\Component\Console\Event\ConsoleErrorEvent;
@@ -79,13 +80,15 @@ class Application implements ResetInterface
7980
private $singleCommand = false;
8081
private $initialized;
8182
private $signalRegistry;
83+
private $signalsToDispatchEvent = [SIGINT, SIGTERM, SIGUSR1, SIGUSR2];
8284

8385
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
8486
{
8587
$this->name = $name;
8688
$this->version = $version;
8789
$this->terminal = new Terminal();
8890
$this->defaultCommand = 'list';
91+
$this->signalRegistry = new SignalRegistry();
8992
}
9093

9194
/**
@@ -101,9 +104,14 @@ public function setCommandLoader(CommandLoaderInterface $commandLoader)
101104
$this->commandLoader = $commandLoader;
102105
}
103106

104-
public function setSignalRegistry(SignalRegistry $signalRegistry)
107+
public function getSignalRegistry(): SignalRegistry
105108
{
106-
$this->signalRegistry = $signalRegistry;
109+
return $this->signalRegistry;
110+
}
111+
112+
public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)
113+
{
114+
$this->signalsToDispatchEvent = $signalsToDispatchEvent;
107115
}
108116

109117
/**
@@ -268,14 +276,13 @@ public function doRun(InputInterface $input, OutputInterface $output)
268276
$command = $this->find($alternative);
269277
}
270278

271-
if ($this->signalRegistry) {
272-
foreach ($this->signalRegistry->getHandlingSignals() as $handlingSignal) {
273-
$event = new ConsoleSignalEvent($command, $input, $output, $handlingSignal);
274-
$onSignalHandler = function () use ($event) {
275-
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
276-
};
279+
if ($this->dispatcher) {
280+
foreach ($this->signalsToDispatchEvent as $signal) {
281+
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
277282

278-
$this->signalRegistry->register($handlingSignal, $onSignalHandler);
283+
$this->signalRegistry->register($signal, function () use ($event) {
284+
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
285+
});
279286
}
280287
}
281288

@@ -926,6 +933,12 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
926933
}
927934
}
928935

936+
if ($command instanceof SignalableCommandInterface) {
937+
foreach ($command->getSubscribedSignals() as $signal) {
938+
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
939+
}
940+
}
941+
929942
if (null === $this->dispatcher) {
930943
return $command->run($input, $output);
931944
}

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ CHANGELOG
77
* Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester`
88
* added support for multiline responses to questions through `Question::setMultiline()`
99
and `Question::isMultiline()`
10+
* Added `SignalRegistry` class to stack signals handlers
11+
* Added support for signals:
12+
* Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods
13+
* Added `SignalableCommandInterface` interface
1014

1115
5.1.0
1216
-----
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Command;
13+
14+
/**
15+
* Interface for command reacting to signal.
16+
*
17+
* @author Grégoire Pineau <lyrixx@lyrix.info>
18+
*/
19+
interface SignalableCommandInterface
20+
{
21+
/**
22+
* Returns the list of signals to subscribe.
23+
*/
24+
public function getSubscribedSignals(): array;
25+
26+
/**
27+
* The method will be called when the application is signaled.
28+
*/
29+
public function handleSignal(int $signal): void;
30+
}

src/Symfony/Component/Console/SignalRegistry/SignalRegistry.php

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
final class SignalRegistry
1515
{
16-
private $registeredSignals = [];
16+
private $signalHandlers = [];
1717

1818
private $handlingSignals = [];
1919

@@ -24,15 +24,16 @@ public function __construct()
2424

2525
public function register(int $signal, callable $signalHandler): void
2626
{
27-
if (!isset($this->registeredSignals[$signal])) {
27+
if (!isset($this->signalHandlers[$signal])) {
2828
$previousCallback = pcntl_signal_get_handler($signal);
2929

3030
if (\is_callable($previousCallback)) {
31-
$this->registeredSignals[$signal][] = $previousCallback;
31+
$this->signalHandlers[$signal][] = $previousCallback;
3232
}
3333
}
3434

35-
$this->registeredSignals[$signal][] = $signalHandler;
35+
$this->signalHandlers[$signal][] = $signalHandler;
36+
3637
pcntl_signal($signal, [$this, 'handle']);
3738
}
3839

@@ -41,20 +42,8 @@ public function register(int $signal, callable $signalHandler): void
4142
*/
4243
public function handle(int $signal): void
4344
{
44-
foreach ($this->registeredSignals[$signal] as $signalHandler) {
45+
foreach ($this->signalHandlers[$signal] as $signalHandler) {
4546
$signalHandler($signal);
4647
}
4748
}
48-
49-
public function addHandlingSignals(int ...$signals): void
50-
{
51-
foreach ($signals as $signal) {
52-
$this->handlingSignals[$signal] = true;
53-
}
54-
}
55-
56-
public function getHandlingSignals(): array
57-
{
58-
return array_keys($this->handlingSignals);
59-
}
6049
}

0 commit comments

Comments
 (0)