Merge branch '4.4' into 5.2

* 4.4:
  install compatible versions of mongodb/mongodb only
  fix resolving parent/self/static type annotations
  [Console] fix QuestionHelper::getHiddenResponse() not working with space in project directory name
  [WebLink] Escape double quotes in attributes values
This commit is contained in:
Christian Flothmann 2021-02-17 16:24:54 +01:00
commit e3b0c8868c
12 changed files with 126 additions and 14 deletions

View File

@ -255,7 +255,7 @@ install:
fi fi
phpenv global $PHP phpenv global $PHP
rm vendor/composer/package-versions-deprecated -Rf rm vendor/composer/package-versions-deprecated -Rf
([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb ^1.9.0) ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb)
tfold 'composer update' $COMPOSER_UP tfold 'composer update' $COMPOSER_UP
tfold 'phpunit install' ./phpunit install tfold 'phpunit install' ./phpunit install
if [[ $deps = high ]]; then if [[ $deps = high ]]; then

View File

@ -411,7 +411,7 @@ class QuestionHelper extends Helper
$exe = $tmpExe; $exe = $tmpExe;
} }
$sExec = shell_exec($exe); $sExec = shell_exec('"'.$exe.'"');
$value = $trimmable ? rtrim($sExec) : $sExec; $value = $trimmable ? rtrim($sExec) : $sExec;
$output->writeln(''); $output->writeln('');

View File

@ -142,11 +142,31 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property
break; break;
} }
$parentClass = null;
$types = []; $types = [];
/** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */
foreach ($docBlock->getTagsByName($tag) as $tag) { foreach ($docBlock->getTagsByName($tag) as $tag) {
if ($tag && !$tag instanceof InvalidTag && null !== $tag->getType()) { if ($tag && !$tag instanceof InvalidTag && null !== $tag->getType()) {
$types = array_merge($types, $this->phpDocTypeHelper->getTypes($tag->getType())); foreach ($this->phpDocTypeHelper->getTypes($tag->getType()) as $type) {
switch ($type->getClassName()) {
case 'self':
case 'static':
$resolvedClass = $class;
break;
case 'parent':
if (false !== $resolvedClass = $parentClass ?? $parentClass = get_parent_class($class)) {
break;
}
// no break
default:
$types[] = $type;
continue 2;
}
$types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $type->isNullable(), $resolvedClass, $type->isCollection(), $type->getCollectionKeyType(), $type->getCollectionValueType());
}
} }
} }

View File

@ -17,6 +17,7 @@ use phpDocumentor\Reflection\Types\Collection;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait;
use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait;
use Symfony\Component\PropertyInfo\Type; use Symfony\Component\PropertyInfo\Type;
@ -136,6 +137,7 @@ class PhpDocExtractorTest extends TestCase
null, null,
null, null,
], ],
['self', [new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)], null, null],
]; ];
} }
@ -342,6 +344,38 @@ class PhpDocExtractorTest extends TestCase
]; ];
} }
/**
* @dataProvider propertiesStaticTypeProvider
*/
public function testPropertiesStaticType(string $class, string $property, Type $type)
{
$this->assertEquals([$type], $this->extractor->getTypes($class, $property));
}
public function propertiesStaticTypeProvider(): array
{
return [
[ParentDummy::class, 'propertyTypeStatic', new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)],
[Dummy::class, 'propertyTypeStatic', new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)],
];
}
/**
* @dataProvider propertiesParentTypeProvider
*/
public function testPropertiesParentType(string $class, string $property, ?array $types)
{
$this->assertEquals($types, $this->extractor->getTypes($class, $property));
}
public function propertiesParentTypeProvider(): array
{
return [
[ParentDummy::class, 'parentAnnotationNoParent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'parent')]],
[Dummy::class, 'parentAnnotation', [new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]],
];
}
protected function isPhpDocumentorV5() protected function isPhpDocumentorV5()
{ {
if (class_exists(InvalidTag::class)) { if (class_exists(InvalidTag::class)) {

View File

@ -24,6 +24,8 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended2; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended2;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php74Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php74Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php7ParentDummy;
use Symfony\Component\PropertyInfo\Type; use Symfony\Component\PropertyInfo\Type;
/** /**
@ -66,12 +68,15 @@ class ReflectionExtractorTest extends TestCase
'arrayWithKeys', 'arrayWithKeys',
'arrayWithKeysAndComplexValue', 'arrayWithKeysAndComplexValue',
'arrayOfMixed', 'arrayOfMixed',
'parentAnnotation',
'foo', 'foo',
'foo2', 'foo2',
'foo3', 'foo3',
'foo4', 'foo4',
'foo5', 'foo5',
'files', 'files',
'propertyTypeStatic',
'parentAnnotationNoParent',
'a', 'a',
'DOB', 'DOB',
'Id', 'Id',
@ -118,12 +123,15 @@ class ReflectionExtractorTest extends TestCase
'arrayWithKeys', 'arrayWithKeys',
'arrayWithKeysAndComplexValue', 'arrayWithKeysAndComplexValue',
'arrayOfMixed', 'arrayOfMixed',
'parentAnnotation',
'foo', 'foo',
'foo2', 'foo2',
'foo3', 'foo3',
'foo4', 'foo4',
'foo5', 'foo5',
'files', 'files',
'propertyTypeStatic',
'parentAnnotationNoParent',
'date', 'date',
'c', 'c',
'd', 'd',
@ -159,12 +167,15 @@ class ReflectionExtractorTest extends TestCase
'arrayWithKeys', 'arrayWithKeys',
'arrayWithKeysAndComplexValue', 'arrayWithKeysAndComplexValue',
'arrayOfMixed', 'arrayOfMixed',
'parentAnnotation',
'foo', 'foo',
'foo2', 'foo2',
'foo3', 'foo3',
'foo4', 'foo4',
'foo5', 'foo5',
'files', 'files',
'propertyTypeStatic',
'parentAnnotationNoParent',
], ],
$noPrefixExtractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy') $noPrefixExtractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy')
); );
@ -200,20 +211,21 @@ class ReflectionExtractorTest extends TestCase
/** /**
* @dataProvider php7TypesProvider * @dataProvider php7TypesProvider
*/ */
public function testExtractPhp7Type($property, array $type = null) public function testExtractPhp7Type(string $class, string $property, array $type = null)
{ {
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy', $property, [])); $this->assertEquals($type, $this->extractor->getTypes($class, $property, []));
} }
public function php7TypesProvider() public function php7TypesProvider()
{ {
return [ return [
['foo', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)]], [Php7Dummy::class, 'foo', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)]],
['bar', [new Type(Type::BUILTIN_TYPE_INT)]], [Php7Dummy::class, 'bar', [new Type(Type::BUILTIN_TYPE_INT)]],
['baz', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]], [Php7Dummy::class, 'baz', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]],
['buz', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy')]], [Php7Dummy::class, 'buz', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy')]],
['biz', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'stdClass')]], [Php7Dummy::class, 'biz', [new Type(Type::BUILTIN_TYPE_OBJECT, false, Php7ParentDummy::class)]],
['donotexist', null], [Php7Dummy::class, 'donotexist', null],
[Php7ParentDummy::class, 'parent', [new Type(Type::BUILTIN_TYPE_OBJECT, false, \stdClass::class)]],
]; ];
} }

View File

@ -145,6 +145,11 @@ class Dummy extends ParentDummy
*/ */
public $arrayOfMixed; public $arrayOfMixed;
/**
* @var parent
*/
public $parentAnnotation;
public static function getStatic() public static function getStatic()
{ {
} }

View File

@ -48,6 +48,16 @@ class ParentDummy
*/ */
public $files; public $files;
/**
* @var static
*/
public $propertyTypeStatic;
/**
* @var parent
*/
public $parentAnnotationNoParent;
/** /**
* @return bool|null * @return bool|null
*/ */

View File

@ -14,7 +14,7 @@ namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
/** /**
* @author Kévin Dunglas <dunglas@gmail.com> * @author Kévin Dunglas <dunglas@gmail.com>
*/ */
class Php7Dummy extends \stdClass class Php7Dummy extends Php7ParentDummy
{ {
public function getFoo(): array public function getFoo(): array
{ {

View File

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
class Php7ParentDummy extends \stdClass
{
public function getParent(): parent
{
}
}

View File

@ -172,6 +172,10 @@ final class PhpDocTypeHelper
return [$docType, null]; return [$docType, null];
} }
if (\in_array($docType, ['parent', 'self', 'static'], true)) {
return ['object', $docType];
}
return ['object', substr($docType, 1)]; // substr to strip the namespace's `\`-prefix return ['object', substr($docType, 1)]; // substr to strip the namespace's `\`-prefix
} }
} }

View File

@ -39,14 +39,14 @@ final class HttpHeaderSerializer
foreach ($link->getAttributes() as $key => $value) { foreach ($link->getAttributes() as $key => $value) {
if (\is_array($value)) { if (\is_array($value)) {
foreach ($value as $v) { foreach ($value as $v) {
$attributesParts[] = sprintf('%s="%s"', $key, $v); $attributesParts[] = sprintf('%s="%s"', $key, preg_replace('/(?<!\\\\)"/', '\"', $v));
} }
continue; continue;
} }
if (!\is_bool($value)) { if (!\is_bool($value)) {
$attributesParts[] = sprintf('%s="%s"', $key, $value); $attributesParts[] = sprintf('%s="%s"', $key, preg_replace('/(?<!\\\\)"/', '\"', $value));
continue; continue;
} }

View File

@ -44,4 +44,12 @@ class HttpHeaderSerializerTest extends TestCase
{ {
$this->assertNull($this->serializer->serialize([])); $this->assertNull($this->serializer->serialize([]));
} }
public function testSerializeDoubleQuotesInAttributeValue()
{
$this->assertSame('</foo>; rel="alternate"; title="\"escape me\" \"already escaped\" \"\"\""', $this->serializer->serialize([
(new Link('alternate', '/foo'))
->withAttribute('title', '"escape me" \"already escaped\" ""\"'),
]));
}
} }