Skip to content

Commit b628210

Browse files
Merge branch '3.4' into 4.3
* 3.4: Sync Twig templateExists behaviors Fix the :only-of-type pseudo class selector [Serializer] Add CsvEncoder tests for PHP 7.4 Copy phpunit.xsd to a predictable path [Security/Http] fix parsing X509 emailAddress [Serializer] fix denormalization of string-arrays with only one element #33731 [Cache] fix known tag versions ttl check
2 parents d8a026b + ff194d9 commit b628210

File tree

17 files changed

+259
-80
lines changed

17 files changed

+259
-80
lines changed

src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s': 'rm -rf %s', "phpunit-$PHPUNIT_VERSION.old"));
111111
}
112112
passthru("$COMPOSER create-project --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\"");
113+
@copy("phpunit-$PHPUNIT_VERSION/phpunit.xsd", 'phpunit.xsd');
113114
chdir("phpunit-$PHPUNIT_VERSION");
114115
if ($SYMFONY_PHPUNIT_REMOVE) {
115116
passthru("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE);

src/Symfony/Bridge/Twig/TwigEngine.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Twig\Error\Error;
2222
use Twig\Error\LoaderError;
2323
use Twig\Loader\ExistsLoaderInterface;
24+
use Twig\Loader\SourceContextLoaderInterface;
2425
use Twig\Template;
2526

2627
/**
@@ -78,19 +79,24 @@ public function exists($name)
7879

7980
$loader = $this->environment->getLoader();
8081

81-
if ($loader instanceof ExistsLoaderInterface || method_exists($loader, 'exists')) {
82-
return $loader->exists((string) $name);
83-
}
82+
if (1 === Environment::MAJOR_VERSION && !$loader instanceof ExistsLoaderInterface) {
83+
try {
84+
// cast possible TemplateReferenceInterface to string because the
85+
// EngineInterface supports them but LoaderInterface does not
86+
if ($loader instanceof SourceContextLoaderInterface) {
87+
$loader->getSourceContext((string) $name);
88+
} else {
89+
$loader->getSource((string) $name);
90+
}
91+
92+
return true;
93+
} catch (LoaderError $e) {
94+
}
8495

85-
try {
86-
// cast possible TemplateReferenceInterface to string because the
87-
// EngineInterface supports them but LoaderInterface does not
88-
$loader->getSourceContext((string) $name)->getCode();
89-
} catch (LoaderError $e) {
9096
return false;
9197
}
9298

93-
return true;
99+
return $loader->exists((string) $name);
94100
}
95101

96102
/**

src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Twig\Environment;
1919
use Twig\Error\LoaderError;
2020
use Twig\Loader\ExistsLoaderInterface;
21+
use Twig\Loader\SourceContextLoaderInterface;
2122

2223
/**
2324
* ExceptionController renders error or exception pages for a given
@@ -120,23 +121,28 @@ protected function findTemplate(Request $request, $format, $code, $showException
120121
return sprintf('@Twig/Exception/%s.html.twig', $showException ? 'exception_full' : $name);
121122
}
122123

123-
// to be removed when the minimum required version of Twig is >= 3.0
124+
// to be removed when the minimum required version of Twig is >= 2.0
124125
protected function templateExists($template)
125126
{
126127
$template = (string) $template;
127128

128129
$loader = $this->twig->getLoader();
129-
if ($loader instanceof ExistsLoaderInterface || method_exists($loader, 'exists')) {
130-
return $loader->exists($template);
131-
}
132130

133-
try {
134-
$loader->getSourceContext($template)->getCode();
131+
if (1 === Environment::MAJOR_VERSION && !$loader instanceof ExistsLoaderInterface) {
132+
try {
133+
if ($loader instanceof SourceContextLoaderInterface) {
134+
$loader->getSourceContext($template);
135+
} else {
136+
$loader->getSource($template);
137+
}
138+
139+
return true;
140+
} catch (LoaderError $e) {
141+
}
135142

136-
return true;
137-
} catch (LoaderError $e) {
143+
return false;
138144
}
139145

140-
return false;
146+
return $loader->exists($template);
141147
}
142148
}

src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Twig\Environment;
2020
use Twig\Error\LoaderError;
2121
use Twig\Loader\ExistsLoaderInterface;
22+
use Twig\Loader\SourceContextLoaderInterface;
2223

2324
/**
2425
* ExceptionController.
@@ -118,17 +119,22 @@ protected function getTemplate()
118119
protected function templateExists($template)
119120
{
120121
$loader = $this->twig->getLoader();
121-
if ($loader instanceof ExistsLoaderInterface) {
122-
return $loader->exists($template);
123-
}
124122

125-
try {
126-
$loader->getSource($template);
123+
if (1 === Environment::MAJOR_VERSION && !$loader instanceof ExistsLoaderInterface) {
124+
try {
125+
if ($loader instanceof SourceContextLoaderInterface) {
126+
$loader->getSourceContext($template);
127+
} else {
128+
$loader->getSource($template);
129+
}
130+
131+
return true;
132+
} catch (LoaderError $e) {
133+
}
127134

128-
return true;
129-
} catch (LoaderError $e) {
135+
return false;
130136
}
131137

132-
return false;
138+
return $loader->exists($template);
133139
}
134140
}

src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,22 @@ public function getNames(Profile $profile)
9999
protected function templateExists($template)
100100
{
101101
$loader = $this->twig->getLoader();
102-
if ($loader instanceof ExistsLoaderInterface) {
103-
return $loader->exists($template);
104-
}
105102

106-
try {
107-
if ($loader instanceof SourceContextLoaderInterface || method_exists($loader, 'getSourceContext')) {
108-
$loader->getSourceContext($template);
109-
} else {
110-
$loader->getSource($template);
103+
if (1 === Environment::MAJOR_VERSION && !$loader instanceof ExistsLoaderInterface) {
104+
try {
105+
if ($loader instanceof SourceContextLoaderInterface) {
106+
$loader->getSourceContext($template);
107+
} else {
108+
$loader->getSource($template);
109+
}
110+
111+
return true;
112+
} catch (LoaderError $e) {
111113
}
112114

113-
return true;
114-
} catch (LoaderError $e) {
115+
return false;
115116
}
116117

117-
return false;
118+
return $loader->exists($template);
118119
}
119120
}

src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Symfony\Bundle\WebProfilerBundle\Tests\TestCase;
1616
use Symfony\Component\HttpKernel\Profiler\Profile;
1717
use Twig\Environment;
18+
use Twig\Loader\LoaderInterface;
19+
use Twig\Loader\SourceContextLoaderInterface;
1820

1921
/**
2022
* Test for TemplateManager class.
@@ -107,11 +109,16 @@ protected function mockTwigEnvironment()
107109
->method('loadTemplate')
108110
->willReturn('loadedTemplate');
109111

110-
if (interface_exists('Twig\Loader\SourceContextLoaderInterface')) {
111-
$loader = $this->getMockBuilder('Twig\Loader\SourceContextLoaderInterface')->getMock();
112+
if (Environment::MAJOR_VERSION > 1) {
113+
$loader = $this->createMock(LoaderInterface::class);
114+
$loader
115+
->expects($this->any())
116+
->method('exists')
117+
->willReturn(true);
112118
} else {
113-
$loader = $this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock();
119+
$loader = $this->createMock(SourceContextLoaderInterface::class);
114120
}
121+
115122
$this->twigEnvironment->expects($this->any())->method('getLoader')->willReturn($loader);
116123

117124
return $this->twigEnvironment;

src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ private function getTagVersions(array $tagsByKey, array &$invalidatedTags = [])
354354
continue;
355355
}
356356
$version -= $this->knownTagVersions[$tag][1];
357-
if ((0 !== $version && 1 !== $version) || $this->knownTagVersionsTtl > $now - $this->knownTagVersions[$tag][0]) {
357+
if ((0 !== $version && 1 !== $version) || $now - $this->knownTagVersions[$tag][0] >= $this->knownTagVersionsTtl) {
358358
// reuse previously fetched tag versions up to the ttl, unless we are storing items or a potential miss arises
359359
$fetchTagVersions = true;
360360
} else {

src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

1414
use PHPUnit\Framework\MockObject\MockObject;
15+
use Psr\Cache\CacheItemInterface;
1516
use Symfony\Component\Cache\Adapter\AdapterInterface;
1617
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
1718
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
@@ -65,6 +66,39 @@ public function testPrune()
6566
$this->assertFalse($cache->prune());
6667
}
6768

69+
public function testKnownTagVersionsTtl()
70+
{
71+
$itemsPool = new FilesystemAdapter('', 10);
72+
$tagsPool = $this
73+
->getMockBuilder(AdapterInterface::class)
74+
->getMock();
75+
76+
$pool = new TagAwareAdapter($itemsPool, $tagsPool, 10);
77+
78+
$item = $pool->getItem('foo');
79+
$item->tag(['baz']);
80+
$item->expiresAfter(100);
81+
82+
$tag = $this->getMockBuilder(CacheItemInterface::class)->getMock();
83+
$tag->expects(self::exactly(2))->method('get')->willReturn(10);
84+
85+
$tagsPool->expects(self::exactly(2))->method('getItems')->willReturn([
86+
'baz'.TagAwareAdapter::TAGS_PREFIX => $tag,
87+
]);
88+
89+
$pool->save($item);
90+
$this->assertTrue($pool->getItem('foo')->isHit());
91+
$this->assertTrue($pool->getItem('foo')->isHit());
92+
93+
sleep(20);
94+
95+
$this->assertTrue($pool->getItem('foo')->isHit());
96+
97+
sleep(5);
98+
99+
$this->assertTrue($pool->getItem('foo')->isHit());
100+
}
101+
68102
/**
69103
* @return MockObject|PruneableCacheInterface
70104
*/

src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public function testXmlLang($css, array $elementsId)
9898
$elements = $document->xpath($translator->cssToXPath($css));
9999
$this->assertCount(\count($elementsId), $elements);
100100
foreach ($elements as $element) {
101-
$this->assertTrue(\in_array($element->attributes()->id, $elementsId));
101+
$this->assertContains((string) $element->attributes()->id, $elementsId);
102102
}
103103
}
104104

@@ -116,7 +116,7 @@ public function testHtmlIds($css, array $elementsId)
116116
$this->assertCount(\count($elementsId), $elementsId);
117117
foreach ($elements as $element) {
118118
if (null !== $element->attributes()->id) {
119-
$this->assertTrue(\in_array($element->attributes()->id, $elementsId));
119+
$this->assertContains((string) $element->attributes()->id, $elementsId);
120120
}
121121
}
122122
libxml_clear_errors();
@@ -137,6 +137,33 @@ public function testHtmlShakespear($css, $count)
137137
$this->assertCount($count, $elements);
138138
}
139139

140+
public function testOnlyOfTypeFindsSingleChildrenOfGivenType()
141+
{
142+
$translator = new Translator();
143+
$translator->registerExtension(new HtmlExtension($translator));
144+
$document = new \DOMDocument();
145+
$document->loadHTML(<<<'HTML'
146+
<html>
147+
<body>
148+
<p>
149+
<span>A</span>
150+
</p>
151+
<p>
152+
<span>B</span>
153+
<span>C</span>
154+
</p>
155+
</body>
156+
</html>
157+
HTML
158+
);
159+
160+
$xpath = new \DOMXPath($document);
161+
$nodeList = $xpath->query($translator->cssToXPath('span:only-of-type'));
162+
163+
$this->assertSame(1, $nodeList->length);
164+
$this->assertSame('A', $nodeList->item(0)->textContent);
165+
}
166+
140167
public function getXpathLiteralTestData()
141168
{
142169
return [
@@ -175,7 +202,7 @@ public function getCssToXPathTestData()
175202
['e:first-of-type', '*/e[position() = 1]'],
176203
['e:last-of-type', '*/e[position() = last()]'],
177204
['e:only-child', "*/*[(name() = 'e') and (last() = 1)]"],
178-
['e:only-of-type', 'e[last() = 1]'],
205+
['e:only-of-type', 'e[count(preceding-sibling::e)=0 and count(following-sibling::e)=0]'],
179206
['e:empty', 'e[not(*) and not(string-length())]'],
180207
['e:EmPTY', 'e[not(*) and not(string-length())]'],
181208
['e:root', 'e[not(parent::*)]'],

src/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,13 @@ public function translateOnlyChild(XPathExpr $xpath)
123123
*/
124124
public function translateOnlyOfType(XPathExpr $xpath)
125125
{
126-
if ('*' === $xpath->getElement()) {
126+
$element = $xpath->getElement();
127+
128+
if ('*' === $element) {
127129
throw new ExpressionErrorException('"*:only-of-type" is not implemented.');
128130
}
129131

130-
return $xpath->addCondition('last() = 1');
132+
return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
131133
}
132134

133135
/**

0 commit comments

Comments
 (0)