Skip to content

Commit 660ce12

Browse files
Merge branch '6.2' into 6.3
* 6.2: (21 commits) Fix tests CS fix [HttpKernel] Tests for DataCollector for #49320 [Console] Fix computing column width containing multibyte chars [Messenger] Fix deprecation layer of RedeliveryStamp [Mime] Form field values with integer keys not resolved correctly [Messenger] [Redis] Fixed problem where worker stops handling messages on first empty message [PHPUnitBridge] Fix PHPUnit 10.1 compatibility [VarDumper] Make the server TCP connection sync [Messenger] Fix warning message on failed messenger show command [Mailer] [Mailjet] Use body MessageID instead of X-MJ-Request-GUID [HttpFoundation] Fix BinaryFileResponse [Form] fix merge [HttpFoundation] Fix memory limit problems in BinaryFileResponse [PropertyAccess] Readonly properties must have no PropertyWriteInfo [Form] Cast choices value callback result to string [Serializer] Unexpected value should throw UnexpectedValueException [ErrorHandler] Don't throw deprecations for HttplugClient [Serializer] Fix denormalization of object with typed constructor arg (not castable) and with COLLECT_DENORMALIZATION_ERRORS ...
2 parents 3712d2e + 911d6a6 commit 660ce12

File tree

28 files changed

+473
-75
lines changed

28 files changed

+473
-75
lines changed

src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
namespace Symfony\Bridge\PhpUnit;
1313

1414
use PHPUnit\Framework\TestResult;
15+
use PHPUnit\Runner\ErrorHandler;
1516
use PHPUnit\Util\Error\Handler;
16-
use PHPUnit\Util\ErrorHandler;
17+
use PHPUnit\Util\ErrorHandler as UtilErrorHandler;
1718
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration;
1819
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
1920
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\DeprecationGroup;
@@ -75,7 +76,12 @@ public static function register($mode = 0)
7576
if (null !== $oldErrorHandler) {
7677
restore_error_handler();
7778

78-
if ($oldErrorHandler instanceof ErrorHandler || [ErrorHandler::class, 'handleError'] === $oldErrorHandler) {
79+
if (
80+
$oldErrorHandler instanceof UtilErrorHandler
81+
|| [UtilErrorHandler::class, 'handleError'] === $oldErrorHandler
82+
|| $oldErrorHandler instanceof ErrorHandler
83+
|| [ErrorHandler::class, 'handleError'] === $oldErrorHandler
84+
) {
7985
restore_error_handler();
8086
self::register($mode);
8187
}
@@ -359,6 +365,8 @@ private static function getPhpUnitErrorHandler(): callable
359365
if (!$eh = self::$errorHandler) {
360366
if (class_exists(Handler::class)) {
361367
$eh = self::$errorHandler = Handler::class;
368+
} elseif (method_exists(UtilErrorHandler::class, '__invoke')) {
369+
$eh = self::$errorHandler = UtilErrorHandler::class;
362370
} elseif (method_exists(ErrorHandler::class, '__invoke')) {
363371
$eh = self::$errorHandler = ErrorHandler::class;
364372
} else {

src/Symfony/Component/Console/Helper/Table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ private function calculateColumnsWidth(iterable $groups)
804804
$textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
805805
$textLength = Helper::width($textContent);
806806
if ($textLength > 0) {
807-
$contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
807+
$contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan()));
808808
foreach ($contentColumns as $position => $content) {
809809
$row[$i + $position] = $content;
810810
}

src/Symfony/Component/Console/Tests/Helper/TableTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ public static function renderProvider()
316316
],
317317
new TableSeparator(),
318318
[
319-
new TableCell('Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil!', ['colspan' => 3]),
319+
new TableCell('Cupìdĭtâte díctá âtquè pôrrò, tèmpórà exercitátìónèm mòdí ânìmí núllà nèmò vèl níhìl!', ['colspan' => 3]),
320320
],
321321
],
322322
'default',
@@ -333,7 +333,7 @@ public static function renderProvider()
333333
| 9971-5-0210-0 | A Tale of |
334334
| | Two Cities |
335335
+-------------------------------+-------------------------------+-----------------------------+
336-
| Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil! |
336+
| Cupìdĭtâte díctá âtquè pôrrò, tèmpórà exercitátìónèm mòdí ânìmí núllà nèmò vèl níhìl! |
337337
+-------------------------------+-------------------------------+-----------------------------+
338338

339339
TABLE

src/Symfony/Component/ErrorHandler/DebugClassLoader.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Prophecy\Prophecy\ProphecySubjectInterface;
2222
use ProxyManager\Proxy\ProxyInterface;
2323
use Symfony\Component\ErrorHandler\Internal\TentativeTypes;
24+
use Symfony\Component\HttpClient\HttplugClient;
2425
use Symfony\Component\VarExporter\LazyObjectInterface;
2526

2627
/**
@@ -421,7 +422,9 @@ public function checkAnnotations(\ReflectionClass $refl, string $class): array
421422
if (!isset(self::$checkedClasses[$use])) {
422423
$this->checkClass($use);
423424
}
424-
if (isset(self::$deprecated[$use]) && strncmp($vendor, str_replace('_', '\\', $use), $vendorLen) && !isset(self::$deprecated[$class])) {
425+
if (isset(self::$deprecated[$use]) && strncmp($vendor, str_replace('_', '\\', $use), $vendorLen) && !isset(self::$deprecated[$class])
426+
&& !(HttplugClient::class === $class && \in_array($use, [\Http\Message\RequestFactory::class, \Http\Message\StreamFactory::class, \Http\Message\UriFactory::class], true))
427+
) {
425428
$type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
426429
$verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
427430

src/Symfony/Component/Filesystem/Filesystem.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ private static function doRemove(array $files, bool $isRecursive): void
169169
}
170170
} elseif (is_dir($file)) {
171171
if (!$isRecursive) {
172-
$tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-.'));
172+
$tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-_'));
173173

174174
if (file_exists($tmpName)) {
175175
try {

src/Symfony/Component/Form/ChoiceList/Loader/AbstractChoiceLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function loadValuesForChoices(array $choices, callable $value = null): ar
4646

4747
if ($value) {
4848
// if a value callback exists, use it
49-
return array_map($value, $choices);
49+
return array_map(fn ($item) => (string) $value($item), $choices);
5050
}
5151

5252
return $this->doLoadValuesForChoices($choices);

src/Symfony/Component/Form/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ public function testLoadChoicesForValuesLoadsChoiceListOnFirstCall()
8686
);
8787
}
8888

89+
public function testLoadValuesForChoicesCastsCallbackItemsToString()
90+
{
91+
$choices = [
92+
(object) ['id' => 2],
93+
(object) ['id' => 3],
94+
];
95+
96+
$value = fn ($item) => $item->id;
97+
98+
$this->assertSame(['2', '3'], self::$loader->loadValuesForChoices($choices, $value));
99+
}
100+
89101
public function testLoadValuesForChoicesLoadsChoiceListOnFirstCall()
90102
{
91103
$this->assertSame(

src/Symfony/Component/HttpFoundation/BinaryFileResponse.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class BinaryFileResponse extends Response
3434
protected $offset = 0;
3535
protected $maxlen = -1;
3636
protected $deleteFileAfterSend = false;
37-
protected $chunkSize = 8 * 1024;
37+
protected $chunkSize = 16 * 1024;
3838

3939
/**
4040
* @param \SplFileInfo|string $file The file to stream
@@ -240,7 +240,7 @@ public function prepare(Request $request): static
240240
$range = $request->headers->get('Range');
241241

242242
if (str_starts_with($range, 'bytes=')) {
243-
[$start, $end] = explode('-', substr($range, 6), 2) + [0];
243+
[$start, $end] = explode('-', substr($range, 6), 2) + [1 => 0];
244244

245245
$end = ('' === $end) ? $fileSize - 1 : (int) $end;
246246

@@ -311,14 +311,21 @@ public function sendContent(): static
311311

312312
$length = $this->maxlen;
313313
while ($length && !feof($file)) {
314-
$read = ($length > $this->chunkSize) ? $this->chunkSize : $length;
315-
$length -= $read;
314+
$read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length;
316315

317-
stream_copy_to_stream($file, $out, $read);
318-
319-
if (connection_aborted()) {
316+
if (false === $data = fread($file, $read)) {
320317
break;
321318
}
319+
while ('' !== $data) {
320+
$read = fwrite($out, $data);
321+
if (false === $read || connection_aborted()) {
322+
break;
323+
}
324+
if (0 < $length) {
325+
$length -= $read;
326+
}
327+
$data = substr($data, $read);
328+
}
322329
}
323330

324331
fclose($out);

src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch
3131
{
3232
$this->kernel = $kernel;
3333
$this->stopwatch = $stopwatch;
34+
$this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];
3435
}
3536

3637
public function collect(Request $request, Response $response, \Throwable $exception = null): void
@@ -51,7 +52,7 @@ public function collect(Request $request, Response $response, \Throwable $except
5152

5253
public function reset(): void
5354
{
54-
$this->data = [];
55+
$this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];
5556

5657
$this->stopwatch?->reset();
5758
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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\HttpKernel\Tests\DataCollector;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\RedirectResponse;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\HttpKernel\DataCollector\RouterDataCollector;
19+
use Symfony\Component\HttpKernel\Event\ControllerEvent;
20+
use Symfony\Component\HttpKernel\KernelInterface;
21+
22+
class RouterDataCollectorTest extends TestCase
23+
{
24+
public function testRouteRedirectResponse()
25+
{
26+
$collector = new RouterDataCollector();
27+
28+
$request = Request::create('http://test.com/foo?bar=baz');
29+
$response = new RedirectResponse('http://test.com/redirect');
30+
31+
$event = $this->createControllerEvent($request);
32+
33+
$collector->onKernelController($event);
34+
$collector->collect($request, $response);
35+
36+
$this->assertTrue($collector->getRedirect());
37+
$this->assertEquals('http://test.com/redirect', $collector->getTargetUrl());
38+
$this->assertEquals('n/a', $collector->getTargetRoute());
39+
}
40+
41+
public function testRouteNotRedirectResponse()
42+
{
43+
$collector = new RouterDataCollector();
44+
45+
$request = Request::create('http://test.com/foo?bar=baz');
46+
$response = new Response('test');
47+
48+
$event = $this->createControllerEvent($request);
49+
50+
$collector->onKernelController($event);
51+
$collector->collect($request, $response);
52+
53+
$this->assertFalse($collector->getRedirect());
54+
$this->assertNull($collector->getTargetUrl());
55+
$this->assertNull($collector->getTargetRoute());
56+
}
57+
58+
public function testReset()
59+
{
60+
$collector = new RouterDataCollector();
61+
62+
// Fill Collector
63+
$request = Request::create('http://test.com/foo?bar=baz');
64+
$response = new RedirectResponse('http://test.com/redirect');
65+
$event = $this->createControllerEvent($request);
66+
$collector->onKernelController($event);
67+
$collector->collect($request, $response);
68+
69+
$collector->reset();
70+
71+
$this->assertFalse($collector->getRedirect());
72+
$this->assertNull($collector->getTargetUrl());
73+
$this->assertNull($collector->getTargetRoute());
74+
}
75+
76+
public function testGetName()
77+
{
78+
$collector = new RouterDataCollector();
79+
80+
$this->assertEquals('router', $collector->getName());
81+
}
82+
83+
protected function createControllerEvent(Request $request): ControllerEvent
84+
{
85+
$kernel = $this->createMock(KernelInterface::class);
86+
87+
return new ControllerEvent($kernel, function () {}, $request, null);
88+
}
89+
}

src/Symfony/Component/HttpKernel/Tests/DataCollector/TimeDataCollectorTest.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
1818
use Symfony\Component\HttpKernel\KernelInterface;
1919
use Symfony\Component\Stopwatch\Stopwatch;
20+
use Symfony\Component\Stopwatch\StopwatchEvent;
2021

2122
/**
2223
* @group time-sensitive
@@ -55,4 +56,104 @@ public function testCollect()
5556
$this->assertEquals(123456000, $c->getStartTime());
5657
$this->assertSame(class_exists(Stopwatch::class, false), $c->isStopwatchInstalled());
5758
}
59+
60+
public function testReset()
61+
{
62+
$collector = new TimeDataCollector();
63+
64+
// Fill Collector
65+
$request = Request::create('http://test.com/foo?bar=baz');
66+
$response = new Response('test');
67+
$collector->collect($request, $response);
68+
69+
$collector->reset();
70+
71+
$this->assertEquals([], $collector->getEvents());
72+
$this->assertEquals(0, $collector->getStartTime());
73+
$this->assertFalse($collector->isStopwatchInstalled());
74+
}
75+
76+
public function testLateCollect()
77+
{
78+
$stopwatch = new Stopwatch();
79+
$stopwatch->start('test');
80+
81+
$collector = new TimeDataCollector(null, $stopwatch);
82+
83+
$request = new Request();
84+
$request->attributes->set('_stopwatch_token', '__root__');
85+
86+
$collector->collect($request, new Response());
87+
$collector->lateCollect();
88+
89+
$this->assertEquals(['test'], array_keys($collector->getEvents()));
90+
}
91+
92+
public function testSetEvents()
93+
{
94+
$collector = new TimeDataCollector();
95+
96+
$event = $this->createMock(StopwatchEvent::class);
97+
$event->expects($this->once())->method('ensureStopped');
98+
99+
$events = [$event];
100+
101+
$collector->setEvents($events);
102+
103+
$this->assertCount(1, $collector->getEvents());
104+
}
105+
106+
public function testGetDurationHasEvents()
107+
{
108+
$collector = new TimeDataCollector();
109+
110+
$request = new Request();
111+
$request->server->set('REQUEST_TIME_FLOAT', 1);
112+
$collector->collect($request, new Response());
113+
114+
$event = $this->createMock(StopwatchEvent::class);
115+
$event->expects($this->once())->method('getDuration')->willReturn(2000.0);
116+
$event->expects($this->once())->method('getOrigin')->willReturn(1000.0);
117+
$events = ['__section__' => $event];
118+
$collector->setEvents($events);
119+
120+
$this->assertEquals(1000 + 2000 - 1000, $collector->getDuration());
121+
}
122+
123+
public function testGetDurationNotEvents()
124+
{
125+
$collector = new TimeDataCollector();
126+
127+
$this->assertEquals(0, $collector->getDuration());
128+
}
129+
130+
public function testGetInitTimeNotEvents()
131+
{
132+
$collector = new TimeDataCollector();
133+
134+
$this->assertEquals(0, $collector->getInitTime());
135+
}
136+
137+
public function testGetInitTimeHasEvents()
138+
{
139+
$collector = new TimeDataCollector();
140+
141+
$request = new Request();
142+
$request->server->set('REQUEST_TIME_FLOAT', 1);
143+
$collector->collect($request, new Response());
144+
145+
$event = $this->createMock(StopwatchEvent::class);
146+
$event->expects($this->once())->method('getOrigin')->willReturn(2000.0);
147+
$events = ['__section__' => $event];
148+
$collector->setEvents($events);
149+
150+
$this->assertEquals(2000 - 1000, $collector->getInitTime());
151+
}
152+
153+
public function testGetName()
154+
{
155+
$collector = new TimeDataCollector();
156+
157+
$this->assertEquals('time', $collector->getName());
158+
}
58159
}

0 commit comments

Comments
 (0)