diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 2d64894f41..94f0fabcc4 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,7 +4,7 @@
| Bug fix? | yes/no
| New feature? | yes/no
| BC breaks? | no
-| Deprecations? | yes/no
+| Deprecations? | yes/no
| Tests pass? | yes
| Fixed tickets | #...
| License | MIT
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 0b1fbb47f3..1034172772 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -43,11 +43,11 @@ Symfony is the result of the work of many people who made the code better
- Diego Saint Esteben (dosten)
- Alexandre Salomé (alexandresalome)
- William Durand (couac)
+ - Hamza Amrouche (simperfit)
- ornicar
- Francis Besset (francisbesset)
- Iltar van der Berg (kjarli)
- stealth35 (stealth35)
- - Hamza Amrouche (simperfit)
- Alexander Mols (asm89)
- Yonel Ceruto (yonelceruto)
- Bulat Shakirzyanov (avalanche123)
@@ -57,8 +57,8 @@ Symfony is the result of the work of many people who made the code better
- Henrik Bjørnskov (henrikbjorn)
- Miha Vrhovnik
- Diego Saint Esteben (dii3g0)
- - Dany Maillard (maidmaid)
- Pierre du Plessis (pierredup)
+ - Dany Maillard (maidmaid)
- Konstantin Kudryashov (everzet)
- Kevin Bond (kbond)
- Bilal Amarni (bamarni)
@@ -66,6 +66,7 @@ Symfony is the result of the work of many people who made the code better
- Jérémy DERUSSÉ (jderusse)
- Florin Patan (florinpatan)
- Samuel ROZE (sroze)
+ - Tobias Nyholm (tobias)
- Gábor Egyed (1ed)
- Michel Weimerskirch (mweimerskirch)
- Andrej Hudec (pulzarraider)
@@ -75,7 +76,6 @@ Symfony is the result of the work of many people who made the code better
- Titouan Galopin (tgalopin)
- Konstantin Myakshin (koc)
- Christian Raue
- - Tobias Nyholm (tobias)
- Arnout Boks (aboks)
- Deni
- Henrik Westphal (snc)
@@ -200,6 +200,7 @@ Symfony is the result of the work of many people who made the code better
- Matthieu Bontemps (mbontemps)
- apetitpa
- Pierre Minnieur (pminnieur)
+ - Jannik Zschiesche (apfelbox)
- fivestar
- Dominique Bongiraud
- Jeremy Livingston (jeremylivingston)
@@ -224,7 +225,6 @@ Symfony is the result of the work of many people who made the code better
- Marcel Beerta (mazen)
- gadelat (gadelat)
- Loïc Faugeron
- - Jannik Zschiesche (apfelbox)
- Hidde Wieringa (hiddewie)
- Marco Pivetta (ocramius)
- Rob Frawley 2nd (robfrawley)
@@ -697,6 +697,7 @@ Symfony is the result of the work of many people who made the code better
- Nykopol (nykopol)
- Jordan Deitch
- Casper Valdemar Poulsen
+ - Remon van de Kamp
- Josiah (josiah)
- Joschi Kuphal
- John Bohn (jbohn)
@@ -736,6 +737,7 @@ Symfony is the result of the work of many people who made the code better
- Adrien Lucas (adrienlucas)
- Zhuravlev Alexander (scif)
- James Michael DuPont
+ - Xavier HAUSHERR
- Tom Klingenberg
- Christopher Hall (mythmakr)
- Patrick Dawkins (pjcdawkins)
@@ -1102,7 +1104,6 @@ Symfony is the result of the work of many people who made the code better
- Pierre Tachoire (krichprollsch)
- Marc J. Schmidt (marcjs)
- Marco Jantke
- - Remon van de Kamp
- Saem Ghani
- Clément LEFEBVRE
- Conrad Kleinespel
@@ -1225,7 +1226,6 @@ Symfony is the result of the work of many people who made the code better
- Sebastian Ionescu
- Thomas Ploch
- Simon Neidhold
- - Xavier HAUSHERR
- Valentin VALCIU
- Jeremiah VALERIE
- Kevin Dew
@@ -1573,6 +1573,7 @@ Symfony is the result of the work of many people who made the code better
- Vladimir Chernyshev (volch)
- Yorkie Chadwick (yorkie76)
- GuillaumeVerdon
+ - Philipp Keck
- Ondrej Mirtes
- akimsko
- Youpie
@@ -1630,6 +1631,7 @@ Symfony is the result of the work of many people who made the code better
- Jordan Hoff
- znerol
- Christian Eikermann
+ - Kai Eichinger
- Antonio Angelino
- Matt Fields
- Niklas Keller
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index e44535a81a..59ec772525 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -65,6 +65,7 @@
Cache\IntegrationTests
Doctrine\Common\Cache
Symfony\Component\Cache
+ Symfony\Component\Cache\Tests\Fixtures
Symfony\Component\Cache\Traits
Symfony\Component\Console
Symfony\Component\HttpFoundation
diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
index 86d96f08a1..a46617db08 100644
--- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
+++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
@@ -104,7 +104,7 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
$classMetadata = $classMetadatas[0];
// Check whether the field exists and is nullable or not
- if ($classMetadata->hasField($property)) {
+ if (isset($classMetadata->fieldMappings[$property])) {
if (!$classMetadata->isNullable($property) && Type::BOOLEAN !== $classMetadata->getTypeOfField($property)) {
return new ValueGuess(true, Guess::HIGH_CONFIDENCE);
}
@@ -133,7 +133,7 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
public function guessMaxLength($class, $property)
{
$ret = $this->getMetadata($class);
- if ($ret && $ret[0]->hasField($property) && !$ret[0]->hasAssociation($property)) {
+ if ($ret && isset($ret[0]->fieldMappings[$property]) && !$ret[0]->hasAssociation($property)) {
$mapping = $ret[0]->getFieldMapping($property);
if (isset($mapping['length'])) {
@@ -152,7 +152,7 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
public function guessPattern($class, $property)
{
$ret = $this->getMetadata($class);
- if ($ret && $ret[0]->hasField($property) && !$ret[0]->hasAssociation($property)) {
+ if ($ret && isset($ret[0]->fieldMappings[$property]) && !$ret[0]->hasAssociation($property)) {
if (in_array($ret[0]->getTypeOfField($property), array(Type::DECIMAL, Type::FLOAT))) {
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php
index 12296729e2..0eda4a3ba6 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php
@@ -33,21 +33,20 @@ class DoctrineOrmTypeGuesserTest extends TestCase
// Simple field, not nullable
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(true));
+ $classMetadata->fieldMappings['field'] = true;
$classMetadata->expects($this->once())->method('isNullable')->with('field')->will($this->returnValue(false));
$return[] = array($classMetadata, new ValueGuess(true, Guess::HIGH_CONFIDENCE));
// Simple field, nullable
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(true));
+ $classMetadata->fieldMappings['field'] = true;
$classMetadata->expects($this->once())->method('isNullable')->with('field')->will($this->returnValue(true));
$return[] = array($classMetadata, new ValueGuess(false, Guess::MEDIUM_CONFIDENCE));
// One-to-one, nullable (by default)
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false));
$classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true));
$mapping = array('joinColumns' => array(array()));
@@ -57,7 +56,6 @@ class DoctrineOrmTypeGuesserTest extends TestCase
// One-to-one, nullable (explicit)
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false));
$classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true));
$mapping = array('joinColumns' => array(array('nullable' => true)));
@@ -67,7 +65,6 @@ class DoctrineOrmTypeGuesserTest extends TestCase
// One-to-one, not nullable
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false));
$classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(true));
$mapping = array('joinColumns' => array(array('nullable' => false)));
@@ -77,7 +74,6 @@ class DoctrineOrmTypeGuesserTest extends TestCase
// One-to-many, no clue
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $classMetadata->expects($this->once())->method('hasField')->with('field')->will($this->returnValue(false));
$classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->will($this->returnValue(false));
$return[] = array($classMetadata, null);
diff --git a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php
index db388ab70b..a921582dba 100644
--- a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php
+++ b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php
@@ -54,8 +54,7 @@ class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface
*/
public function extract($resource, MessageCatalogue $catalogue)
{
- $files = $this->extractFiles($resource);
- foreach ($files as $file) {
+ foreach ($this->extractFiles($resource) as $file) {
try {
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
} catch (Error $e) {
diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json
index e2557ebc47..402c4ed9a8 100644
--- a/src/Symfony/Bridge/Twig/composer.json
+++ b/src/Symfony/Bridge/Twig/composer.json
@@ -23,7 +23,7 @@
"symfony/asset": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
- "symfony/form": "^3.4.5|^4.0.5",
+ "symfony/form": "^3.4.7|^4.0.7",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/polyfill-intl-icu": "~1.0",
@@ -41,7 +41,7 @@
"symfony/workflow": "~3.4|~4.0"
},
"conflict": {
- "symfony/form": "<3.4.5|<4.0.5,>=4.0",
+ "symfony/form": "<3.4.7|<4.0.7,>=4.0",
"symfony/console": "<3.4"
},
"suggest": {
diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
index e5839b7690..db6fe4ba61 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
@@ -28,17 +28,19 @@ class AnnotationsCacheWarmer extends AbstractPhpFileCacheWarmer
{
private $annotationReader;
private $excludeRegexp;
+ private $debug;
/**
* @param Reader $annotationReader
* @param string $phpArrayFile The PHP file where annotations are cached
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered annotations are cached
*/
- public function __construct(Reader $annotationReader, string $phpArrayFile, CacheItemPoolInterface $fallbackPool, string $excludeRegexp = null)
+ public function __construct(Reader $annotationReader, string $phpArrayFile, CacheItemPoolInterface $fallbackPool, string $excludeRegexp = null, bool $debug = false)
{
parent::__construct($phpArrayFile, $fallbackPool);
$this->annotationReader = $annotationReader;
$this->excludeRegexp = $excludeRegexp;
+ $this->debug = $debug;
}
/**
@@ -53,7 +55,7 @@ class AnnotationsCacheWarmer extends AbstractPhpFileCacheWarmer
}
$annotatedClasses = include $annotatedClassPatterns;
- $reader = new CachedReader($this->annotationReader, new DoctrineProvider($arrayAdapter));
+ $reader = new CachedReader($this->annotationReader, new DoctrineProvider($arrayAdapter), $this->debug);
foreach ($annotatedClasses as $class) {
if (null !== $this->excludeRegexp && preg_match($this->excludeRegexp, $class)) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
index 5877caaf59..063097d9b4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
+++ b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
@@ -11,7 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\HttpCache;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\HttpKernel\HttpCache\HttpCache as BaseHttpCache;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\HttpCache\Store;
@@ -23,16 +23,16 @@ use Symfony\Component\HttpFoundation\Response;
*
* @author Fabien Potencier
*/
-abstract class HttpCache extends BaseHttpCache
+class HttpCache extends BaseHttpCache
{
protected $cacheDir;
protected $kernel;
/**
- * @param HttpKernelInterface $kernel An HttpKernelInterface instance
- * @param string $cacheDir The cache directory (default used if null)
+ * @param KernelInterface $kernel A KernelInterface instance
+ * @param string $cacheDir The cache directory (default used if null)
*/
- public function __construct(HttpKernelInterface $kernel, string $cacheDir = null)
+ public function __construct(KernelInterface $kernel, string $cacheDir = null)
{
$this->kernel = $kernel;
$this->cacheDir = $cacheDir;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml
index 6e8cc4f9e6..2b4ea42962 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml
@@ -38,6 +38,7 @@
%kernel.cache_dir%/annotations.php
#^Symfony\\(?:Component\\HttpKernel\\|Bundle\\FrameworkBundle\\Controller\\(?!AbstractController$|Controller$))#
+ %kernel.debug%
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php
new file mode 100644
index 0000000000..b32274e7e7
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php
@@ -0,0 +1,103 @@
+cacheDir = sys_get_temp_dir().'/'.uniqid();
+ $fs = new Filesystem();
+ $fs->mkdir($this->cacheDir);
+ parent::setUp();
+ }
+
+ protected function tearDown()
+ {
+ $fs = new Filesystem();
+ $fs->remove($this->cacheDir);
+ parent::tearDown();
+ }
+
+ public function testAnnotationsCacheWarmerWithDebugDisabled()
+ {
+ file_put_contents($this->cacheDir.'/annotations.map', sprintf('cacheDir, __FUNCTION__);
+ $reader = new AnnotationReader();
+ $fallbackPool = new ArrayAdapter();
+ $warmer = new AnnotationsCacheWarmer(
+ $reader,
+ $cacheFile,
+ $fallbackPool,
+ null
+ );
+ $warmer->warmUp($this->cacheDir);
+ $this->assertFileExists($cacheFile);
+
+ // Assert cache is valid
+ $reader = new CachedReader(
+ $this->getReadOnlyReader(),
+ new DoctrineProvider(new PhpArrayAdapter($cacheFile, new NullAdapter()))
+ );
+ $refClass = new \ReflectionClass($this);
+ $reader->getClassAnnotations($refClass);
+ $reader->getMethodAnnotations($refClass->getMethod(__FUNCTION__));
+ $reader->getPropertyAnnotations($refClass->getProperty('cacheDir'));
+ }
+
+ public function testAnnotationsCacheWarmerWithDebugEnabled()
+ {
+ file_put_contents($this->cacheDir.'/annotations.map', sprintf('cacheDir, __FUNCTION__);
+ $reader = new AnnotationReader();
+ $fallbackPool = new ArrayAdapter();
+ $warmer = new AnnotationsCacheWarmer(
+ $reader,
+ $cacheFile,
+ $fallbackPool,
+ null,
+ true
+ );
+ $warmer->warmUp($this->cacheDir);
+ $this->assertFileExists($cacheFile);
+ // Assert cache is valid
+ $reader = new CachedReader(
+ $this->getReadOnlyReader(),
+ new DoctrineProvider(new PhpArrayAdapter($cacheFile, new NullAdapter())),
+ true
+ );
+ $refClass = new \ReflectionClass($this);
+ $reader->getClassAnnotations($refClass);
+ $reader->getMethodAnnotations($refClass->getMethod(__FUNCTION__));
+ $reader->getPropertyAnnotations($refClass->getProperty('cacheDir'));
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|Reader
+ */
+ private function getReadOnlyReader()
+ {
+ $readerMock = $this->getMockBuilder('Doctrine\Common\Annotations\Reader')->getMock();
+ $readerMock->expects($this->exactly(0))->method('getClassAnnotations');
+ $readerMock->expects($this->exactly(0))->method('getClassAnnotation');
+ $readerMock->expects($this->exactly(0))->method('getMethodAnnotations');
+ $readerMock->expects($this->exactly(0))->method('getMethodAnnotation');
+ $readerMock->expects($this->exactly(0))->method('getPropertyAnnotations');
+ $readerMock->expects($this->exactly(0))->method('getPropertyAnnotation');
+
+ return $readerMock;
+ }
+}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php
index 1f45ab1a44..c3be9ebd6d 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SimpleFormFactory.php
@@ -55,6 +55,7 @@ class SimpleFormFactory extends FormLoginFactory
->replaceArgument(0, new Reference($config['authenticator']))
->replaceArgument(1, new Reference($userProviderId))
->replaceArgument(2, $id)
+ ->replaceArgument(3, new Reference('security.user_checker.'.$id))
;
return $provider;
diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php
index a2201c9ce1..480f02b948 100644
--- a/src/Symfony/Component/BrowserKit/Cookie.php
+++ b/src/Symfony/Component/BrowserKit/Cookie.php
@@ -44,14 +44,14 @@ class Cookie
/**
* Sets a cookie.
*
- * @param string $name The cookie name
- * @param string $value The value of the cookie
- * @param string $expires The time the cookie expires
- * @param string $path The path on the server in which the cookie will be available on
- * @param string $domain The domain that the cookie is available
- * @param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client
- * @param bool $httponly The cookie httponly flag
- * @param bool $encodedValue Whether the value is encoded or not
+ * @param string $name The cookie name
+ * @param string $value The value of the cookie
+ * @param string|null $expires The time the cookie expires
+ * @param string|null $path The path on the server in which the cookie will be available on
+ * @param string $domain The domain that the cookie is available
+ * @param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client
+ * @param bool $httponly The cookie httponly flag
+ * @param bool $encodedValue Whether the value is encoded or not
*/
public function __construct(string $name, ?string $value, string $expires = null, string $path = null, string $domain = '', bool $secure = false, bool $httponly = true, bool $encodedValue = false)
{
@@ -112,8 +112,8 @@ class Cookie
/**
* Creates a Cookie instance from a Set-Cookie header value.
*
- * @param string $cookie A Set-Cookie header value
- * @param string $url The base URL
+ * @param string $cookie A Set-Cookie header value
+ * @param string|null $url The base URL
*
* @return static
*
@@ -242,7 +242,7 @@ class Cookie
/**
* Gets the expires time of the cookie.
*
- * @return string The cookie expires time
+ * @return string|null The cookie expires time
*/
public function getExpiresTime()
{
diff --git a/src/Symfony/Component/BrowserKit/CookieJar.php b/src/Symfony/Component/BrowserKit/CookieJar.php
index 232cefc8b6..7a4d64c10e 100644
--- a/src/Symfony/Component/BrowserKit/CookieJar.php
+++ b/src/Symfony/Component/BrowserKit/CookieJar.php
@@ -43,32 +43,21 @@ class CookieJar
{
$this->flushExpiredCookies();
- if (!empty($domain)) {
- foreach ($this->cookieJar as $cookieDomain => $pathCookies) {
- if ($cookieDomain) {
- $cookieDomain = '.'.ltrim($cookieDomain, '.');
- if ($cookieDomain != substr('.'.$domain, -strlen($cookieDomain))) {
- continue;
- }
- }
-
- foreach ($pathCookies as $cookiePath => $namedCookies) {
- if ($cookiePath != substr($path, 0, strlen($cookiePath))) {
- continue;
- }
- if (isset($namedCookies[$name])) {
- return $namedCookies[$name];
- }
+ foreach ($this->cookieJar as $cookieDomain => $pathCookies) {
+ if ($cookieDomain && $domain) {
+ $cookieDomain = '.'.ltrim($cookieDomain, '.');
+ if ($cookieDomain !== substr('.'.$domain, -\strlen($cookieDomain))) {
+ continue;
}
}
- return;
- }
-
- // avoid relying on this behavior that is mainly here for BC reasons
- foreach ($this->cookieJar as $cookies) {
- if (isset($cookies[$path][$name])) {
- return $cookies[$path][$name];
+ foreach ($pathCookies as $cookiePath => $namedCookies) {
+ if (0 !== strpos($path, $cookiePath)) {
+ continue;
+ }
+ if (isset($namedCookies[$name])) {
+ return $namedCookies[$name];
+ }
}
}
}
diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php
index 9c9e122e86..3117e5ce47 100644
--- a/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php
@@ -237,6 +237,8 @@ class CookieJarTest extends TestCase
$this->assertEquals($cookie1, $cookieJar->get('foo', '/test', 'example.com'));
$this->assertEquals($cookie2, $cookieJar->get('foo1', '/', 'example.com'));
$this->assertEquals($cookie2, $cookieJar->get('foo1', '/bar', 'example.com'));
+
+ $this->assertEquals($cookie2, $cookieJar->get('foo1', '/bar'));
}
public function testCookieWithWildcardDomain()
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php
index 93ec982438..8d4dfe2858 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/DoctrineAdapterTest.php
@@ -11,8 +11,8 @@
namespace Symfony\Component\Cache\Tests\Adapter;
-use Doctrine\Common\Cache\ArrayCache;
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
+use Symfony\Component\Cache\Tests\Fixtures\ArrayCache;
/**
* @group time-sensitive
diff --git a/src/Symfony/Component/Cache/Tests/Fixtures/ArrayCache.php b/src/Symfony/Component/Cache/Tests/Fixtures/ArrayCache.php
new file mode 100644
index 0000000000..1a6157e822
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Fixtures/ArrayCache.php
@@ -0,0 +1,52 @@
+doContains($id) ? $this->data[$id][0] : false;
+ }
+
+ protected function doContains($id)
+ {
+ if (!isset($this->data[$id])) {
+ return false;
+ }
+
+ $expiry = $this->data[$id][1];
+
+ return !$expiry || time() <= $expiry || !$this->doDelete($id);
+ }
+
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ $this->data[$id] = array($data, $lifeTime ? time() + $lifeTime : false);
+
+ return true;
+ }
+
+ protected function doDelete($id)
+ {
+ unset($this->data[$id]);
+
+ return true;
+ }
+
+ protected function doFlush()
+ {
+ $this->data = array();
+
+ return true;
+ }
+
+ protected function doGetStats()
+ {
+ return null;
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php
index 0a185297ab..127c96858c 100644
--- a/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php
+++ b/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php
@@ -11,8 +11,8 @@
namespace Symfony\Component\Cache\Tests\Simple;
-use Doctrine\Common\Cache\ArrayCache;
use Symfony\Component\Cache\Simple\DoctrineCache;
+use Symfony\Component\Cache\Tests\Fixtures\ArrayCache;
/**
* @group time-sensitive
diff --git a/src/Symfony/Component/Cache/phpunit.xml.dist b/src/Symfony/Component/Cache/phpunit.xml.dist
index 6b5c79331d..9b3c30d76f 100644
--- a/src/Symfony/Component/Cache/phpunit.xml.dist
+++ b/src/Symfony/Component/Cache/phpunit.xml.dist
@@ -39,6 +39,7 @@
Cache\IntegrationTests
Doctrine\Common\Cache
Symfony\Component\Cache
+ Symfony\Component\Cache\Tests\Fixtures
Symfony\Component\Cache\Traits
diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php
index fa2faea7fe..5f51a5da41 100644
--- a/src/Symfony/Component/Config/Definition/ArrayNode.php
+++ b/src/Symfony/Component/Config/Definition/ArrayNode.php
@@ -153,9 +153,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
}
/**
- * Sets the node Name.
- *
- * @param string $name The node's name
+ * {@inheritdoc}
*/
public function setName($name)
{
@@ -163,9 +161,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
}
/**
- * Checks if the node has a default value.
- *
- * @return bool
+ * {@inheritdoc}
*/
public function hasDefaultValue()
{
@@ -173,11 +169,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
}
/**
- * Retrieves the default value.
- *
- * @return array The default value
- *
- * @throws \RuntimeException if the node has no default value
+ * {@inheritdoc}
*/
public function getDefaultValue()
{
diff --git a/src/Symfony/Component/Config/Definition/BaseNode.php b/src/Symfony/Component/Config/Definition/BaseNode.php
index b0a32c1b35..d942b28cc7 100644
--- a/src/Symfony/Component/Config/Definition/BaseNode.php
+++ b/src/Symfony/Component/Config/Definition/BaseNode.php
@@ -41,7 +41,7 @@ abstract class BaseNode implements NodeInterface
*/
public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR)
{
- if (false !== strpos($name, $pathSeparator)) {
+ if (false !== strpos($name = (string) , $pathSeparator)) {
throw new \InvalidArgumentException('The name must not contain "'.$pathSeparator.'".');
}
@@ -185,9 +185,7 @@ abstract class BaseNode implements NodeInterface
}
/**
- * Checks if this node is required.
- *
- * @return bool
+ * {@inheritdoc}
*/
public function isRequired()
{
@@ -218,9 +216,7 @@ abstract class BaseNode implements NodeInterface
}
/**
- * Returns the name of this node.
- *
- * @return string The Node's name
+ * {@inheritdoc}
*/
public function getName()
{
@@ -228,9 +224,7 @@ abstract class BaseNode implements NodeInterface
}
/**
- * Retrieves the path of this node.
- *
- * @return string The Node's path
+ * {@inheritdoc}
*/
public function getPath()
{
@@ -242,14 +236,7 @@ abstract class BaseNode implements NodeInterface
}
/**
- * Merges two values together.
- *
- * @param mixed $leftSide
- * @param mixed $rightSide
- *
- * @return mixed The merged value
- *
- * @throws ForbiddenOverwriteException
+ * {@inheritdoc}
*/
final public function merge($leftSide, $rightSide)
{
@@ -269,11 +256,7 @@ abstract class BaseNode implements NodeInterface
}
/**
- * Normalizes a value, applying all normalization closures.
- *
- * @param mixed $value Value to normalize
- *
- * @return mixed The normalized value
+ * {@inheritdoc}
*/
final public function normalize($value)
{
@@ -321,14 +304,7 @@ abstract class BaseNode implements NodeInterface
}
/**
- * Finalizes a value, applying all finalization closures.
- *
- * @param mixed $value The value to finalize
- *
- * @return mixed The finalized value
- *
- * @throws Exception
- * @throws InvalidConfigurationException
+ * {@inheritdoc}
*/
final public function finalize($value)
{
diff --git a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
index c39bd0ad11..febcc67c7c 100644
--- a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
+++ b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
@@ -48,7 +48,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
}
/**
- * Sets a custom children builder.
+ * {@inheritdoc}
*/
public function setBuilder(NodeBuilder $builder)
{
@@ -56,9 +56,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
}
/**
- * Returns a builder to add children nodes.
- *
- * @return NodeBuilder
+ * {@inheritdoc}
*/
public function children()
{
@@ -366,17 +364,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
}
/**
- * Appends a node definition.
- *
- * $node = new ArrayNodeDefinition()
- * ->children()
- * ->scalarNode('foo')->end()
- * ->scalarNode('baz')->end()
- * ->end()
- * ->append($this->getBarNodeDefinition())
- * ;
- *
- * @return $this
+ * {@inheritdoc}
*/
public function append(NodeDefinition $node)
{
diff --git a/src/Symfony/Component/Config/Definition/Builder/BuilderAwareInterface.php b/src/Symfony/Component/Config/Definition/Builder/BuilderAwareInterface.php
index 8efbb58e21..f30b8736cf 100644
--- a/src/Symfony/Component/Config/Definition/Builder/BuilderAwareInterface.php
+++ b/src/Symfony/Component/Config/Definition/Builder/BuilderAwareInterface.php
@@ -18,5 +18,8 @@ namespace Symfony\Component\Config\Definition\Builder;
*/
interface BuilderAwareInterface
{
+ /**
+ * Sets a custom children builder.
+ */
public function setBuilder(NodeBuilder $builder);
}
diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
index bf43861fc1..ea2e42c1c6 100644
--- a/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
@@ -143,8 +143,8 @@ class NodeBuilder implements NodeParentInterface
/**
* Creates a child node.
*
- * @param string $name The name of the node
- * @param string $type The type of the node
+ * @param string|null $name The name of the node
+ * @param string $type The type of the node
*
* @return NodeDefinition The child node
*
diff --git a/src/Symfony/Component/Config/Definition/Builder/ParentNodeDefinitionInterface.php b/src/Symfony/Component/Config/Definition/Builder/ParentNodeDefinitionInterface.php
index c75de68cab..41c52c235e 100644
--- a/src/Symfony/Component/Config/Definition/Builder/ParentNodeDefinitionInterface.php
+++ b/src/Symfony/Component/Config/Definition/Builder/ParentNodeDefinitionInterface.php
@@ -21,9 +21,26 @@ namespace Symfony\Component\Config\Definition\Builder;
interface ParentNodeDefinitionInterface extends BuilderAwareInterface
{
/**
+ * Returns a builder to add children nodes.
+ *
* @return NodeBuilder
*/
public function children();
+ /**
+ * Appends a node definition.
+ *
+ * Usage:
+ *
+ * $node = $parentNode
+ * ->children()
+ * ->scalarNode('foo')->end()
+ * ->scalarNode('baz')->end()
+ * ->append($this->getBarNodeDefinition())
+ * ->end()
+ * ;
+ *
+ * @return $this
+ */
public function append(NodeDefinition $node);
}
diff --git a/src/Symfony/Component/Config/Definition/NodeInterface.php b/src/Symfony/Component/Config/Definition/NodeInterface.php
index b9bddc4938..45f1f681c1 100644
--- a/src/Symfony/Component/Config/Definition/NodeInterface.php
+++ b/src/Symfony/Component/Config/Definition/NodeInterface.php
@@ -11,6 +11,10 @@
namespace Symfony\Component\Config\Definition;
+use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+
/**
* Common Interface among all nodes.
*
@@ -59,11 +63,13 @@ interface NodeInterface
public function getDefaultValue();
/**
- * Normalizes the supplied value.
+ * Normalizes a value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
+ *
+ * @throws InvalidTypeException if the value type is invalid
*/
public function normalize($value);
@@ -73,7 +79,10 @@ interface NodeInterface
* @param mixed $leftSide
* @param mixed $rightSide
*
- * @return mixed The merged values
+ * @return mixed The merged value
+ *
+ * @throws ForbiddenOverwriteException if the configuration path cannot be overwritten
+ * @throws InvalidTypeException if the value type is invalid
*/
public function merge($leftSide, $rightSide);
@@ -83,6 +92,9 @@ interface NodeInterface
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
+ *
+ * @throws InvalidTypeException if the value type is invalid
+ * @throws InvalidConfigurationException if the value is invalid configuration
*/
public function finalize($value);
}
diff --git a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php
index c576198b54..d183a60525 100644
--- a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php
+++ b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php
@@ -102,9 +102,7 @@ class PrototypedArrayNode extends ArrayNode
}
/**
- * Checks if the node has a default value.
- *
- * @return bool
+ * {@inheritdoc}
*/
public function hasDefaultValue()
{
@@ -126,12 +124,10 @@ class PrototypedArrayNode extends ArrayNode
}
/**
- * Retrieves the default value.
+ * {@inheritdoc}
*
* The default value could be either explicited or derived from the prototype
* default value.
- *
- * @return array The default value
*/
public function getDefaultValue()
{
diff --git a/src/Symfony/Component/Config/Definition/VariableNode.php b/src/Symfony/Component/Config/Definition/VariableNode.php
index a9c35284cd..0cd84c72bf 100644
--- a/src/Symfony/Component/Config/Definition/VariableNode.php
+++ b/src/Symfony/Component/Config/Definition/VariableNode.php
@@ -27,9 +27,6 @@ class VariableNode extends BaseNode implements PrototypeNodeInterface
protected $defaultValue;
protected $allowEmptyValue = true;
- /**
- * {@inheritdoc}
- */
public function setDefaultValue($value)
{
$this->defaultValueSet = true;
diff --git a/src/Symfony/Component/Config/Tests/ConfigCacheFactoryTest.php b/src/Symfony/Component/Config/Tests/ConfigCacheFactoryTest.php
index c523e5cd5e..24e3224ce5 100644
--- a/src/Symfony/Component/Config/Tests/ConfigCacheFactoryTest.php
+++ b/src/Symfony/Component/Config/Tests/ConfigCacheFactoryTest.php
@@ -20,7 +20,7 @@ class ConfigCacheFactoryTest extends TestCase
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Invalid type for callback argument. Expected callable, but got "object".
*/
- public function testCachWithInvalidCallback()
+ public function testCacheWithInvalidCallback()
{
$cacheFactory = new ConfigCacheFactory(true);
diff --git a/src/Symfony/Component/Console/Descriptor/DescriptorInterface.php b/src/Symfony/Component/Console/Descriptor/DescriptorInterface.php
index 3929b6d9ed..5d3339a9e6 100644
--- a/src/Symfony/Component/Console/Descriptor/DescriptorInterface.php
+++ b/src/Symfony/Component/Console/Descriptor/DescriptorInterface.php
@@ -21,7 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
interface DescriptorInterface
{
/**
- * Describes an InputArgument instance.
+ * Describes an object if supported.
*
* @param OutputInterface $output
* @param object $object
diff --git a/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php b/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
index dffb079d75..5f16ac48f8 100644
--- a/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
+++ b/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
@@ -46,7 +46,7 @@ class TokenizerPatterns
$this->nonAsciiPattern = '[^\x00-\x7F]';
$this->nmCharPattern = '[_a-z0-9-]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
$this->nmStartPattern = '[_a-z]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
- $this->identifierPattern = '(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
+ $this->identifierPattern = '-?(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
$this->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
$this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
$this->quotedStringPattern = '([^\n\r\f%s]|'.$this->stringEscapePattern.')*';
diff --git a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
index 37a3ef1d58..53b35a9547 100644
--- a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
+++ b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
@@ -186,6 +186,7 @@ class ParserTest extends TestCase
array('foo:after', 'Element[foo]', 'after'),
array('foo::selection', 'Element[foo]', 'selection'),
array('lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'),
+ array('video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'),
);
}
diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php
index 00149b38e5..5dbdd69338 100644
--- a/src/Symfony/Component/Debug/ErrorHandler.php
+++ b/src/Symfony/Component/Debug/ErrorHandler.php
@@ -547,14 +547,15 @@ class ErrorHandler
}
}
}
+ $exceptionHandler = $this->exceptionHandler;
+ $this->exceptionHandler = null;
try {
- if (null !== $this->exceptionHandler) {
- return \call_user_func($this->exceptionHandler, $exception);
+ if (null !== $exceptionHandler) {
+ return \call_user_func($exceptionHandler, $exception);
}
$handlerException = $handlerException ?: $exception;
} catch (\Throwable $handlerException) {
}
- $this->exceptionHandler = null;
if ($exception === $handlerException) {
self::$reservedMemory = null; // Disable the fatal error handler
throw $exception; // Give back $exception to the native handler
diff --git a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
index 0d57204481..afe16ea4f7 100644
--- a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
+++ b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
@@ -464,4 +464,17 @@ class ErrorHandlerTest extends TestCase
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
}
+
+ /**
+ * @expectedException \Exception
+ */
+ public function testCustomExceptionHandler()
+ {
+ $handler = new ErrorHandler();
+ $handler->setExceptionHandler(function ($e) use ($handler) {
+ $handler->handleException($e);
+ });
+
+ $handler->handleException(new \Exception());
+ }
}
diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php
index 1e1c4a7848..7b4d5170c1 100644
--- a/src/Symfony/Component/DomCrawler/Crawler.php
+++ b/src/Symfony/Component/DomCrawler/Crawler.php
@@ -648,7 +648,7 @@ class Crawler implements \Countable, \IteratorAggregate
}
}
- $data[] = $count > 1 ? $elements : $elements[0];
+ $data[] = 1 === $count ? $elements[0] : $elements;
}
return $data;
diff --git a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php
index 6d321e0282..4d3aebfba5 100644
--- a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php
+++ b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php
@@ -97,14 +97,14 @@ class ChoiceFormField extends FormField
}
/**
- * Ticks a checkbox.
+ * Unticks a checkbox.
*
* @throws \LogicException When the type provided is not correct
*/
public function untick()
{
if ('checkbox' !== $this->type) {
- throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type));
+ throw new \LogicException(sprintf('You cannot untick "%s" as it is not a checkbox (%s).', $this->name, $this->type));
}
$this->setValue(false);
@@ -113,7 +113,7 @@ class ChoiceFormField extends FormField
/**
* Sets the value of the field.
*
- * @param string $value The value of the field
+ * @param string|array $value The value of the field
*
* @throws \InvalidArgumentException When value type provided is not correct
*/
diff --git a/src/Symfony/Component/DomCrawler/Field/InputFormField.php b/src/Symfony/Component/DomCrawler/Field/InputFormField.php
index 090913efa3..1c3c84d721 100644
--- a/src/Symfony/Component/DomCrawler/Field/InputFormField.php
+++ b/src/Symfony/Component/DomCrawler/Field/InputFormField.php
@@ -32,11 +32,12 @@ class InputFormField extends FormField
throw new \LogicException(sprintf('An InputFormField can only be created from an input or button tag (%s given).', $this->node->nodeName));
}
- if ('checkbox' === strtolower($this->node->getAttribute('type'))) {
+ $type = strtolower($this->node->getAttribute('type'));
+ if ('checkbox' === $type) {
throw new \LogicException('Checkboxes should be instances of ChoiceFormField.');
}
- if ('file' === strtolower($this->node->getAttribute('type'))) {
+ if ('file' === $type) {
throw new \LogicException('File inputs should be instances of FileFormField.');
}
diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
index ec8512e4ef..a8dc525e55 100644
--- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
@@ -413,6 +413,7 @@ EOF
$this->assertEquals(array('One', 'Two', 'Three'), $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list');
$this->assertEquals(array(array('One', 'first'), array('Two', ''), array('Three', '')), $crawler->extract(array('_text', 'class')), '->extract() returns an array of extracted data from the node list');
+ $this->assertEquals(array(array(), array(), array()), $crawler->extract(array()), '->extract() returns empty arrays if the attribute list is empty');
$this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty');
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 9a8c7d427b..1beb6ab806 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -80,6 +80,7 @@ class FormType extends BaseType
}
}
+ $formConfig = $form->getConfig();
$view->vars = array_replace($view->vars, array(
'errors' => $form->getErrors(),
'valid' => $form->isSubmitted() ? $form->isValid() : true,
@@ -88,9 +89,9 @@ class FormType extends BaseType
'required' => $form->isRequired(),
'size' => null,
'label_attr' => $options['label_attr'],
- 'compound' => $form->getConfig()->getCompound(),
- 'method' => $form->getConfig()->getMethod(),
- 'action' => $form->getConfig()->getAction(),
+ 'compound' => $formConfig->getCompound(),
+ 'method' => $formConfig->getMethod(),
+ 'action' => $formConfig->getAction(),
'submitted' => $form->isSubmitted(),
));
}
diff --git a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
index 410eedc2ae..bd116d2a71 100644
--- a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
+++ b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
@@ -52,9 +52,7 @@ class ValidationListener implements EventSubscriberInterface
if ($form->isRoot()) {
// Validate the form in group "Default"
- $violations = $this->validator->validate($form);
-
- foreach ($violations as $violation) {
+ foreach ($this->validator->validate($form) as $violation) {
// Allow the "invalid" constraint to be put onto
// non-synchronized forms
// ConstraintViolation::getConstraint() must not expect to provide a constraint as long as Symfony\Component\Validator\ExecutionContext exists (before 3.0)
diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
index bde7458258..207015b2ce 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
@@ -253,12 +253,8 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
$classMetadata = $this->metadataFactory->getMetadataFor($class);
if ($classMetadata instanceof ClassMetadataInterface && $classMetadata->hasPropertyMetadata($property)) {
- $memberMetadatas = $classMetadata->getPropertyMetadata($property);
-
- foreach ($memberMetadatas as $memberMetadata) {
- $constraints = $memberMetadata->getConstraints();
-
- foreach ($constraints as $constraint) {
+ foreach ($classMetadata->getPropertyMetadata($property) as $memberMetadata) {
+ foreach ($memberMetadata->getConstraints() as $constraint) {
if ($guess = $closure($constraint)) {
$guesses[] = $guess;
}
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
index 6e448c413a..beabaa21cd 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
@@ -166,10 +166,10 @@ abstract class AbstractBootstrap4LayoutTest extends AbstractBootstrap3LayoutTest
./span[@class="mb-0 d-block"]
[./span[.="[trans]Error[/trans]"]]
[./span[.="[trans]Error 1[/trans]"]]
-
+
/following-sibling::span[@class="mb-0 d-block"]
[./span[.="[trans]Error[/trans]"]]
- [./span[.="[trans]Error 2[/trans]"]]
+ [./span[.="[trans]Error 2[/trans]"]]
]
[count(./span)=2]
'
diff --git a/src/Symfony/Component/Intl/Intl.php b/src/Symfony/Component/Intl/Intl.php
index 3444c10f83..e552b994fd 100644
--- a/src/Symfony/Component/Intl/Intl.php
+++ b/src/Symfony/Component/Intl/Intl.php
@@ -15,6 +15,7 @@ use Symfony\Component\Intl\Data\Bundle\Reader\JsonBundleReader;
use Symfony\Component\Intl\Data\Bundle\Reader\BufferedBundleReader;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
+use Symfony\Component\Intl\Data\Provider\LocaleDataProvider;
use Symfony\Component\Intl\Data\Provider\ScriptDataProvider;
use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
use Symfony\Component\Intl\ResourceBundle\CurrencyBundleInterface;
@@ -259,6 +260,11 @@ final class Intl
new JsonBundleReader(),
self::BUFFER_SIZE
));
+ $localeDataProvider = new LocaleDataProvider(
+ self::getDataDirectory().'/'.self::LOCALE_DIR,
+ self::$entryReader
+ );
+ self::$entryReader->setLocaleAliases($localeDataProvider->getAliases());
}
return self::$entryReader;
diff --git a/src/Symfony/Component/Intl/Tests/IntlTest.php b/src/Symfony/Component/Intl/Tests/IntlTest.php
new file mode 100644
index 0000000000..d77655b77d
--- /dev/null
+++ b/src/Symfony/Component/Intl/Tests/IntlTest.php
@@ -0,0 +1,84 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Intl\Tests;
+
+use Symfony\Component\Intl\Intl;
+use PHPUnit\Framework\TestCase;
+
+class IntlTest extends TestCase
+{
+ /**
+ * @requires extension intl
+ */
+ public function testIsExtensionLoadedChecksIfIntlExtensionIsLoaded()
+ {
+ $this->assertTrue(Intl::isExtensionLoaded());
+ }
+
+ public function testGetCurrencyBundleCreatesTheCurrencyBundle()
+ {
+ $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\CurrencyBundleInterface', Intl::getCurrencyBundle());
+ }
+
+ public function testGetLanguageBundleCreatesTheLanguageBundle()
+ {
+ $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface', Intl::getLanguageBundle());
+ }
+
+ public function testGetLocaleBundleCreatesTheLocaleBundle()
+ {
+ $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface', Intl::getLocaleBundle());
+ }
+
+ public function testGetRegionBundleCreatesTheRegionBundle()
+ {
+ $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface', Intl::getLocaleBundle());
+ }
+
+ public function testGetIcuVersionReadsTheVersionOfInstalledIcuLibrary()
+ {
+ $this->assertStringMatchesFormat('%d.%d', Intl::getIcuVersion());
+ }
+
+ public function testGetIcuDataVersionReadsTheVersionOfInstalledIcuData()
+ {
+ $this->assertStringMatchesFormat('%d.%d', Intl::getIcuDataVersion());
+ }
+
+ public function testGetIcuStubVersionReadsTheVersionOfBundledStubs()
+ {
+ $this->assertStringMatchesFormat('%d.%d', Intl::getIcuStubVersion());
+ }
+
+ public function testGetDataDirectoryReturnsThePathToIcuData()
+ {
+ $this->assertTrue(is_dir(Intl::getDataDirectory()));
+ }
+
+ /**
+ * @requires extension intl
+ */
+ public function testLocaleAliasesAreLoaded()
+ {
+ \Locale::setDefault('zh_TW');
+ $countryNameZhTw = Intl::getRegionBundle()->getCountryName('AD');
+
+ \Locale::setDefault('zh_Hant_TW');
+ $countryNameHantZhTw = Intl::getRegionBundle()->getCountryName('AD');
+
+ \Locale::setDefault('zh');
+ $countryNameZh = Intl::getRegionBundle()->getCountryName('AD');
+
+ $this->assertSame($countryNameZhTw, $countryNameHantZhTw, 'zh_TW is an alias to zh_Hant_TW');
+ $this->assertNotSame($countryNameZh, $countryNameZhTw, 'zh_TW does not fall back to zh');
+ }
+}
diff --git a/src/Symfony/Component/Process/PhpExecutableFinder.php b/src/Symfony/Component/Process/PhpExecutableFinder.php
index ef79065ff7..1916274faf 100644
--- a/src/Symfony/Component/Process/PhpExecutableFinder.php
+++ b/src/Symfony/Component/Process/PhpExecutableFinder.php
@@ -47,7 +47,7 @@ class PhpExecutableFinder
$args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
// PHP_BINARY return the current sapi executable
- if (PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg')) && is_file(PHP_BINARY)) {
+ if (PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg'))) {
return PHP_BINARY.$args;
}
diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php
index d3f5ad6291..0c16c96aeb 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Core\Authentication\Provider;
+use Symfony\Component\Security\Core\User\UserChecker;
+use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface;
@@ -24,23 +26,29 @@ class SimpleAuthenticationProvider implements AuthenticationProviderInterface
private $simpleAuthenticator;
private $userProvider;
private $providerKey;
+ private $userChecker;
- public function __construct(SimpleAuthenticatorInterface $simpleAuthenticator, UserProviderInterface $userProvider, string $providerKey)
+ public function __construct(SimpleAuthenticatorInterface $simpleAuthenticator, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker = null)
{
$this->simpleAuthenticator = $simpleAuthenticator;
$this->userProvider = $userProvider;
$this->providerKey = $providerKey;
+ $this->userChecker = $userChecker ?: new UserChecker();
}
public function authenticate(TokenInterface $token)
{
$authToken = $this->simpleAuthenticator->authenticateToken($token, $this->userProvider, $this->providerKey);
- if ($authToken instanceof TokenInterface) {
- return $authToken;
+ if (!$authToken instanceof TokenInterface) {
+ throw new AuthenticationException('Simple authenticator failed to return an authenticated token.');
}
- throw new AuthenticationException('Simple authenticator failed to return an authenticated token.');
+ $user = $authToken->getUser();
+ $this->userChecker->checkPreAuth($user);
+ $this->userChecker->checkPostAuth($user);
+
+ return $authToken;
}
public function supports(TokenInterface $token)
diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php
new file mode 100644
index 0000000000..1e7069c1fa
--- /dev/null
+++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php
@@ -0,0 +1,89 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Authentication\Provider;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Security\Core\Exception\DisabledException;
+use Symfony\Component\Security\Core\Authentication\Provider\SimpleAuthenticationProvider;
+use Symfony\Component\Security\Core\Exception\LockedException;
+
+class SimpleAuthenticationProviderTest extends TestCase
+{
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\DisabledException
+ */
+ public function testAuthenticateWhenPreChecksFails()
+ {
+ $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
+
+ $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
+ $token->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $userChecker = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserCheckerInterface')->getMock();
+ $userChecker->expects($this->once())
+ ->method('checkPreAuth')
+ ->will($this->throwException(new DisabledException()));
+
+ $authenticator = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface')->getMock();
+ $authenticator->expects($this->once())
+ ->method('authenticateToken')
+ ->will($this->returnValue($token));
+
+ $provider = $this->getProvider($authenticator, null, $userChecker);
+
+ $provider->authenticate($token);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\LockedException
+ */
+ public function testAuthenticateWhenPostChecksFails()
+ {
+ $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
+
+ $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
+ $token->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $userChecker = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserCheckerInterface')->getMock();
+ $userChecker->expects($this->once())
+ ->method('checkPostAuth')
+ ->will($this->throwException(new LockedException()));
+
+ $authenticator = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface')->getMock();
+ $authenticator->expects($this->once())
+ ->method('authenticateToken')
+ ->will($this->returnValue($token));
+
+ $provider = $this->getProvider($authenticator, null, $userChecker);
+
+ $provider->authenticate($token);
+ }
+
+ protected function getProvider($simpleAuthenticator = null, $userProvider = null, $userChecker = null, $key = 'test')
+ {
+ if (null === $userChecker) {
+ $userChecker = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserCheckerInterface')->getMock();
+ }
+ if (null === $simpleAuthenticator) {
+ $simpleAuthenticator = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface')->getMock();
+ }
+ if (null === $userProvider) {
+ $userProvider = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserProviderInterface')->getMock();
+ }
+
+ return new SimpleAuthenticationProvider($simpleAuthenticator, $userProvider, $key, $userChecker);
+ }
+}
diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
index caba1fcb20..dd0dd1fa46 100644
--- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
+++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
@@ -47,7 +47,7 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
public $defaultGroup;
/**
- * @var MemberMetadata[]
+ * @var MemberMetadata[][]
*
* @internal This property is public in order to reduce the size of the
* class' serialized representation. Do not access it. Use