Merge branch '5.1'
* 5.1: Fix test that fails on old distros Fix: compatibility with phpunit 9.3 [DoctrineBridge] work around Connection::ping() deprecation [MimeType] Duplicated MimeType due to PHP Bug [HttpClient] fix casting TraceableResponse to php streams [DI] fix parsing of argument type=binary in xml fix guessing form types for DateTime types fix handling typed properties as constraint options Fix the 'supports' method argument type of the security voter Use the driverConnection executeUpdate method
This commit is contained in:
commit
75031a1230
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\Messenger;
|
||||
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Middleware\StackInterface;
|
||||
@ -36,7 +37,9 @@ class DoctrinePingConnectionMiddleware extends AbstractDoctrineMiddleware
|
||||
{
|
||||
$connection = $entityManager->getConnection();
|
||||
|
||||
if (!$connection->ping()) {
|
||||
try {
|
||||
$connection->query($connection->getDatabasePlatform()->getDummySelectSQL());
|
||||
} catch (DBALException $e) {
|
||||
$connection->close();
|
||||
$connection->connect();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bridge\Doctrine\Tests\Messenger;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Symfony\Bridge\Doctrine\Messenger\DoctrinePingConnectionMiddleware;
|
||||
@ -47,8 +48,8 @@ class DoctrinePingConnectionMiddlewareTest extends MiddlewareTestCase
|
||||
public function testMiddlewarePingOk()
|
||||
{
|
||||
$this->connection->expects($this->once())
|
||||
->method('ping')
|
||||
->willReturn(false);
|
||||
->method('getDatabasePlatform')
|
||||
->will($this->throwException(new DBALException()));
|
||||
|
||||
$this->connection->expects($this->once())
|
||||
->method('close')
|
||||
@ -65,6 +66,10 @@ class DoctrinePingConnectionMiddlewareTest extends MiddlewareTestCase
|
||||
|
||||
public function testMiddlewarePingResetEntityManager()
|
||||
{
|
||||
$this->connection->expects($this->once())
|
||||
->method('getDatabasePlatform')
|
||||
->will($this->throwException(new DBALException()));
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('isOpen')
|
||||
->willReturn(false)
|
||||
|
@ -12,9 +12,11 @@
|
||||
namespace Symfony\Bridge\PhpUnit\Legacy;
|
||||
|
||||
use PHPUnit\TextUI\Command as BaseCommand;
|
||||
use PHPUnit\TextUI\Configuration\Configuration;
|
||||
use PHPUnit\TextUI\Configuration\Configuration as LegacyConfiguration;
|
||||
use PHPUnit\TextUI\Configuration\Registry;
|
||||
use PHPUnit\TextUI\TestRunner as BaseRunner;
|
||||
use PHPUnit\TextUI\XmlConfiguration\Configuration;
|
||||
use PHPUnit\TextUI\XmlConfiguration\Loader;
|
||||
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
|
||||
|
||||
/**
|
||||
@ -43,9 +45,13 @@ class CommandForV9 extends BaseCommand
|
||||
|
||||
if (isset($this->arguments['configuration'])) {
|
||||
$configuration = $this->arguments['configuration'];
|
||||
if (!$configuration instanceof Configuration) {
|
||||
|
||||
if (!class_exists(Configuration::class) && !$configuration instanceof LegacyConfiguration) {
|
||||
$configuration = Registry::getInstance()->get($this->arguments['configuration']);
|
||||
} elseif (class_exists(Configuration::class) && !$configuration instanceof Configuration) {
|
||||
$configuration = (new Loader())->load($this->arguments['configuration']);
|
||||
}
|
||||
|
||||
foreach ($configuration->listeners() as $registeredListener) {
|
||||
if ('Symfony\Bridge\PhpUnit\SymfonyTestsListener' === ltrim($registeredListener->className(), '\\')) {
|
||||
$registeredLocally = true;
|
||||
|
@ -289,6 +289,7 @@
|
||||
<xsd:enumeration value="expression" />
|
||||
<xsd:enumeration value="string" />
|
||||
<xsd:enumeration value="constant" />
|
||||
<xsd:enumeration value="binary" />
|
||||
<xsd:enumeration value="iterator" />
|
||||
<xsd:enumeration value="service_locator" />
|
||||
<!-- "tagged" is an alias of "tagged_iterator", using "tagged_iterator" is preferred. -->
|
||||
|
@ -97,6 +97,7 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
|
||||
case 'long':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
case \DateTime::class:
|
||||
case '\DateTime':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
|
@ -12,9 +12,17 @@
|
||||
namespace Symfony\Component\Form\Tests\Extension\Validator;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser;
|
||||
use Symfony\Component\Form\Guess\Guess;
|
||||
use Symfony\Component\Form\Guess\TypeGuess;
|
||||
use Symfony\Component\Form\Guess\ValueGuess;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Email;
|
||||
use Symfony\Component\Validator\Constraints\File;
|
||||
use Symfony\Component\Validator\Constraints\IsTrue;
|
||||
@ -60,6 +68,35 @@ class ValidatorTypeGuesserTest extends TestCase
|
||||
$this->guesser = new ValidatorTypeGuesser($this->metadataFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider guessTypeProvider
|
||||
*/
|
||||
public function testGuessType(Constraint $constraint, TypeGuess $guess)
|
||||
{
|
||||
$this->metadata->addPropertyConstraint(self::TEST_PROPERTY, $constraint);
|
||||
|
||||
$this->assertEquals($guess, $this->guesser->guessType(self::TEST_CLASS, self::TEST_PROPERTY));
|
||||
}
|
||||
|
||||
public function guessTypeProvider()
|
||||
{
|
||||
return [
|
||||
[new Type('array'), new TypeGuess(CollectionType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('bool'), new TypeGuess(CheckboxType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('boolean'), new TypeGuess(CheckboxType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('double'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('float'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('numeric'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('real'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('int'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('integer'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('long'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('string'), new TypeGuess(TextType::class, [], Guess::LOW_CONFIDENCE)],
|
||||
[new Type(\DateTime::class), new TypeGuess(DateType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
[new Type('\DateTime'), new TypeGuess(DateType::class, [], Guess::MEDIUM_CONFIDENCE)],
|
||||
];
|
||||
}
|
||||
|
||||
public function guessRequiredProvider()
|
||||
{
|
||||
return [
|
||||
|
@ -17,6 +17,7 @@ use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface;
|
||||
use Psr\Http\Message\StreamFactoryInterface;
|
||||
use Symfony\Component\HttpClient\Response\CommonResponseTrait;
|
||||
use Symfony\Component\HttpClient\Response\StreamWrapper;
|
||||
use Symfony\Component\HttpClient\Response\TraceableResponse;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
@ -119,7 +120,7 @@ final class HttplugWaitLoop
|
||||
}
|
||||
}
|
||||
|
||||
if (isset(class_uses($response)[CommonResponseTrait::class])) {
|
||||
if ($response instanceof TraceableResponse || isset(class_uses($response)[CommonResponseTrait::class])) {
|
||||
$body = $this->streamFactory->createStreamFromResource($response->toStream(false));
|
||||
} elseif (!$buffer) {
|
||||
$body = $this->streamFactory->createStreamFromResource(StreamWrapper::createResource($response, $this->client));
|
||||
|
@ -29,6 +29,7 @@ use Psr\Http\Message\UriFactoryInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Symfony\Component\HttpClient\Response\CommonResponseTrait;
|
||||
use Symfony\Component\HttpClient\Response\StreamWrapper;
|
||||
use Symfony\Component\HttpClient\Response\TraceableResponse;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
@ -104,7 +105,7 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str
|
||||
}
|
||||
}
|
||||
|
||||
$body = isset(class_uses($response)[CommonResponseTrait::class]) ? $response->toStream(false) : StreamWrapper::createResource($response, $this->client);
|
||||
$body = $response instanceof TraceableResponse || isset(class_uses($response)[CommonResponseTrait::class]) ? $response->toStream(false) : StreamWrapper::createResource($response, $this->client);
|
||||
$body = $this->streamFactory->createStreamFromResource($body);
|
||||
|
||||
if ($body->isSeekable()) {
|
||||
|
@ -49,7 +49,7 @@ class StreamWrapper
|
||||
*/
|
||||
public static function createResource(ResponseInterface $response, HttpClientInterface $client = null)
|
||||
{
|
||||
if (\is_callable([$response, 'toStream']) && isset(class_uses($response)[CommonResponseTrait::class])) {
|
||||
if ($response instanceof TraceableResponse || (\is_callable([$response, 'toStream']) && isset(class_uses($response)[CommonResponseTrait::class]))) {
|
||||
$stack = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
|
||||
if ($response !== ($stack[1]['object'] ?? null)) {
|
||||
|
@ -130,7 +130,7 @@ class Connection implements ResetInterface
|
||||
'available_at' => '?',
|
||||
]);
|
||||
|
||||
$this->executeQuery($queryBuilder->getSQL(), [
|
||||
$this->executeUpdate($queryBuilder->getSQL(), [
|
||||
$body,
|
||||
json_encode($headers),
|
||||
$this->configuration['queue_name'],
|
||||
@ -181,7 +181,7 @@ class Connection implements ResetInterface
|
||||
->set('delivered_at', '?')
|
||||
->where('id = ?');
|
||||
$now = new \DateTime();
|
||||
$this->executeQuery($queryBuilder->getSQL(), [
|
||||
$this->executeUpdate($queryBuilder->getSQL(), [
|
||||
$now,
|
||||
$doctrineEnvelope['id'],
|
||||
], [
|
||||
@ -338,6 +338,25 @@ class Connection implements ResetInterface
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
private function executeUpdate(string $sql, array $parameters = [], array $types = [])
|
||||
{
|
||||
try {
|
||||
$stmt = $this->driverConnection->executeUpdate($sql, $parameters, $types);
|
||||
} catch (TableNotFoundException $e) {
|
||||
if ($this->driverConnection->isTransactionActive()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// create table
|
||||
if ($this->autoSetup) {
|
||||
$this->setup();
|
||||
}
|
||||
$stmt = $this->driverConnection->executeUpdate($sql, $parameters, $types);
|
||||
}
|
||||
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
private function getSchema(): Schema
|
||||
{
|
||||
$schema = new Schema([], [], $this->driverConnection->getSchemaManager()->createSchemaConfig());
|
||||
|
@ -57,7 +57,13 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
|
||||
if (false === $finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) {
|
||||
return null;
|
||||
}
|
||||
$mimeType = $finfo->file($path);
|
||||
|
||||
return $finfo->file($path);
|
||||
if ($mimeType && 0 === (\strlen($mimeType) % 2)) {
|
||||
$mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1);
|
||||
$mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType;
|
||||
}
|
||||
|
||||
return $mimeType;
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,11 @@ abstract class AbstractMimeTypeGuesserTest extends TestCase
|
||||
$this->assertEquals('application/octet-stream', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/.unknownextension'));
|
||||
}
|
||||
|
||||
public function testGuessWithDuplicatedFileType()
|
||||
{
|
||||
$this->assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/test.docx'));
|
||||
}
|
||||
|
||||
public function testGuessWithIncorrectPath()
|
||||
{
|
||||
if (!$this->getGuesser()->isGuesserSupported()) {
|
||||
|
BIN
src/Symfony/Component/Mime/Tests/Fixtures/test.docx
Normal file
BIN
src/Symfony/Component/Mime/Tests/Fixtures/test.docx
Normal file
Binary file not shown.
@ -30,8 +30,21 @@ abstract class Voter implements VoterInterface
|
||||
$vote = self::ACCESS_ABSTAIN;
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if (!$this->supports($attribute, $subject)) {
|
||||
continue;
|
||||
try {
|
||||
if (!$this->supports($attribute, $subject)) {
|
||||
continue;
|
||||
}
|
||||
} catch (\TypeError $e) {
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
if (0 === strpos($e->getMessage(), 'Argument 1 passed to')
|
||||
&& false !== strpos($e->getMessage(), '::supports() must be of the type string')) {
|
||||
continue;
|
||||
}
|
||||
} elseif (false !== strpos($e->getMessage(), 'supports(): Argument #1')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// as soon as at least one attribute is supported, default is to deny access
|
||||
|
@ -27,34 +27,49 @@ class VoterTest extends TestCase
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
$voter = new VoterTest_Voter();
|
||||
$integerVoter = new IntegerVoterTest_Voter();
|
||||
|
||||
return [
|
||||
[['EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'],
|
||||
[['CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access'],
|
||||
[$voter, ['EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'],
|
||||
[$voter, ['CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access'],
|
||||
|
||||
[['DELETE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access'],
|
||||
[['DELETE', 'CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access'],
|
||||
[$voter, ['DELETE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access'],
|
||||
[$voter, ['DELETE', 'CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access'],
|
||||
|
||||
[['CREATE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access'],
|
||||
[$voter, ['CREATE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access'],
|
||||
|
||||
[['DELETE'], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'],
|
||||
[$voter, ['DELETE'], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'],
|
||||
|
||||
[['EDIT'], VoterInterface::ACCESS_ABSTAIN, $this, 'ACCESS_ABSTAIN if class is not supported'],
|
||||
[$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, $this, 'ACCESS_ABSTAIN if class is not supported'],
|
||||
|
||||
[['EDIT'], VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'],
|
||||
[$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'],
|
||||
|
||||
[[], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided'],
|
||||
[$voter, [], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided'],
|
||||
|
||||
[$voter, [new StringableAttribute()], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'],
|
||||
|
||||
[$voter, [new \stdClass()], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if attributes were not strings'],
|
||||
|
||||
[$integerVoter, [42], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute is an integer'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTests
|
||||
*/
|
||||
public function testVote(array $attributes, $expectedVote, $object, $message)
|
||||
public function testVote(VoterInterface $voter, array $attributes, $expectedVote, $object, $message)
|
||||
{
|
||||
$voter = new VoterTest_Voter();
|
||||
|
||||
$this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message);
|
||||
}
|
||||
|
||||
public function testVoteWithTypeError()
|
||||
{
|
||||
$this->expectException('TypeError');
|
||||
$this->expectExceptionMessage('Should error');
|
||||
$voter = new TypeErrorVoterTest_Voter();
|
||||
$voter->vote($this->token, new \stdClass(), ['EDIT']);
|
||||
}
|
||||
}
|
||||
|
||||
class VoterTest_Voter extends Voter
|
||||
@ -69,3 +84,37 @@ class VoterTest_Voter extends Voter
|
||||
return $object instanceof \stdClass && \in_array($attribute, ['EDIT', 'CREATE']);
|
||||
}
|
||||
}
|
||||
|
||||
class IntegerVoterTest_Voter extends Voter
|
||||
{
|
||||
protected function voteOnAttribute($attribute, $object, TokenInterface $token): bool
|
||||
{
|
||||
return 42 === $attribute;
|
||||
}
|
||||
|
||||
protected function supports($attribute, $object): bool
|
||||
{
|
||||
return $object instanceof \stdClass && \is_int($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeErrorVoterTest_Voter extends Voter
|
||||
{
|
||||
protected function voteOnAttribute($attribute, $object, TokenInterface $token): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function supports($attribute, $object): bool
|
||||
{
|
||||
throw new \TypeError('Should error');
|
||||
}
|
||||
}
|
||||
|
||||
class StringableAttribute
|
||||
{
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'EDIT';
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ abstract class Constraint
|
||||
$defaultOption = $this->getDefaultOption();
|
||||
$invalidOptions = [];
|
||||
$missingOptions = array_flip((array) $this->getRequiredOptions());
|
||||
$knownOptions = get_object_vars($this);
|
||||
$knownOptions = get_class_vars(static::class);
|
||||
|
||||
// The "groups" option is added to the object lazily
|
||||
$knownOptions['groups'] = true;
|
||||
|
@ -13,10 +13,13 @@ namespace Symfony\Component\Validator\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Exception\InvalidOptionsException;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintC;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithStaticProperty;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithTypedProperty;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithValue;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithValueAsDefault;
|
||||
|
||||
@ -245,4 +248,25 @@ class ConstraintTest extends TestCase
|
||||
$this->expectExceptionMessage('No default option is configured for constraint "Symfony\Component\Validator\Tests\Fixtures\ConstraintB".');
|
||||
new ConstraintB(['value' => 1]);
|
||||
}
|
||||
|
||||
public function testStaticPropertiesAreNoOptions()
|
||||
{
|
||||
$this->expectException(InvalidOptionsException::class);
|
||||
|
||||
new ConstraintWithStaticProperty([
|
||||
'foo' => 'bar',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7.4
|
||||
*/
|
||||
public function testSetTypedProperty()
|
||||
{
|
||||
$constraint = new ConstraintWithTypedProperty([
|
||||
'foo' => 'bar',
|
||||
]);
|
||||
|
||||
$this->assertSame('bar', $constraint->foo);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
class ConstraintWithStaticProperty extends Constraint
|
||||
{
|
||||
public static $foo;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
class ConstraintWithTypedProperty extends Constraint
|
||||
{
|
||||
public string $foo;
|
||||
}
|
Reference in New Issue
Block a user