Skip to content

Navigation Menu

Sign in
Appearance settings
Sign up
Appearance settings

Commit 57c7290

Browse filesBrowse the repository at this point in the historyBrowse files
Merge branch '6.4' into 7.4
* 6.4: Add an agent skill for authoring pull requests [Translation] Read CSV translations without SplFileObject [Validator] Allow a literal # in the fragment part of Url [HttpFoundation] Declare create_sid() on session handlers [BrowserKit][HttpClient][Routing] Don't pass objects to http_build_query() [VarDumper] Don't call ArrayIterator::getFlags() nor ::setFlags() Use spl_object_id() instead of spl_object_hash() [PhpUnitBridge] Fix crash when a deprecation is triggered from a method inherited from an internal class [MonologBridge] Release command data in ConsoleCommandProcessor when the command terminates [Mailer] Reconnect after a timeout to avoid SMTP response desync # Conflicts: # .github/expected-missing-return-types.diff # src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php # src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php # src/Symfony/Component/Cache/Adapter/ProxyAdapter.php # src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php # src/Symfony/Component/Lock/Store/DoctrineDbalPostgreSqlStore.php # src/Symfony/Component/Lock/Store/PostgreSqlStore.php
2 parents 80757cf + 3737c4b commit 57c7290
Copy full SHA for 57c7290

46 files changed

+650-143Lines changed: 650 additions & 143 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree
Open diff view settings
Collapse file
+41Lines changed: 41 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
name: pr-authoring
3+
description: >
4+
Hold your own work to the review standard of this repository, so that a change
5+
is merge-ready when it is opened. Use when the user asks to fix an issue, to
6+
add a feature, to refactor, or to make any other change to this codebase, and
7+
read it before writing the first line of code.
8+
---
9+
10+
# Authoring a pull request
11+
12+
## Consult the review standard first
13+
14+
- Read `.agents/skills/pr-review-merge-prep/SKILL.md` in full before writing code. It states what a change must satisfy to be merged here.
15+
- That skill speaks from the reviewer's seat, and every requirement in it applies to the code you write yourself. A reviewer will hold your pull request to it, so hold your work to it first.
16+
- This skill only says when to consult the review skill and what to do with the answer. It repeats none of its rules. When the two seem to disagree, the review skill decides.
17+
18+
## Before writing code
19+
20+
- Choose the target branch before the first commit, with the branch rules of the review skill. The target decides which APIs the code may use, which test style it follows, and where the changelog entry goes. Changing it later means rewriting the change, not rebasing it.
21+
- Re-derive the problem from the code, whatever the issue or the request says it is. A report describes a symptom. Work from the cause you found yourself.
22+
- Reproduce the current behavior with a probe or a failing test before changing anything. A fix for a problem you never saw happen cannot be verified.
23+
- Run the public-API challenge of the review skill against your own design before you build it, not after. Dropping a method that is not needed costs nothing at that point. Defending one that is not justified costs a whole discussion later.
24+
25+
## While working
26+
27+
- Keep the diff to what the request needs. Unrelated cleanups make the change harder to review, and they can pull it toward another target branch. Report what you find outside that scope, or send it as its own pull request.
28+
- Apply the house rules of the review skill to everything you produce: tests first, comments, tone, attribution, order of methods, plain English.
29+
30+
## Before opening it
31+
32+
- Review your own diff with the review skill, as if someone else had written it. Run the checks it asks a reviewer to run: revert-verify each new test, probe the edge cases, check every borrowed symbol against the declared version constraints, check that the changelog and upgrade entries sit in the unreleased section, and run the full suite of every touched component together with the style tool.
33+
- Apply what that pass finds. Do not file the findings in the description as known limitations, because a reviewer reads them as work left undone.
34+
- Shape the commits before pushing: a message that matches its diff, and a structure that carries meaning, such as a failing test followed by the fix.
35+
- Write the description for someone who never saw the request: what the change does, the public API it adds, the options and their defaults, and the traps. Fill the header table, and give the title the component prefix.
36+
- Say which checks you ran and what they returned. State what you did not cover just as plainly.
37+
38+
## Opening it
39+
40+
- Opening a pull request, pushing to it and commenting on it are outward actions. Ask the user before the first one, unless they already asked for the pull request.
41+
- Push the branch to a fork. Never push a working branch to the upstream repository.
Collapse file

‎.github/deprecation-ignore‎

Copy file name to clipboardExpand all lines: .github/deprecation-ignore
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@
22
# These are vendor-internal: ORM has not yet migrated SchemaTool to the DBAL
33
# Schema/Table editor API. Symfony's own schema code already uses the editor API.
44
%^Doctrine\\DBAL\\Schema\\(Table|Schema)::\w+\(?\)? is deprecated%
5+
6+
# spl_object_hash() is deprecated as of PHP 8.6. Symfony's own code uses
7+
# spl_object_id() but some dependencies still call it: masterminds/html5,
8+
# doctrine/collections, doctrine/dbal and the sebastian/* packages that ship
9+
# with PHPUnit.
10+
%^Function spl_object_hash\(\) is deprecated%
Collapse file

‎.github/expected-missing-return-types.diff‎

Copy file name to clipboardExpand all lines: .github/expected-missing-return-types.diff
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,33 @@ diff --git a/src/Symfony/Component/Form/Test/TypeTestCase.php b/src/Symfony/Comp
397397
+ public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual): void
398398
{
399399
self::assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
400+
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php
401+
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php
402+
@@ -42,5 +42,5 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
403+
* @return string
404+
*/
405+
- public function create_sid()
406+
+ public function create_sid(): string
407+
{
408+
return session_create_id() ?: throw new \RuntimeException('Unable to create a session ID.');
409+
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php
410+
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php
411+
@@ -38,5 +38,5 @@ class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpd
412+
* @return string
413+
*/
414+
- public function create_sid()
415+
+ public function create_sid(): string
416+
{
417+
return session_create_id() ?: throw new \RuntimeException('Unable to create a session ID.');
418+
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php
419+
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php
420+
@@ -42,5 +42,5 @@ class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdat
421+
* @return string
422+
*/
423+
- public function create_sid()
424+
+ public function create_sid(): string
425+
{
426+
return session_create_id() ?: throw new \RuntimeException('Unable to create a session ID.');
400427
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
401428
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
402429
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
Collapse file

‎src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ private function getHash(string|object $listener): string
204204
return '_service_'.$listener;
205205
}
206206

207-
return spl_object_hash($listener);
207+
return spl_object_id($listener);
208208
}
209209

210210
private function getMethod(object $listener, string $event): string
Collapse file

‎src/Symfony/Bridge/Doctrine/Tests/TestRepositoryFactory.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/TestRepositoryFactory.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ private function createRepository(EntityManagerInterface $entityManager, string
4949

5050
private function getRepositoryHash(EntityManagerInterface $entityManager, string $entityName): string
5151
{
52-
return $entityManager->getClassMetadata($entityName)->getName().spl_object_hash($entityManager);
52+
return $entityManager->getClassMetadata($entityName)->getName()."\0".spl_object_id($entityManager);
5353
}
5454
}
Collapse file

‎src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php
+18-8Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626
final class ConsoleCommandProcessor implements EventSubscriberInterface, ResetInterface, ResettableInterface
2727
{
28-
private array $commandData;
28+
private array $commandDataStack = [];
2929

3030
public function __construct(
3131
private bool $includeArguments = true,
@@ -35,36 +35,46 @@ public function __construct(
3535

3636
public function __invoke(LogRecord $record): LogRecord
3737
{
38-
if (isset($this->commandData) && !isset($record->extra['command'])) {
39-
$record->extra['command'] = $this->commandData;
38+
if ($this->commandDataStack && !isset($record->extra['command'])) {
39+
$record->extra['command'] = $this->commandDataStack[array_key_last($this->commandDataStack)];
4040
}
4141

4242
return $record;
4343
}
4444

4545
public function reset(): void
4646
{
47-
// the command data is set once, on ConsoleEvents::COMMAND, and must outlive any reset
48-
// happening while the command is still running
47+
// the command data is set on ConsoleEvents::COMMAND and removed on ConsoleEvents::TERMINATE,
48+
// it must outlive any reset happening while a command is still running
4949
}
5050

5151
public function addCommandData(ConsoleEvent $event): void
5252
{
53-
$this->commandData = [
53+
$commandData = [
5454
'name' => $event->getCommand()->getName(),
5555
];
5656
if ($this->includeArguments) {
57-
$this->commandData['arguments'] = $event->getInput()->getArguments();
57+
$commandData['arguments'] = $event->getInput()->getArguments();
5858
}
5959
if ($this->includeOptions) {
60-
$this->commandData['options'] = $event->getInput()->getOptions();
60+
$commandData['options'] = $event->getInput()->getOptions();
6161
}
62+
63+
$this->commandDataStack[] = $commandData;
64+
}
65+
66+
public function removeCommandData(): void
67+
{
68+
array_pop($this->commandDataStack);
6269
}
6370

6471
public static function getSubscribedEvents(): array
6572
{
6673
return [
6774
ConsoleEvents::COMMAND => ['addCommandData', 1],
75+
// lower than ConsoleHandler::onTerminate() (-255) so that records logged
76+
// on ConsoleEvents::TERMINATE still carry the command information
77+
ConsoleEvents::TERMINATE => ['removeCommandData', -2048],
6878
];
6979
}
7080
}
Collapse file

‎src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php
+99-2Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Bridge\Monolog\Processor\ConsoleCommandProcessor;
1616
use Symfony\Bridge\Monolog\Tests\RecordFactory;
17+
use Symfony\Component\Console\Application;
1718
use Symfony\Component\Console\Command\Command;
19+
use Symfony\Component\Console\ConsoleEvents;
1820
use Symfony\Component\Console\Event\ConsoleEvent;
21+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
22+
use Symfony\Component\Console\Input\ArrayInput;
1923
use Symfony\Component\Console\Input\InputInterface;
2024
use Symfony\Component\Console\Output\NullOutput;
25+
use Symfony\Component\EventDispatcher\EventDispatcher;
2126

2227
class ConsoleCommandProcessorTest extends TestCase
2328
{
@@ -74,12 +79,104 @@ public function testCommandDataSurvivesReset()
7479
$this->assertSame(self::TEST_NAME, $record['extra']['command']['name']);
7580
}
7681

77-
private function getConsoleEvent(): ConsoleEvent
82+
public function testCommandDataIsRemovedWhenCommandTerminates()
83+
{
84+
$processor = new ConsoleCommandProcessor();
85+
$processor->addCommandData($this->getConsoleEvent());
86+
87+
$processor->removeCommandData();
88+
89+
$record = $processor(RecordFactory::create());
90+
$this->assertEquals([], $record['extra']);
91+
92+
$processor->removeCommandData();
93+
94+
$record = $processor(RecordFactory::create());
95+
$this->assertEquals([], $record['extra']);
96+
}
97+
98+
public function testCommandDataIsRestoredWhenNestedCommandTerminates()
99+
{
100+
$processor = new ConsoleCommandProcessor();
101+
$processor->addCommandData($this->getConsoleEvent());
102+
$processor->addCommandData($this->getConsoleEvent('some:nested'));
103+
104+
$record = $processor(RecordFactory::create());
105+
$this->assertSame('some:nested', $record['extra']['command']['name']);
106+
107+
$processor->removeCommandData();
108+
109+
$record = $processor(RecordFactory::create());
110+
$this->assertSame(self::TEST_NAME, $record['extra']['command']['name']);
111+
}
112+
113+
public function testCommandDataOfNestedCommandSurvivesReset()
114+
{
115+
$processor = new ConsoleCommandProcessor();
116+
$processor->addCommandData($this->getConsoleEvent());
117+
$processor->addCommandData($this->getConsoleEvent('some:nested'));
118+
119+
$processor->reset();
120+
121+
$record = $processor(RecordFactory::create());
122+
$this->assertSame('some:nested', $record['extra']['command']['name']);
123+
}
124+
125+
public function testCommandDataFollowsANestedCommandRun()
126+
{
127+
$processor = new ConsoleCommandProcessor();
128+
129+
$dispatcher = new EventDispatcher();
130+
$dispatcher->addSubscriber($processor);
131+
132+
$application = new Application();
133+
$application->setAutoExit(false);
134+
$application->setCatchExceptions(false);
135+
$application->setDispatcher($dispatcher);
136+
137+
$records = [];
138+
$capture = static function (string $key) use ($processor, &$records) {
139+
$records[$key] = $processor(RecordFactory::create());
140+
};
141+
142+
$dispatcher->addListener(ConsoleEvents::TERMINATE, static function (ConsoleTerminateEvent $event) use ($capture) {
143+
$capture('terminate of '.$event->getCommand()->getName());
144+
}, -255);
145+
146+
$nested = new Command('some:nested');
147+
$nested->setCode(static function () use ($capture) {
148+
$capture('inside the nested command');
149+
150+
return 0;
151+
});
152+
153+
$outer = new Command(self::TEST_NAME);
154+
$outer->setCode(static function () use ($application, $capture) {
155+
$capture('before the nested command');
156+
$application->run(new ArrayInput(['command' => 'some:nested']), new NullOutput());
157+
$capture('after the nested command');
158+
159+
return 0;
160+
});
161+
162+
$application->addCommands([$nested, $outer]);
163+
$application->run(new ArrayInput(['command' => self::TEST_NAME]), new NullOutput());
164+
$capture('after the outer command');
165+
166+
$this->assertSame(self::TEST_NAME, $records['before the nested command']['extra']['command']['name']);
167+
$this->assertSame('some:nested', $records['inside the nested command']['extra']['command']['name']);
168+
$this->assertSame('some:nested', $records['terminate of some:nested']['extra']['command']['name']);
169+
$this->assertSame(self::TEST_NAME, $records['after the nested command']['extra']['command']['name']);
170+
$this->assertSame(self::TEST_NAME, $records['terminate of '.self::TEST_NAME]['extra']['command']['name']);
171+
$this->assertSame([], $records['after the outer command']['extra']);
172+
}
173+
174+
private function getConsoleEvent(string $name = self::TEST_NAME): ConsoleEvent
78175
{
79176
$input = $this->createStub(InputInterface::class);
80177
$input->method('getArguments')->willReturn(self::TEST_ARGUMENTS);
81178
$input->method('getOptions')->willReturn(self::TEST_OPTIONS);
82-
$command = new Command(self::TEST_NAME);
179+
$command = new Command($name);
83180

84181
return new ConsoleEvent($command, $input, new NullOutput());
85182
}
Collapse file

‎src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
+14-3Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,24 @@ public function isLegacy(): bool
213213
}
214214

215215
$method = $this->originatingMethod();
216-
$groups = class_exists(Groups::class, false) ? [new Groups(), 'groups'] : [Test::class, 'getGroups'];
217216

218-
return str_starts_with($method, 'testLegacy')
217+
if (str_starts_with($method, 'testLegacy')
219218
|| str_starts_with($method, 'provideLegacy')
220219
|| str_starts_with($method, 'getLegacy')
221220
|| strpos($this->originClass, '\Legacy')
222-
|| \in_array('legacy', $groups($this->originClass, $method), true);
221+
) {
222+
return true;
223+
}
224+
225+
// The method can be inherited from an internal class, in which case it has no
226+
// doc block nor any file/line to read annotations or attributes from.
227+
if (!method_exists($this->originClass, $method) || (new \ReflectionMethod($this->originClass, $method))->isInternal()) {
228+
return false;
229+
}
230+
231+
$groups = class_exists(Groups::class, false) ? [new Groups(), 'groups'] : [Test::class, 'getGroups'];
232+
233+
return \in_array('legacy', $groups($this->originClass, $method), true);
223234
}
224235

225236
public function isMuted(): bool
Collapse file

‎src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ public function testLegacyTestMethodIsDetectedAsSuch()
7575
$this->assertTrue($deprecation->isLegacy('whatever'));
7676
}
7777

78+
public function testMethodInheritedFromAnInternalClassIsNotLegacy()
79+
{
80+
$object = new class extends \ArrayObject {
81+
};
82+
$deprecation = new Deprecation('💩', [
83+
[],
84+
[],
85+
[],
86+
['class' => \ArrayObject::class, 'function' => 'count', 'object' => $object, 'file' => __FILE__],
87+
], __FILE__);
88+
89+
$this->assertFalse($deprecation->isLegacy());
90+
}
91+
7892
public function testItCanBeConvertedToAString()
7993
{
8094
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
Collapse file

‎src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa
6868

6969
public function getCacheDir(): string
7070
{
71-
return sys_get_temp_dir().'/cache-'.spl_object_hash($this);
71+
return sys_get_temp_dir().'/cache-'.spl_object_id($this);
7272
}
7373

7474
public function getLogDir(): string
7575
{
76-
return sys_get_temp_dir().'/log-'.spl_object_hash($this);
76+
return sys_get_temp_dir().'/log-'.spl_object_id($this);
7777
}
7878

7979
protected function build(ContainerBuilder $container): void

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.