Skip to content

Commit bfbf0e8

Browse files
Merge branch '5.4' into 6.0
* 5.4: cs fix [Messenger] Fix Doctrine transport on MySQL [Filesystem] Remove needless `mb_*` calls [Translator] Fix translator overlapse [Yaml] Improve test coverage in DumperTest and ParserTest Extract dispatching console signal handling and include subscribers [Mailer] Fix error message in case of an STMP error [HttpClient] Fix shared connections not being freed on PHP < 8 [HttpFoundation] Fix invalid ID not regenerated with native PHP file sessions [HttpClient] Fix memory leak when using StreamWrapper minor: fix test [Serializer] Fix error message remove the ChatterInterface alias when the chatter service is removed Bump Symfony version to 5.4.12 Update VERSION for 5.4.11 Update CHANGELOG for 5.4.11 Bump Symfony version to 4.4.45 Update VERSION for 4.4.44 Update CONTRIBUTORS for 4.4.44 Update CHANGELOG for 4.4.44
2 parents 09b8e50 + 7490104 commit bfbf0e8

File tree

2 files changed

+158
-38
lines changed

2 files changed

+158
-38
lines changed

Application.php

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -957,22 +957,31 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
957957
}
958958
}
959959

960-
if ($command instanceof SignalableCommandInterface && ($this->signalsToDispatchEvent || $command->getSubscribedSignals())) {
961-
if (!$this->signalRegistry) {
962-
throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
963-
}
960+
if ($this->signalsToDispatchEvent) {
961+
$commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];
962+
$dispatchSignals = $this->dispatcher && $this->dispatcher->hasListeners(ConsoleEvents::SIGNAL);
964963

965-
if (Terminal::hasSttyAvailable()) {
966-
$sttyMode = shell_exec('stty -g');
964+
if ($commandSignals || $dispatchSignals) {
965+
if (!$this->signalRegistry) {
966+
throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
967+
}
967968

968-
foreach ([\SIGINT, \SIGTERM] as $signal) {
969-
$this->signalRegistry->register($signal, static function () use ($sttyMode) {
970-
shell_exec('stty '.$sttyMode);
971-
});
969+
if (Terminal::hasSttyAvailable()) {
970+
$sttyMode = shell_exec('stty -g');
971+
972+
foreach ([\SIGINT, \SIGTERM] as $signal) {
973+
$this->signalRegistry->register($signal, static function () use ($sttyMode) {
974+
shell_exec('stty '.$sttyMode);
975+
});
976+
}
977+
}
978+
979+
foreach ($commandSignals as $signal) {
980+
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
972981
}
973982
}
974983

975-
if ($this->dispatcher) {
984+
if ($dispatchSignals) {
976985
foreach ($this->signalsToDispatchEvent as $signal) {
977986
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
978987

@@ -988,10 +997,6 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
988997
});
989998
}
990999
}
991-
992-
foreach ($command->getSubscribedSignals() as $signal) {
993-
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
994-
}
9951000
}
9961001

9971002
if (null === $this->dispatcher) {

Tests/ApplicationTest.php

Lines changed: 138 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
2222
use Symfony\Component\Console\Event\ConsoleCommandEvent;
2323
use Symfony\Component\Console\Event\ConsoleErrorEvent;
24+
use Symfony\Component\Console\Event\ConsoleSignalEvent;
2425
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
2526
use Symfony\Component\Console\Exception\CommandNotFoundException;
2627
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
@@ -42,6 +43,8 @@
4243
use Symfony\Component\Console\Tester\ApplicationTester;
4344
use Symfony\Component\DependencyInjection\ContainerBuilder;
4445
use Symfony\Component\EventDispatcher\EventDispatcher;
46+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
47+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
4548
use Symfony\Component\Process\Process;
4649

4750
class ApplicationTest extends TestCase
@@ -1862,39 +1865,107 @@ public function testCommandNameMismatchWithCommandLoaderKeyThrows()
18621865
/**
18631866
* @requires extension pcntl
18641867
*/
1865-
public function testSignal()
1868+
public function testSignalListenerNotCalledByDefault()
18661869
{
1867-
$command = new SignableCommand();
1870+
$command = new SignableCommand(false);
18681871

18691872
$dispatcherCalled = false;
18701873
$dispatcher = new EventDispatcher();
18711874
$dispatcher->addListener('console.signal', function () use (&$dispatcherCalled) {
18721875
$dispatcherCalled = true;
18731876
});
18741877

1875-
$application = new Application();
1876-
$application->setAutoExit(false);
1877-
$application->setDispatcher($dispatcher);
1878-
$application->setSignalsToDispatchEvent(\SIGALRM);
1879-
$application->add(new LazyCommand('signal', [], '', false, function () use ($command) { return $command; }, true));
1880-
1881-
$this->assertFalse($command->signaled);
1882-
$this->assertFalse($dispatcherCalled);
1878+
$application = $this->createSignalableApplication($command, $dispatcher);
18831879

18841880
$this->assertSame(0, $application->run(new ArrayInput(['signal'])));
18851881
$this->assertFalse($command->signaled);
18861882
$this->assertFalse($dispatcherCalled);
1883+
}
1884+
1885+
/**
1886+
* @requires extension pcntl
1887+
*/
1888+
public function testSignalListener()
1889+
{
1890+
$command = new SignableCommand();
1891+
1892+
$dispatcherCalled = false;
1893+
$dispatcher = new EventDispatcher();
1894+
$dispatcher->addListener('console.signal', function () use (&$dispatcherCalled) {
1895+
$dispatcherCalled = true;
1896+
});
1897+
1898+
$application = $this->createSignalableApplication($command, $dispatcher);
18871899

1888-
$command->loop = 100000;
1889-
pcntl_alarm(1);
18901900
$this->assertSame(1, $application->run(new ArrayInput(['signal'])));
1891-
$this->assertTrue($command->signaled);
18921901
$this->assertTrue($dispatcherCalled);
1902+
$this->assertTrue($command->signaled);
1903+
}
1904+
1905+
/**
1906+
* @requires extension pcntl
1907+
*/
1908+
public function testSignalSubscriberNotCalledByDefault()
1909+
{
1910+
$command = new BaseSignableCommand(false);
1911+
1912+
$subscriber = new SignalEventSubscriber();
1913+
$dispatcher = new EventDispatcher();
1914+
$dispatcher->addSubscriber($subscriber);
1915+
1916+
$application = $this->createSignalableApplication($command, $dispatcher);
1917+
1918+
$this->assertSame(0, $application->run(new ArrayInput(['signal'])));
1919+
$this->assertFalse($subscriber->signaled);
1920+
}
1921+
1922+
/**
1923+
* @requires extension pcntl
1924+
*/
1925+
public function testSignalSubscriber()
1926+
{
1927+
$command = new BaseSignableCommand();
1928+
1929+
$subscriber1 = new SignalEventSubscriber();
1930+
$subscriber2 = new SignalEventSubscriber();
1931+
1932+
$dispatcher = new EventDispatcher();
1933+
$dispatcher->addSubscriber($subscriber1);
1934+
$dispatcher->addSubscriber($subscriber2);
1935+
1936+
$application = $this->createSignalableApplication($command, $dispatcher);
1937+
1938+
$this->assertSame(1, $application->run(new ArrayInput(['signal'])));
1939+
$this->assertTrue($subscriber1->signaled);
1940+
$this->assertTrue($subscriber2->signaled);
1941+
}
1942+
1943+
/**
1944+
* @requires extension pcntl
1945+
*/
1946+
public function testSetSignalsToDispatchEvent()
1947+
{
1948+
$command = new BaseSignableCommand();
1949+
1950+
$subscriber = new SignalEventSubscriber();
1951+
1952+
$dispatcher = new EventDispatcher();
1953+
$dispatcher->addSubscriber($subscriber);
1954+
1955+
$application = $this->createSignalableApplication($command, $dispatcher);
1956+
$application->setSignalsToDispatchEvent(\SIGUSR2);
1957+
$this->assertSame(0, $application->run(new ArrayInput(['signal'])));
1958+
$this->assertFalse($subscriber->signaled);
1959+
1960+
$application = $this->createSignalableApplication($command, $dispatcher);
1961+
$application->setSignalsToDispatchEvent(\SIGUSR1);
1962+
$this->assertSame(1, $application->run(new ArrayInput(['signal'])));
1963+
$this->assertTrue($subscriber->signaled);
18931964
}
18941965

18951966
public function testSignalableCommandInterfaceWithoutSignals()
18961967
{
1897-
$command = new SignableCommand();
1968+
$command = new SignableCommand(false);
18981969

18991970
$dispatcher = new EventDispatcher();
19001971
$application = new Application();
@@ -1936,6 +2007,18 @@ public function testSignalableRestoresStty()
19362007

19372008
$this->assertSame($previousSttyMode, $sttyMode);
19382009
}
2010+
2011+
private function createSignalableApplication(Command $command, ?EventDispatcherInterface $dispatcher): Application
2012+
{
2013+
$application = new Application();
2014+
$application->setAutoExit(false);
2015+
if ($dispatcher) {
2016+
$application->setDispatcher($dispatcher);
2017+
}
2018+
$application->add(new LazyCommand('signal', [], '', false, function () use ($command) { return $command; }, true));
2019+
2020+
return $application;
2021+
}
19392022
}
19402023

19412024
class CustomApplication extends Application
@@ -1987,25 +2070,26 @@ public function isEnabled(): bool
19872070
}
19882071
}
19892072

1990-
class SignableCommand extends Command implements SignalableCommandInterface
2073+
class BaseSignableCommand extends Command
19912074
{
19922075
public $signaled = false;
1993-
public $loop = 100;
2076+
public $loop = 1000;
2077+
private $emitsSignal;
19942078

19952079
protected static $defaultName = 'signal';
19962080

1997-
public function getSubscribedSignals(): array
2081+
public function __construct(bool $emitsSignal = true)
19982082
{
1999-
return SignalRegistry::isSupported() ? [\SIGALRM] : [];
2000-
}
2001-
2002-
public function handleSignal(int $signal): void
2003-
{
2004-
$this->signaled = true;
2083+
parent::__construct();
2084+
$this->emitsSignal = $emitsSignal;
20052085
}
20062086

20072087
protected function execute(InputInterface $input, OutputInterface $output): int
20082088
{
2089+
if ($this->emitsSignal) {
2090+
posix_kill(posix_getpid(), SIGUSR1);
2091+
}
2092+
20092093
for ($i = 0; $i < $this->loop; ++$i) {
20102094
usleep(100);
20112095
if ($this->signaled) {
@@ -2016,3 +2100,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int
20162100
return 0;
20172101
}
20182102
}
2103+
2104+
class SignableCommand extends BaseSignableCommand implements SignalableCommandInterface
2105+
{
2106+
protected static $defaultName = 'signal';
2107+
2108+
public function getSubscribedSignals(): array
2109+
{
2110+
return SignalRegistry::isSupported() ? [\SIGUSR1] : [];
2111+
}
2112+
2113+
public function handleSignal(int $signal): void
2114+
{
2115+
$this->signaled = true;
2116+
}
2117+
}
2118+
2119+
class SignalEventSubscriber implements EventSubscriberInterface
2120+
{
2121+
public $signaled = false;
2122+
2123+
public function onSignal(ConsoleSignalEvent $event): void
2124+
{
2125+
$this->signaled = true;
2126+
$event->getCommand()->signaled = true;
2127+
}
2128+
2129+
public static function getSubscribedEvents(): array
2130+
{
2131+
return ['console.signal' => 'onSignal'];
2132+
}
2133+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy