8000 Merge branch '4.4' into 5.4 · Trismegiste/symfony@e6f392a · GitHub
[go: up one dir, main page]

Skip to content

Commit e6f392a

Browse files
Merge branch '4.4' into 5.4
* 4.4: Fix composer on appveyor [PropertyAccess] Fix typo in PropertyAccessor::readProperty() DocBlock [VarExporter] Fix exporting objects with readonly properties [ExpressionLanguage] Fix matches when the regexp is not valid [Messenger] Add mysql indexes back and work around deadlocks using soft-delete [Validator] Fix File constraint invalid max size exception message [Console] Fix exit status on uncaught exception with negative code
2 parents 8352e29 + 8016293 commit e6f392a

File tree

14 files changed

+159
-73
lines changed

14 files changed

+159
-73
lines changed

.appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ install:
4848
- echo extension=php_sodium.dll >> php.ini-max
4949
- copy /Y php.ini-max php.ini
5050
- cd c:\projects\symfony
51-
- IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/2.0.0/composer.phar)
51+
- IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/2.2.10/composer.phar)
5252
- php composer.phar self-update --2
5353
- copy /Y .github\composer-config.json %APPDATA%\Composer\config.json
5454
- git config --global user.email ""

src/Symfony/Component/Console/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null
179179
$exitCode = $e->getCode();
180180
if (is_numeric($exitCode)) {
181181
$exitCode = (int) $exitCode;
182-
if (0 === $exitCode) {
182+
if ($exitCode <= 0) {
183183
$exitCode = 1;
184184
}
185185
} else {

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,25 @@ public function testRunDispatchesExitCodeOneForExceptionCodeZero()
11721172
$this->assertTrue($passedRightValue, '-> exit code 1 was passed in the console.terminate event');
11731173
}
11741174

1175+
/**
1176+
* @testWith [-1]
1177+
* [-32000]
1178+
*/
1179+
public function testRunReturnsExitCodeOneForNegativeExceptionCode($exceptionCode)
1180+
{
1181+
$exception = new \Exception('', $exceptionCode);
1182+
1183+
$application = $this->getMockBuilder(Application::class)->setMethods(['doRun'])->getMock();
1184+
$application->setAutoExit(false);
1185+
$application->expects($this->once())
1186+
->method('doRun')
1187+
->willThrowException($exception);
1188+
1189+
$exitCode = $application->run(new ArrayInput([]), new NullOutput());
1190+
1191+
$this->assertSame(1, $exitCode, '->run() returns exit code 1 when exception code is '.$exceptionCode);
1192+
}
1193+
11751194
public function testAddingOptionWithDuplicateShortcut()
11761195
{
11771196
$this->expectException(\LogicException::class);

src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\ExpressionLanguage\Node;
1313

1414
use Symfony\Component\ExpressionLanguage\Compiler;
15+
use Symfony\Component\ExpressionLanguage\SyntaxError;
1516

1617
/**
1718
* @author Fabien Potencier <fabien@symfony.com>
@@ -46,8 +47,12 @@ public function compile(Compiler $compiler)
4647
$operator = $this->attributes['operator'];
4748

4849
if ('matches' == $operator) {
50+
if ($this->nodes['right'] instanceof ConstantNode) {
51+
$this->evaluateMatches($this->nodes['right']->evaluate([], []), '');
52+
}
53+
4954
$compiler
50-
->raw('preg_match(')
55+
->raw('(static function ($regexp, $str) { set_error_handler(function ($t, $m) use ($regexp, $str) { throw new \Symfony\Component\ExpressionLanguage\SyntaxError(sprintf(\'Regexp "%s" passed to "matches" is not valid\', $regexp).substr($m, 12)); }); try { return preg_match($regexp, $str); } finally { restore_error_handler(); } })(')
5156
->compile($this->nodes['right'])
5257
->raw(', ')
5358
->compile($this->nodes['left'])
@@ -159,12 +164,24 @@ public function evaluate(array $functions, array $values)
159164

160165
return $left % $right;
161166
case 'matches':
162-
return preg_match($right, $left);
167+
return $this->evaluateMatches($right, $left);
163168
}
164169
}
165170

166171
public function toArray()
167172
{
168173
return ['(', $this->nodes['left'], ' '.$this->attributes['operator'].' ', $this->nodes['right'], ')'];
169174
}
175+
176+
private function evaluateMatches(string $regexp, string $str): int
177+
{
178+
set_error_handler(function ($t, $m) use ($regexp) {
179+
throw new SyntaxError(sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
180+
});
181+
try {
182+
return preg_match($regexp, $str);
183+
} finally {
184+
restore_error_handler();
185+
}
186+
}
170187
}

src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111

1212
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
1313

14+
use Symfony\Component\ExpressionLanguage\Compiler;
1415
use Symfony\Component\ExpressionLanguage\Node\ArrayNode;
1516
use Symfony\Component\ExpressionLanguage\Node\BinaryNode;
1617
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
18+
use Symfony\Component\ExpressionLanguage\Node\NameNode;
19+
use Symfony\Component\ExpressionLanguage\SyntaxError;
1720

1821
class BinaryNodeTest extends AbstractNodeTest
1922
{
@@ -111,7 +114,7 @@ public function getCompileData()
111114

112115
['range(1, 3)', new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))],
113116

114-
['preg_match("/^[a-z]+/i\$/", "abc")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+/i$/'))],
117+
['(static function ($regexp, $str) { set_error_handler(function ($t, $m) use ($regexp, $str) { throw new \Symfony\Component\ExpressionLanguage\SyntaxError(sprintf(\'Regexp "%s" passed to "matches" is not valid\', $regexp).substr($m, 12)); }); try { return preg_match($regexp, $str); } finally { restore_error_handler(); } })("/^[a-z]+\$/", "abc")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+$/'))],
115118
];
116119
}
117120

@@ -160,7 +163,42 @@ public function getDumpData()
160163

161164
['(1 .. 3)', new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))],
162165

163-
['("abc" matches "/^[a-z]+/i$/")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+/i$/'))],
166+
['("abc" matches "/^[a-z]+$/")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+$/'))],
164167
];
165168
}
169+
170+
public function testEvaluateMatchesWithInvalidRegexp()
171+
{
172+
$node = new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('this is not a regexp'));
173+
174+
$this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash'));
175+
$node->evaluate([], []);
176+
}
177+
178+
public function testEvaluateMatchesWithInvalidRegexpAsExpression()
179+
{
180+
$node = new BinaryNode('matches', new ConstantNode('abc'), new NameNode('regexp'));
181+
182+
$this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash'));
183+
$node->evaluate([], ['regexp' => 'this is not a regexp']);
184+
}
185+
186+
public function testCompileMatchesWithInvalidRegexp()
187+
{
188+
$node = new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('this is not a regexp'));
189+
190+
$this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash'));
191+
$compiler = new Compiler([]);
192+
$node->compile($compiler);
193+
}
194+
195+
public function testCompileMatchesWithInvalidRegexpAsExpression()
196+
{
197+
$node = new BinaryNode('matches', new ConstantNode('abc'), new NameNode('regexp'));
198+
199+
$this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash'));
200+
$compiler = new Compiler([]);
201+
$node->compile($compiler);
202+
eval('$regexp = "this is not a regexp"; '.$compiler->getSource().';');
203+
}
166204
}

src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\Messenger\Bridge\Doctrine\Tests\Transport;
1313

1414
use Doctrine\DBAL\Abstraction\Result as AbstractionResult;
15-
use Doctrine\DBAL\Configuration;
1615
use Doctrine\DBAL\Connection as DBALConnection;
1716
use Doctrine\DBAL\Driver\Result as DriverResult;
1817
use Doctrine\DBAL\Driver\ResultStatement;
@@ -25,9 +24,7 @@
2524
use Doctrine\DBAL\Schema\AbstractSchemaManager;
2625
use Doctrine\DBAL\Schema\Schema;
2726
use Doctrine\DBAL\Schema\SchemaConfig;
28-
use Doctrine\DBAL\Schema\TableDiff;
2927
use Doctrine\DBAL\Statement;
30-
use Doctrine\DBAL\Types\Types;
3128
use PHPUnit\Framework\TestCase;
3229
use Symfony\Component\Messenger\Bridge\Doctrine\Tests\Fixtures\DummyMessage;
3330
use Symfony\Component\Messenger\Bridge\Doctrine\Transport\Connection;
@@ -402,60 +399,6 @@ public function providePlatformSql(): iterable
402399
];
403400
}
404401

405-
/**
406-
* @dataProvider setupIndicesProvider
407-
*/
408-
public function testSetupIndices(string $platformClass, array $expectedIndices)
409-
{
410-
$driverConnection = $this->createMock(DBALConnection::class);
411-
$driverConnection->method('getConfiguration')->willReturn(new Configuration());
412-
413-
$schemaManager = $this->createMock(AbstractSchemaManager::class);
414-
$schema = new Schema();
415-
$expectedTable = $schema->createTable('messenger_messages');
416-
$expectedTable->addColumn('id', Types::BIGINT);
417-
$expectedTable->setPrimaryKey(['id']);
418-
// Make sure columns for indices exists so addIndex() will not throw
419-
foreach (array_unique(array_merge(...$expectedIndices)) as $columnName) {
420-
$expectedTable->addColumn($columnName, Types::STRING);
421-
}
422-
foreach ($expectedIndices as $indexColumns) {
423-
$expectedTable->addIndex($indexColumns);
424-
}
425-
$schemaManager->method('createSchema')->willReturn($schema);
426-
if (method_exists(DBALConnection::class, 'createSchemaManager')) {
427-
$driverConnection->method('createSchemaManager')->willReturn($schemaManager);
428-
} else {
429-
$driverConnection->method('getSchemaManager')->willReturn($schemaManager);
430-
}
431-
432-
$platformMock = $this->createMock($platformClass);
433-
$platformMock
434-
->expects(self::once())
435-
->method('getAlterTableSQL')
436-
->with(self::callback(static function (TableDiff $tableDiff): bool {
437-
return 0 === \count($tableDiff->addedIndexes) && 0 === \count($tableDiff->changedIndexes) && 0 === \count($tableDiff->removedIndexes);
438-
}))
439-
->willReturn([]);
440-
$driverConnection->method('getDatabasePlatform')->willReturn($platformMock);
441-
442-
$connection = new Connection([], $driverConnection);
443-
$connection->setup();
444-
}
445-
446-
public function setupIndicesProvider(): iterable
447-
{
448-
yield 'MySQL' => [
449-
MySQL57Platform::class,
450-
[['delivered_at']],
451-
];
452-
453-
yield 'Other platforms' => [
454-
AbstractPlatform::class,
455-
[['queue_name'], ['available_at'], ['delivered_at']],
456-
];
457-
}
458-
459402
public function testConfigureSchema()
460403
{
461404
$driverConnection = $this->getDBALConnectionMock();

src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport;
1313

1414
use Doctrine\DBAL\Connection as DBALConnection;
15+
use Doctrine\DBAL\Driver\Exception as DriverException;
1516
use Doctrine\DBAL\Driver\Result as DriverResult;
1617
use Doctrine\DBAL\Exception as DBALException;
1718
use Doctrine\DBAL\Exception\TableNotFoundException;
@@ -153,6 +154,14 @@ public function send(string $body, array $headers, int $delay = 0): string
153154

154155
public function get(): ?array
155156
{
157+
if ($this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) {
158+
try {
159+
$this->driverConnection->delete($this->configuration['table_name'], ['delivered_at' => '9999-12-31']);
160+
} catch (DriverException $e) {
161+
// Ignore the exception
162+
}
163+
}
164+
156165
get:
157166
$this->driverConnection->beginTransaction();
158167
try {
@@ -224,6 +233,10 @@ public function get(): ?array
224233
public function ack(string $id): bool
225234
{
226235
try {
236+
if ($this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) {
237+
return $this->driverConnection->update($this->configuration['table_name'], ['delivered_at' => '9999-12-31'], ['id' => $id]) > 0;
238+
}
239+
227240
return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0;
228241
} catch (DBALException $exception) {
229242
throw new TransportException($exception->getMessage(), 0, $exception);
@@ -233,6 +246,10 @@ public function ack(string $id): bool
233246
public function reject(string $id): bool
234247
{
235248
try {
249+
if ($this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) {
250+
return $this->driverConnection->update($this->configuration['table_name'], ['delivered_at' => '9999-12-31'], ['id' => $id]) > 0;
251+
}
252+
236253
return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0;
237254
} catch (DBALException $exception) {
238255
throw new TransportException($exception->getMessage(), 0, $exception);
@@ -404,6 +421,7 @@ private function addTableToSchema(Schema $schema): void
404421
$table->addColumn('headers', Types::TEXT)
405422
->setNotnull(true);
406423
$table->addColumn('queue_name', Types::STRING)
424+
->setLength(190) // MySQL 5.6 only supports 191 characters on an indexed column in utf8mb4 mode
407425
->setNotnull(true);
408426
$table->addColumn('created_at', Types::DATETIME_MUTABLE)
409427
->setNotnull(true);
@@ -412,11 +430,8 @@ private function addTableToSchema(Schema $schema): void
412430
$table->addColumn('delivered_at', Types::DATETIME_MUTABLE)
413431
->setNotnull(false);
414432
$table->setPrimaryKey(['id']);
415-
// No indices on queue_name and available_at on MySQL to prevent deadlock issues when running multiple consumers.
416-
if (!$this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) {
417-
$table->addIndex(['queue_name']);
418-
$table->addIndex(['available_at']);
419-
}
433+
$table->addIndex(['queue_name']);
434+
$table->addIndex(['available_at']);
420435
$table->addIndex(['delivered_at']);
421436
}
422437

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ private function readIndex(array $zval, $index): array
443443
}
444444

445445
/**
446-
* Reads the a property from an object.
446+
* Reads the value of a property from an object.
447447
*
448448
* @throws NoSuchPropertyException If $ignoreInvalidProperty is false and the property does not exist or is not public
449449
*/

src/Symfony/Component/Validator/Constraints/File.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ private function normalizeBinaryFormat($maxSize)
168168
$this->maxSize = $matches[1] * $factors[$unit = strtolower($matches[2])];
169169
$this->binaryFormat = $this->binaryFormat ?? (2 === \strlen($unit));
170170
} else {
171-
throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum size.', $this->maxSize));
171+
throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum size.', $maxSize));
172172
}
173173
}
174174
}

src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,5 +526,14 @@ public function uploadedFileErrorProvider()
526526
return $tests;
527527
}
528528

529+
public function testNegativeMaxSize()
530+
{
531+
$this->expectException(ConstraintDefinitionException::class);
532+
$this->expectExceptionMessage('"-1" is not a valid maximum size.');
533+
534+
$file = new File();
535+
$file->maxSize = -1;
536+
}
537+
529538
abstract protected function getFile($filename);
530539
}

0 commit comments

Comments
 (0)
0