diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index 7d19467d80..6a2eaea10d 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -194,6 +194,7 @@ Security * The `LdapUserProvider` class has been deprecated, use `Symfony\Component\Ldap\Security\LdapUserProvider` instead. * Implementations of `PasswordEncoderInterface` and `UserPasswordEncoderInterface` should add a new `needsRehash()` method + * Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`. Please explicitly return `false` to indicate invalid credentials. Stopwatch --------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index c6da522603..25749c546b 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -467,6 +467,7 @@ Security * The `BCryptPasswordEncoder` class has been removed, use `NativePasswordEncoder` instead. * Classes implementing the `TokenInterface` must implement the two new methods `__serialize` and `__unserialize` + * Implementations of `Guard\AuthenticatorInterface::checkCredentials()` must return a boolean value now. Please explicitly return `false` to indicate invalid credentials. SecurityBundle -------------- diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php index 488246e6a8..fbc11010af 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php @@ -84,6 +84,6 @@ class ORMQueryBuilderLoader implements EntityLoaderInterface return $qb->andWhere($where) ->getQuery() ->setParameter($parameter, $values, $parameterType) - ->getResult(); + ->getResult() ?: []; } } diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index b4b3e1c5f8..f93dd0baf9 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -49,7 +49,7 @@ $getEnvVar = function ($name, $default = false) { if (PHP_VERSION_ID >= 70200) { // PHPUnit 8 requires PHP 7.2+ - $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.2'); + $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.3'); } elseif (PHP_VERSION_ID >= 70100) { // PHPUnit 7 requires PHP 7.1+ $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '7.5'); diff --git a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php index 2f1a1fb049..1af04720d1 100644 --- a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php +++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php @@ -13,6 +13,7 @@ namespace Symfony\Bridge\Twig\Mime; use League\HTMLToMarkdown\HtmlConverter; use Symfony\Component\Mime\BodyRendererInterface; +use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Message; use Twig\Environment; @@ -44,7 +45,12 @@ final class BodyRenderer implements BodyRendererInterface return; } - $vars = array_merge($this->context, $message->getContext(), [ + $messageContext = $message->getContext(); + if (isset($messageContext['email'])) { + throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', TemplatedEmail::class)); + } + + $vars = array_merge($this->context, $messageContext, [ 'email' => new WrappedTemplatedEmail($this->twig, $message), ]); diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php index 55bc3ae9a8..d8a791b3a4 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -107,6 +107,8 @@ final class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor /** * {@inheritdoc} + * + * @return int */ public function getPriority(): int { diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php index 89a15cd622..2764afc0a4 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php @@ -97,6 +97,8 @@ final class TranslationNodeVisitor extends AbstractNodeVisitor /** * {@inheritdoc} + * + * @return int */ public function getPriority(): int { diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php similarity index 80% rename from src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php rename to src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php index 3c40e6d7ee..6eeade3a73 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php @@ -14,11 +14,12 @@ namespace Symfony\Bridge\Twig\Tests\Mime; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Twig\Mime\BodyRenderer; use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Part\Multipart\AlternativePart; use Twig\Environment; use Twig\Loader\ArrayLoader; -class RendererTest extends TestCase +class BodyRendererTest extends TestCase { public function testRenderTextOnly(): void { @@ -54,7 +55,13 @@ class RendererTest extends TestCase $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); } - private function prepareEmail(?string $text, ?string $html): TemplatedEmail + public function testRenderWithContextReservedEmailEntry(): void + { + $this->expectException(InvalidArgumentException::class); + $this->prepareEmail('Text', '', ['email' => 'reserved!']); + } + + private function prepareEmail(?string $text, ?string $html, array $context = []): TemplatedEmail { $twig = new Environment(new ArrayLoader([ 'text' => $text, @@ -63,7 +70,11 @@ class RendererTest extends TestCase 'image.jpg' => 'Some image data', ])); $renderer = new BodyRenderer($twig); - $email = (new TemplatedEmail())->to('fabien@symfony.com')->from('helene@symfony.com'); + $email = (new TemplatedEmail()) + ->to('fabien@symfony.com') + ->from('helene@symfony.com') + ->context($context) + ; if (null !== $text) { $email->textTemplate('text'); } diff --git a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php index 7bd7fb7166..5fefa4c2d5 100644 --- a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php +++ b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php @@ -104,9 +104,7 @@ class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface } /** - * @param string|array $directory - * - * @return array + * {@inheritdoc} */ protected function extractFromDirectory($directory) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 91afeffa70..00d1a4a6a1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -157,4 +157,23 @@ class RedirectController return new RedirectResponse($url, $statusCode); } + + public function __invoke(Request $request): Response + { + $p = $request->attributes->get('_route_params', []); + + if (\array_key_exists('route', $p)) { + if (\array_key_exists('path', $p)) { + throw new \RuntimeException(sprintf('Ambiguous redirection settings, use the "path" or "route" parameter, not both: "%s" and "%s" found respectively in "%s" routing configuration.', $p['path'], $p['route'], $request->attributes->get('_route'))); + } + + return $this->redirectAction($request, $p['route'], $p['permanent'] ?? false, $p['ignoreAttributes'] ?? false, $p['keepRequestMethod'] ?? false, $p['keepQueryParams'] ?? false); + } + + if (\array_key_exists('path', $p)) { + return $this->urlRedirectAction($request, $p['path'], $p['permanent'] ?? false, $p['scheme'] ?? null, $p['httpPort'] ?? null, $p['httpsPort'] ?? null, $p['keepRequestMethod'] ?? false); + } + + throw new \RuntimeException(sprintf('The parameter "path" or "route" is required to configure the redirect action in "%s" routing configuration.', $request->attributes->get('_route'))); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 9d5f407293..a1edd440f5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1838,9 +1838,7 @@ class FrameworkExtension extends Extension } /** - * Returns the base path for the XSD files. - * - * @return string The XSD base path + * {@inheritdoc} */ public function getXsdValidationBasePath() { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/Fixture/TestAppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/Fixture/TestAppKernel.php index 678d573586..26d03ef9b9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/Fixture/TestAppKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/Fixture/TestAppKernel.php @@ -36,6 +36,13 @@ class TestAppKernel extends Kernel $loader->load(__DIR__.\DIRECTORY_SEPARATOR.'config.yml'); } + public function setAnnotatedClassCache(array $annotatedClasses) + { + $annotatedClasses = array_diff($annotatedClasses, ['Symfony\Bundle\WebProfilerBundle\Controller\ExceptionController', 'Symfony\Bundle\TwigBundle\Controller\ExceptionController']); + + parent::setAnnotatedClassCache($annotatedClasses); + } + protected function build(ContainerBuilder $container) { $container->register('logger', NullLogger::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 1c76d0366c..c8942614d1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -42,6 +42,22 @@ class RedirectControllerTest extends TestCase } catch (HttpException $e) { $this->assertSame(404, $e->getStatusCode()); } + + $request = new Request([], [], ['_route_params' => ['route' => '', 'permanent' => true]]); + try { + $controller($request); + $this->fail('Expected Symfony\Component\HttpKernel\Exception\HttpException to be thrown'); + } catch (HttpException $e) { + $this->assertSame(410, $e->getStatusCode()); + } + + $request = new Request([], [], ['_route_params' => ['route' => '', 'permanent' => false]]); + try { + $controller($request); + $this->fail('Expected Symfony\Component\HttpKernel\Exception\HttpException to be thrown'); + } catch (HttpException $e) { + $this->assertSame(404, $e->getStatusCode()); + } } /** @@ -71,7 +87,7 @@ class RedirectControllerTest extends TestCase $router = $this->getMockBuilder(UrlGeneratorInterface::class)->getMock(); $router - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('generate') ->with($this->equalTo($route), $this->equalTo($expectedAttributes)) ->willReturn($url); @@ -79,7 +95,10 @@ class RedirectControllerTest extends TestCase $controller = new RedirectController($router); $returnResponse = $controller->redirectAction($request, $route, $permanent, $ignoreAttributes, $keepRequestMethod, $keepQueryParams); + $this->assertRedirectUrl($returnResponse, $url); + $this->assertEquals($expectedCode, $returnResponse->getStatusCode()); + $returnResponse = $controller($request); $this->assertRedirectUrl($returnResponse, $url); $this->assertEquals($expectedCode, $returnResponse->getStatusCode()); } @@ -116,14 +135,35 @@ class RedirectControllerTest extends TestCase } catch (HttpException $e) { $this->assertSame(404, $e->getStatusCode()); } + + $request = new Request([], [], ['_route_params' => ['path' => '', 'permanent' => true]]); + try { + $controller($request); + $this->fail('Expected Symfony\Component\HttpKernel\Exception\HttpException to be thrown'); + } catch (HttpException $e) { + $this->assertSame(410, $e->getStatusCode()); + } + + $request = new Request([], [], ['_route_params' => ['path' => '', 'permanent' => false]]); + try { + $controller($request); + $this->fail('Expected Symfony\Component\HttpKernel\Exception\HttpException to be thrown'); + } catch (HttpException $e) { + $this->assertSame(404, $e->getStatusCode()); + } } public function testFullURL() { $request = new Request(); $controller = new RedirectController(); - $returnResponse = $controller->urlRedirectAction($request, 'http://foo.bar/'); + $returnResponse = $controller->urlRedirectAction($request, 'http://foo.bar/'); + $this->assertRedirectUrl($returnResponse, 'http://foo.bar/'); + $this->assertEquals(302, $returnResponse->getStatusCode()); + + $request = new Request([], [], ['_route_params' => ['path' => 'http://foo.bar/']]); + $returnResponse = $controller($request); $this->assertRedirectUrl($returnResponse, 'http://foo.bar/'); $this->assertEquals(302, $returnResponse->getStatusCode()); } @@ -132,8 +172,13 @@ class RedirectControllerTest extends TestCase { $request = new Request(); $controller = new RedirectController(); - $returnResponse = $controller->urlRedirectAction($request, 'http://foo.bar/', false, null, null, null, true); + $returnResponse = $controller->urlRedirectAction($request, 'http://foo.bar/', false, null, null, null, true); + $this->assertRedirectUrl($returnResponse, 'http://foo.bar/'); + $this->assertEquals(307, $returnResponse->getStatusCode()); + + $request = new Request([], [], ['_route_params' => ['path' => 'http://foo.bar/', 'keepRequestMethod' => true]]); + $returnResponse = $controller($request); $this->assertRedirectUrl($returnResponse, 'http://foo.bar/'); $this->assertEquals(307, $returnResponse->getStatusCode()); } @@ -151,12 +196,18 @@ class RedirectControllerTest extends TestCase $controller = $this->createRedirectController(null, $httpsPort); $returnValue = $controller->urlRedirectAction($request, $path, false, 'https'); $this->assertRedirectUrl($returnValue, $expectedUrl); + $request->attributes = new ParameterBag(['_route_params' => ['path' => $path, 'scheme' => 'https']]); + $returnValue = $controller($request); + $this->assertRedirectUrl($returnValue, $expectedUrl); $expectedUrl = "http://$host:$httpPort$baseUrl$path"; $request = $this->createRequestObject('https', $host, $httpPort, $baseUrl); $controller = $this->createRedirectController($httpPort); $returnValue = $controller->urlRedirectAction($request, $path, false, 'http'); $this->assertRedirectUrl($returnValue, $expectedUrl); + $request->attributes = new ParameterBag(['_route_params' => ['path' => $path, 'scheme' => 'http']]); + $returnValue = $controller($request); + $this->assertRedirectUrl($returnValue, $expectedUrl); } public function urlRedirectProvider() @@ -205,6 +256,10 @@ class RedirectControllerTest extends TestCase $returnValue = $controller->urlRedirectAction($request, $path, false, $scheme, $httpPort, $httpsPort); $this->assertRedirectUrl($returnValue, $expectedUrl); + + $request->attributes = new ParameterBag(['_route_params' => ['path' => $path, 'scheme' => $scheme, 'httpPort' => $httpPort, 'httpsPort' => $httpsPort]]); + $returnValue = $controller($request); + $this->assertRedirectUrl($returnValue, $expectedUrl); } public function pathQueryParamsProvider() @@ -234,6 +289,10 @@ class RedirectControllerTest extends TestCase $returnValue = $controller->urlRedirectAction($request, $path, false, $scheme, $port, null); $this->assertRedirectUrl($returnValue, $expectedUrl); + + $request->attributes = new ParameterBag(['_route_params' => ['path' => $path, 'scheme' => $scheme, 'httpPort' => $port]]); + $returnValue = $controller($request); + $this->assertRedirectUrl($returnValue, $expectedUrl); } public function testRedirectWithQuery() @@ -247,10 +306,13 @@ class RedirectControllerTest extends TestCase $request->query = new ParameterBag(['base' => 'zaza']); $request->attributes = new ParameterBag(['_route_params' => ['base2' => 'zaza']]); $urlGenerator = $this->getMockBuilder(UrlGeneratorInterface::class)->getMock(); - $urlGenerator->expects($this->once())->method('generate')->willReturn('/test?base=zaza&base2=zaza')->with('/test', ['base' => 'zaza', 'base2' => 'zaza'], UrlGeneratorInterface::ABSOLUTE_URL); + $urlGenerator->expects($this->exactly(2))->method('generate')->willReturn('/test?base=zaza&base2=zaza')->with('/test', ['base' => 'zaza', 'base2' => 'zaza'], UrlGeneratorInterface::ABSOLUTE_URL); $controller = new RedirectController($urlGenerator); $this->assertRedirectUrl($controller->redirectAction($request, '/test', false, false, false, true), '/test?base=zaza&base2=zaza'); + + $request->attributes->set('_route_params', ['base2' => 'zaza', 'route' => '/test', 'ignoreAttributes' => false, 'keepRequestMethod' => false, 'keepQueryParams' => true]); + $this->assertRedirectUrl($controller($request), '/test?base=zaza&base2=zaza'); } public function testRedirectWithQueryWithRouteParamsOveriding() @@ -264,10 +326,29 @@ class RedirectControllerTest extends TestCase $request->query = new ParameterBag(['base' => 'zaza']); $request->attributes = new ParameterBag(['_route_params' => ['base' => 'zouzou']]); $urlGenerator = $this->getMockBuilder(UrlGeneratorInterface::class)->getMock(); - $urlGenerator->expects($this->once())->method('generate')->willReturn('/test?base=zouzou')->with('/test', ['base' => 'zouzou'], UrlGeneratorInterface::ABSOLUTE_URL); + $urlGenerator->expects($this->exactly(2))->method('generate')->willReturn('/test?base=zouzou')->with('/test', ['base' => 'zouzou'], UrlGeneratorInterface::ABSOLUTE_URL); $controller = new RedirectController($urlGenerator); $this->assertRedirectUrl($controller->redirectAction($request, '/test', false, false, false, true), '/test?base=zouzou'); + + $request->attributes->set('_route_params', ['base' => 'zouzou', 'route' => '/test', 'ignoreAttributes' => false, 'keepRequestMethod' => false, 'keepQueryParams' => true]); + $this->assertRedirectUrl($controller($request), '/test?base=zouzou'); + } + + public function testMissingPathOrRouteParameter() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('The parameter "path" or "route" is required to configure the redirect action in "_redirect" routing configuration.'); + + (new RedirectController())(new Request([], [], ['_route' => '_redirect'])); + } + + public function testAmbiguousPathAndRouteParameter() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Ambiguous redirection settings, use the "path" or "route" parameter, not both: "/foo" and "bar" found respectively in "_redirect" routing configuration.'); + + (new RedirectController())(new Request([], [], ['_route' => '_redirect', '_route_params' => ['path' => '/foo', 'route' => 'bar']])); } private function createRequestObject($scheme, $host, $port, $baseUrl, $queryString = '') diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php index 7ee42cdd17..35c2e63b7e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php @@ -24,16 +24,16 @@ class ProfilerTest extends AbstractWebTestCase } $client->request('GET', '/profiler'); - $this->assertFalse($client->getProfile()); + $this->assertNull($client->getProfile()); // enable the profiler for the next request $client->enableProfiler(); - $this->assertFalse($client->getProfile()); + $this->assertNull($client->getProfile()); $client->request('GET', '/profiler'); $this->assertIsObject($client->getProfile()); $client->request('GET', '/profiler'); - $this->assertFalse($client->getProfile()); + $this->assertNull($client->getProfile()); } public function getConfigs() diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index 275f14dedc..ef43bf2af6 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -239,7 +239,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Gets the roles of the user. * - * @return array The roles + * @return array|Data */ public function getRoles() { @@ -249,7 +249,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Gets the inherited roles of the user. * - * @return array The inherited roles + * @return array|Data */ public function getInheritedRoles() { @@ -277,16 +277,25 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn return $this->data['authenticated']; } + /** + * @return bool + */ public function isImpersonated() { return $this->data['impersonated']; } + /** + * @return string|null + */ public function getImpersonatorUser() { return $this->data['impersonator_user']; } + /** + * @return string|null + */ public function getImpersonationExitPath() { return $this->data['impersonation_exit_path']; @@ -295,7 +304,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Get the class name of the security token. * - * @return string The token + * @return string|Data|null The token */ public function getTokenClass() { @@ -305,7 +314,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Get the full security token class as Data object. * - * @return Data + * @return Data|null */ public function getToken() { @@ -315,7 +324,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Get the logout URL. * - * @return string The logout URL + * @return string|null The logout URL */ public function getLogoutUrl() { @@ -325,7 +334,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Returns the FQCN of the security voters enabled in the application. * - * @return string[] + * @return string[]|Data */ public function getVoters() { @@ -345,7 +354,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Returns the log of the security decisions made by the access decision manager. * - * @return array + * @return array|Data */ public function getAccessDecisionLog() { @@ -355,13 +364,16 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn /** * Returns the configuration of the current firewall context. * - * @return array + * @return array|Data */ public function getFirewall() { return $this->data['firewall']; } + /** + * @return array|Data + */ public function getListeners() { return $this->data['listeners']; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 31c42ba2e1..3b51c66c97 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -749,9 +749,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface } /** - * Returns the base path for the XSD files. - * - * @return string The XSD base path + * {@inheritdoc} */ public function getXsdValidationBasePath() { diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index b3483b12a2..b411b75d2a 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -180,9 +180,7 @@ class TwigExtension extends Extension } /** - * Returns the base path for the XSD files. - * - * @return string The XSD base path + * {@inheritdoc} */ public function getXsdValidationBasePath() { diff --git a/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php b/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php index b8e863ff9a..5d2be19909 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php +++ b/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php @@ -58,9 +58,7 @@ class WebProfilerExtension extends Extension } /** - * Returns the base path for the XSD files. - * - * @return string The XSD base path + * {@inheritdoc} */ public function getXsdValidationBasePath() { diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php index e468c4313d..de85599fd7 100644 --- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php @@ -146,7 +146,9 @@ abstract class AbstractBrowser /** * Gets single server parameter for specified key. * - * @return string A value of the parameter + * @param mixed $default A default value when key is undefined + * + * @return mixed A value of the parameter */ public function getServerParameter(string $key, $default = '') { diff --git a/src/Symfony/Component/BrowserKit/Request.php b/src/Symfony/Component/BrowserKit/Request.php index c1e7ba4ce8..4dd0bc406f 100644 --- a/src/Symfony/Component/BrowserKit/Request.php +++ b/src/Symfony/Component/BrowserKit/Request.php @@ -107,7 +107,7 @@ class Request /** * Gets the request raw body data. * - * @return string The request raw body data + * @return string|null The request raw body data */ public function getContent() { diff --git a/src/Symfony/Component/Cache/DoctrineProvider.php b/src/Symfony/Component/Cache/DoctrineProvider.php index ee3102617e..d7e0bca927 100644 --- a/src/Symfony/Component/Cache/DoctrineProvider.php +++ b/src/Symfony/Component/Cache/DoctrineProvider.php @@ -99,7 +99,7 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese */ protected function doFlush() { - $this->pool->clear(); + return $this->pool->clear(); } /** @@ -109,5 +109,6 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese */ protected function doGetStats() { + return null; } } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php index 99f8f85c5a..724aa9451c 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php @@ -40,6 +40,10 @@ class MaxIdLengthAdapterTest extends TestCase ->setConstructorArgs([str_repeat('-', 26)]) ->getMock(); + $cache + ->method('doFetch') + ->willReturn(['2:']); + $reflectionClass = new \ReflectionClass(AbstractAdapter::class); $reflectionMethod = $reflectionClass->getMethod('getId'); @@ -56,7 +60,7 @@ class MaxIdLengthAdapterTest extends TestCase $reflectionProperty->setValue($cache, true); // Versioning enabled - $this->assertEquals('--------------------------:1:------------', $reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)])); + $this->assertEquals('--------------------------:2:------------', $reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)])); $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)]))); $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 23)]))); $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 40)]))); diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php index d7a3f0d804..88e8eaf559 100644 --- a/src/Symfony/Component/Config/Definition/ArrayNode.php +++ b/src/Symfony/Component/Config/Definition/ArrayNode.php @@ -38,17 +38,13 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface } /** - * Normalizes keys between the different configuration formats. + * {@inheritdoc} * * Namely, you mostly have foo_bar in YAML while you have foo-bar in XML. * After running this method, all keys are normalized to foo_bar. * * If you have a mixed key like foo-bar_moo, it will not be altered. * The key will also not be altered if the target key already exists. - * - * @param mixed $value - * - * @return array The value with normalized keys */ protected function preNormalize($value) { diff --git a/src/Symfony/Component/Config/Definition/BaseNode.php b/src/Symfony/Component/Config/Definition/BaseNode.php index 02f816313e..d72162012c 100644 --- a/src/Symfony/Component/Config/Definition/BaseNode.php +++ b/src/Symfony/Component/Config/Definition/BaseNode.php @@ -102,16 +102,25 @@ abstract class BaseNode implements NodeInterface $this->attributes[$key] = $value; } + /** + * @return mixed + */ public function getAttribute(string $key, $default = null) { return isset($this->attributes[$key]) ? $this->attributes[$key] : $default; } + /** + * @return bool + */ public function hasAttribute(string $key) { return isset($this->attributes[$key]); } + /** + * @return array + */ public function getAttributes() { return $this->attributes; @@ -138,7 +147,7 @@ abstract class BaseNode implements NodeInterface /** * Returns info message. * - * @return string The info text + * @return string|null The info text */ public function getInfo() { @@ -158,7 +167,7 @@ abstract class BaseNode implements NodeInterface /** * Retrieves the example configuration for this node. * - * @return string|array The example + * @return string|array|null The example */ public function getExample() { diff --git a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php index 61291e2e05..ff4570ee76 100644 --- a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php +++ b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php @@ -76,7 +76,7 @@ class PrototypedArrayNode extends ArrayNode /** * Retrieves the name of the attribute which value should be used as key. * - * @return string The name of the attribute + * @return string|null The name of the attribute */ public function getKeyAttribute() { diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php index 97b159a0c1..0ebeec4daa 100644 --- a/src/Symfony/Component/Config/Util/XmlUtils.php +++ b/src/Symfony/Component/Config/Util/XmlUtils.php @@ -152,7 +152,7 @@ class XmlUtils * @param \DOMElement $element A \DOMElement instance * @param bool $checkPrefix Check prefix in an element or an attribute name * - * @return array A PHP array + * @return mixed */ public static function convertDomElementToArray(\DOMElement $element, bool $checkPrefix = true) { diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index ce32349f5b..26878fcb6a 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -20,7 +20,6 @@ use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\ExceptionInterface; -use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Exception\NamespaceNotFoundException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\DebugFormatterHelper; @@ -468,13 +467,8 @@ class Application implements ResetInterface return null; } - if (null === $command->getDefinition()) { - throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', \get_class($command))); - } - - if (!$command->getName()) { - throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($command))); - } + // Will throw if the command is not correctly initialized. + $command->getDefinition(); $this->commands[$command->getName()] = $command; @@ -947,7 +941,7 @@ class Application implements ResetInterface /** * Gets the name of the command based on input. * - * @return string The command name + * @return string|null */ protected function getCommandName(InputInterface $input) { diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 5e9f7fb1f0..3488c37914 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -40,8 +40,8 @@ class Command private $aliases = []; private $definition; private $hidden = false; - private $help; - private $description; + private $help = ''; + private $description = ''; private $ignoreValidationErrors = false; private $applicationDefinitionMerged = false; private $applicationDefinitionMergedWithArgs = false; @@ -105,7 +105,7 @@ class Command /** * Gets the helper set. * - * @return HelperSet A HelperSet instance + * @return HelperSet|null A HelperSet instance */ public function getHelperSet() { @@ -115,7 +115,7 @@ class Command /** * Gets the application instance for this command. * - * @return Application An Application instance + * @return Application|null An Application instance */ public function getApplication() { @@ -339,6 +339,10 @@ class Command */ public function getDefinition() { + if (null === $this->definition) { + throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', \get_class($this))); + } + return $this->definition; } @@ -437,6 +441,10 @@ class Command */ public function getName() { + if (!$this->name) { + throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($this))); + } + return $this->name; } diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php index a85851bc50..8b0e4d989a 100644 --- a/src/Symfony/Component/Console/Question/Question.php +++ b/src/Symfony/Component/Console/Question/Question.php @@ -253,7 +253,7 @@ class Question * * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. * - * @return callable + * @return callable|null */ public function getNormalizer() { diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 472fefd58c..af30bdb3bd 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -362,8 +362,6 @@ class Container implements ContainerInterface, ResetInterface /** * Creates a service by requiring its factory file. - * - * @return object The service created by the file */ protected function load($file) { diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index b794f240a9..0c9b9f3ec1 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -770,7 +770,7 @@ class Definition /** * Gets the configurator to call after the service is fully initialized. * - * @return callable|null The PHP callable to call + * @return callable|array|null */ public function getConfigurator() { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/DumperInterface.php b/src/Symfony/Component/DependencyInjection/Dumper/DumperInterface.php index e8c3e4898e..8abc19250f 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/DumperInterface.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/DumperInterface.php @@ -21,7 +21,7 @@ interface DumperInterface /** * Dumps the service container. * - * @return string The representation of the service container + * @return string|array The representation of the service container */ public function dump(array $options = []); } diff --git a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php index 18de31272f..6a7a2cf023 100644 --- a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php +++ b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php @@ -37,7 +37,7 @@ interface ExtensionInterface /** * Returns the base path for the XSD files. * - * @return string The XSD base path + * @return string|false */ public function getXsdValidationBasePath(); diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 3e1d63317e..adc092bc36 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -703,7 +703,7 @@ EOF * * @param \DOMElement $element A \DOMElement instance * - * @return array A PHP array + * @return mixed */ public static function convertDomElementToArray(\DOMElement $element) { diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php index e9b70c0d0d..643424ad55 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php @@ -190,7 +190,7 @@ class ParameterBag implements ParameterBagInterface * * @param array $resolving An array of keys that are being resolved (used internally to detect circular references) * - * @return string The resolved string + * @return mixed The resolved string * * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist * @throws ParameterCircularReferenceException if a circular reference if detected diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectExtension.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectExtension.php index 4dee6add01..c9fb65ddee 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectExtension.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectExtension.php @@ -25,7 +25,7 @@ class ProjectExtension implements ExtensionInterface return $configuration; } - public function getXsdValidationBasePath(): string + public function getXsdValidationBasePath() { return false; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectWithXsdExtension.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectWithXsdExtension.php index f457abd2a3..f986cccec9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectWithXsdExtension.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/ProjectWithXsdExtension.php @@ -2,7 +2,7 @@ class ProjectWithXsdExtension extends ProjectExtension { - public function getXsdValidationBasePath(): string + public function getXsdValidationBasePath() { return __DIR__.'/schema'; } diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index b65cad7119..0fc61a7683 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -44,7 +44,7 @@ class Crawler implements \Countable, \IteratorAggregate private $document; /** - * @var \DOMElement[] + * @var \DOMNode[] */ private $nodes = []; @@ -61,7 +61,7 @@ class Crawler implements \Countable, \IteratorAggregate private $html5Parser; /** - * @param mixed $node A Node to use as the base for the crawling + * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A Node to use as the base for the crawling */ public function __construct($node = null, string $uri = null, string $baseHref = null) { @@ -107,7 +107,7 @@ class Crawler implements \Countable, \IteratorAggregate * This method uses the appropriate specialized add*() method based * on the type of the argument. * - * @param \DOMNodeList|\DOMNode|array|string|null $node A node + * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A node * * @throws \InvalidArgumentException when node is not the expected type */ @@ -1058,7 +1058,7 @@ class Crawler implements \Countable, \IteratorAggregate } /** - * @return \DOMElement|null + * @return \DOMNode|null */ public function getNode(int $position) { @@ -1074,7 +1074,7 @@ class Crawler implements \Countable, \IteratorAggregate } /** - * @return \ArrayIterator|\DOMElement[] + * @return \ArrayIterator|\DOMNode[] */ public function getIterator() { @@ -1191,7 +1191,7 @@ class Crawler implements \Countable, \IteratorAggregate /** * Creates a crawler for some subnodes. * - * @param \DOMElement|\DOMElement[]|\DOMNodeList|null $nodes + * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $nodes * * @return static */ @@ -1207,7 +1207,7 @@ class Crawler implements \Countable, \IteratorAggregate } /** - * @throws \RuntimeException If the CssSelector Component is not available + * @throws \LogicException If the CssSelector Component is not available */ private function createCssSelectorConverter(): CssSelectorConverter { diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/logs.html.php b/src/Symfony/Component/ErrorRenderer/Resources/views/logs.html.php index ee5170a2f5..5ee4e7292e 100644 --- a/src/Symfony/Component/ErrorRenderer/Resources/views/logs.html.php +++ b/src/Symfony/Component/ErrorRenderer/Resources/views/logs.html.php @@ -19,7 +19,7 @@ $severity = $log['context']['exception']['severity'] ?? false; $status = E_DEPRECATED === $severity || E_USER_DEPRECATED === $severity ? 'warning' : 'normal'; } ?> - data-filter-channel="escape($log['channel']); ?>" + data-filter-channel="escape($log['channel']); ?>"> escape($log['priorityName']); ?> diff --git a/src/Symfony/Component/Form/ButtonBuilder.php b/src/Symfony/Component/Form/ButtonBuilder.php index cd5c3b4784..5a85f8bc73 100644 --- a/src/Symfony/Component/Form/ButtonBuilder.php +++ b/src/Symfony/Component/Form/ButtonBuilder.php @@ -27,7 +27,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface /** * @var bool */ - private $disabled; + private $disabled = false; /** * @var ResolvedFormTypeInterface diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php b/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php index b05dcc018d..ba2f8dfe0e 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php @@ -26,6 +26,7 @@ class ButtonType extends BaseType implements ButtonTypeInterface */ public function getParent() { + return null; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index a2bec36949..1430261745 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -204,6 +204,7 @@ class FormType extends BaseType */ public function getParent() { + return null; } /** diff --git a/src/Symfony/Component/Form/FormError.php b/src/Symfony/Component/Form/FormError.php index 75d965a9eb..8ea67c4412 100644 --- a/src/Symfony/Component/Form/FormError.php +++ b/src/Symfony/Component/Form/FormError.php @@ -125,7 +125,7 @@ class FormError /** * Returns the form that caused this error. * - * @return FormInterface The form that caused this error + * @return FormInterface|null The form that caused this error */ public function getOrigin() { diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php index ba3d644cd9..c5229ae167 100644 --- a/src/Symfony/Component/Form/FormInterface.php +++ b/src/Symfony/Component/Form/FormInterface.php @@ -31,7 +31,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable * @throws Exception\LogicException when trying to set a parent for a form with * an empty name */ - public function setParent(self $parent = null); + public function setParent(FormInterface $parent = null); /** * Returns the parent form. diff --git a/src/Symfony/Component/Form/Test/Traits/ValidatorExtensionTrait.php b/src/Symfony/Component/Form/Test/Traits/ValidatorExtensionTrait.php index 07dd9e0d55..46bd8b7e57 100644 --- a/src/Symfony/Component/Form/Test/Traits/ValidatorExtensionTrait.php +++ b/src/Symfony/Component/Form/Test/Traits/ValidatorExtensionTrait.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Test\Traits; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\Test\TypeTestCase; +use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -37,9 +38,9 @@ trait ValidatorExtensionTrait } $this->validator = $this->getMockBuilder(ValidatorInterface::class)->getMock(); - $metadata = $this->getMockBuilder(ClassMetadata::class)->disableOriginalConstructor()->setMethods(['addPropertyConstraint'])->getMock(); + $metadata = $this->getMockBuilder(ClassMetadata::class)->setConstructorArgs([''])->setMethods(['addPropertyConstraint'])->getMock(); $this->validator->expects($this->any())->method('getMetadataFor')->will($this->returnValue($metadata)); - $this->validator->expects($this->any())->method('validate')->will($this->returnValue([])); + $this->validator->expects($this->any())->method('validate')->will($this->returnValue(new ConstraintViolationList())); return new ValidatorExtension($this->validator); } diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php index 714cc71dc8..61455a5133 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php @@ -346,7 +346,7 @@ abstract class AbstractRequestHandlerTest extends TestCase [1024, '1K', false], [null, '1K', false], [1024, '', false], - [1024, 0, false], + [1024, '0', false], ]; } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php index dcddc0298d..39d54c536a 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php @@ -13,7 +13,9 @@ namespace Symfony\Component\Form\Tests\ChoiceList\Factory; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; +use Symfony\Component\Form\ChoiceList\View\ChoiceListView; /** * @author Bernhard Schussek @@ -38,7 +40,7 @@ class CachingFactoryDecoratorTest extends TestCase public function testCreateFromChoicesEmpty() { - $list = new \stdClass(); + $list = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->once()) ->method('createListFromChoices') @@ -54,7 +56,7 @@ class CachingFactoryDecoratorTest extends TestCase // The top-most traversable is converted to an array $choices1 = new \ArrayIterator(['A' => 'a']); $choices2 = ['A' => 'a']; - $list = new \stdClass(); + $list = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->once()) ->method('createListFromChoices') @@ -69,8 +71,8 @@ class CachingFactoryDecoratorTest extends TestCase { $choices1 = ['key' => ['A' => 'a']]; $choices2 = ['A' => 'a']; - $list1 = new \stdClass(); - $list2 = new \stdClass(); + $list1 = new ArrayChoiceList([]); + $list2 = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->at(0)) ->method('createListFromChoices') @@ -92,7 +94,7 @@ class CachingFactoryDecoratorTest extends TestCase { $choices1 = [$choice1]; $choices2 = [$choice2]; - $list = new \stdClass(); + $list = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->once()) ->method('createListFromChoices') @@ -110,8 +112,8 @@ class CachingFactoryDecoratorTest extends TestCase { $choices1 = [$choice1]; $choices2 = [$choice2]; - $list1 = new \stdClass(); - $list2 = new \stdClass(); + $list1 = new ArrayChoiceList([]); + $list2 = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->at(0)) ->method('createListFromChoices') @@ -129,7 +131,7 @@ class CachingFactoryDecoratorTest extends TestCase public function testCreateFromChoicesSameValueClosure() { $choices = [1]; - $list = new \stdClass(); + $list = new ArrayChoiceList([]); $closure = function () {}; $this->decoratedFactory->expects($this->once()) @@ -144,8 +146,8 @@ class CachingFactoryDecoratorTest extends TestCase public function testCreateFromChoicesDifferentValueClosure() { $choices = [1]; - $list1 = new \stdClass(); - $list2 = new \stdClass(); + $list1 = new ArrayChoiceList([]); + $list2 = new ArrayChoiceList([]); $closure1 = function () {}; $closure2 = function () {}; @@ -165,7 +167,7 @@ class CachingFactoryDecoratorTest extends TestCase public function testCreateFromLoaderSameLoader() { $loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock(); - $list = new \stdClass(); + $list = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->once()) ->method('createListFromLoader') @@ -180,8 +182,8 @@ class CachingFactoryDecoratorTest extends TestCase { $loader1 = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock(); $loader2 = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock(); - $list1 = new \stdClass(); - $list2 = new \stdClass(); + $list1 = new ArrayChoiceList([]); + $list2 = new ArrayChoiceList([]); $this->decoratedFactory->expects($this->at(0)) ->method('createListFromLoader') @@ -199,7 +201,7 @@ class CachingFactoryDecoratorTest extends TestCase public function testCreateFromLoaderSameValueClosure() { $loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock(); - $list = new \stdClass(); + $list = new ArrayChoiceList([]); $closure = function () {}; $this->decoratedFactory->expects($this->once()) @@ -214,8 +216,8 @@ class CachingFactoryDecoratorTest extends TestCase public function testCreateFromLoaderDifferentValueClosure() { $loader = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')->getMock(); - $list1 = new \stdClass(); - $list2 = new \stdClass(); + $list1 = new ArrayChoiceList([]); + $list2 = new ArrayChoiceList([]); $closure1 = function () {}; $closure2 = function () {}; @@ -236,7 +238,7 @@ class CachingFactoryDecoratorTest extends TestCase { $preferred = ['a']; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -252,8 +254,8 @@ class CachingFactoryDecoratorTest extends TestCase $preferred1 = ['a']; $preferred2 = ['b']; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') @@ -272,7 +274,7 @@ class CachingFactoryDecoratorTest extends TestCase { $preferred = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -288,8 +290,8 @@ class CachingFactoryDecoratorTest extends TestCase $preferred1 = function () {}; $preferred2 = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') @@ -308,7 +310,7 @@ class CachingFactoryDecoratorTest extends TestCase { $labels = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -324,8 +326,8 @@ class CachingFactoryDecoratorTest extends TestCase $labels1 = function () {}; $labels2 = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') @@ -344,7 +346,7 @@ class CachingFactoryDecoratorTest extends TestCase { $index = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -360,8 +362,8 @@ class CachingFactoryDecoratorTest extends TestCase $index1 = function () {}; $index2 = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') @@ -380,7 +382,7 @@ class CachingFactoryDecoratorTest extends TestCase { $groupBy = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -396,8 +398,8 @@ class CachingFactoryDecoratorTest extends TestCase $groupBy1 = function () {}; $groupBy2 = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') @@ -416,7 +418,7 @@ class CachingFactoryDecoratorTest extends TestCase { $attr = ['class' => 'foobar']; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -432,8 +434,8 @@ class CachingFactoryDecoratorTest extends TestCase $attr1 = ['class' => 'foobar1']; $attr2 = ['class' => 'foobar2']; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') @@ -452,7 +454,7 @@ class CachingFactoryDecoratorTest extends TestCase { $attr = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view = new \stdClass(); + $view = new ChoiceListView(); $this->decoratedFactory->expects($this->once()) ->method('createView') @@ -468,8 +470,8 @@ class CachingFactoryDecoratorTest extends TestCase $attr1 = function () {}; $attr2 = function () {}; $list = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\ChoiceListInterface')->getMock(); - $view1 = new \stdClass(); - $view2 = new \stdClass(); + $view1 = new ChoiceListView(); + $view2 = new ChoiceListView(); $this->decoratedFactory->expects($this->at(0)) ->method('createView') diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php index 87b8c87fc5..df3a6bb705 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php @@ -13,7 +13,9 @@ namespace Symfony\Component\Form\Tests\ChoiceList\Factory; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; +use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Component\PropertyAccess\PropertyPath; /** @@ -45,10 +47,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createListFromChoices') ->with($choices, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($choices, $callback) { - return array_map($callback, $choices); + return new ArrayChoiceList(array_map($callback, $choices)); }); - $this->assertSame(['value'], $this->factory->createListFromChoices($choices, 'property')); + $this->assertSame(['value' => 'value'], $this->factory->createListFromChoices($choices, 'property')->getChoices()); } public function testCreateFromChoicesPropertyPathInstance() @@ -59,10 +61,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createListFromChoices') ->with($choices, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($choices, $callback) { - return array_map($callback, $choices); + return new ArrayChoiceList(array_map($callback, $choices)); }); - $this->assertSame(['value'], $this->factory->createListFromChoices($choices, new PropertyPath('property'))); + $this->assertSame(['value' => 'value'], $this->factory->createListFromChoices($choices, new PropertyPath('property'))->getChoices()); } public function testCreateFromLoaderPropertyPath() @@ -73,10 +75,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createListFromLoader') ->with($loader, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($loader, $callback) { - return $callback((object) ['property' => 'value']); + return new ArrayChoiceList((array) $callback((object) ['property' => 'value'])); }); - $this->assertSame('value', $this->factory->createListFromLoader($loader, 'property')); + $this->assertSame(['value' => 'value'], $this->factory->createListFromLoader($loader, 'property')->getChoices()); } // https://github.com/symfony/symfony/issues/5494 @@ -88,10 +90,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createListFromChoices') ->with($choices, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($choices, $callback) { - return array_map($callback, $choices); + return new ArrayChoiceList(array_map($callback, $choices)); }); - $this->assertSame([null], $this->factory->createListFromChoices($choices, 'property')); + $this->assertSame([null], $this->factory->createListFromChoices($choices, 'property')->getChoices()); } // https://github.com/symfony/symfony/issues/5494 @@ -103,10 +105,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createListFromLoader') ->with($loader, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($loader, $callback) { - return $callback(null); + return new ArrayChoiceList((array) $callback(null)); }); - $this->assertNull($this->factory->createListFromLoader($loader, 'property')); + $this->assertSame([], $this->factory->createListFromLoader($loader, 'property')->getChoices()); } public function testCreateFromLoaderPropertyPathInstance() @@ -117,10 +119,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createListFromLoader') ->with($loader, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($loader, $callback) { - return $callback((object) ['property' => 'value']); + return new ArrayChoiceList((array) $callback((object) ['property' => 'value'])); }); - $this->assertSame('value', $this->factory->createListFromLoader($loader, new PropertyPath('property'))); + $this->assertSame(['value' => 'value'], $this->factory->createListFromLoader($loader, new PropertyPath('property'))->getChoices()); } public function testCreateViewPreferredChoicesAsPropertyPath() @@ -131,13 +133,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred) { - return $preferred((object) ['property' => true]); + return new ChoiceListView((array) $preferred((object) ['property' => true])); }); - $this->assertTrue($this->factory->createView( - $list, - 'property' - )); + $this->assertSame([true], $this->factory->createView($list, 'property')->choices); } public function testCreateViewPreferredChoicesAsPropertyPathInstance() @@ -148,13 +147,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred) { - return $preferred((object) ['property' => true]); + return new ChoiceListView((array) $preferred((object) ['property' => true])); }); - $this->assertTrue($this->factory->createView( - $list, - new PropertyPath('property') - )); + $this->assertSame([true], $this->factory->createView($list, 'property')->choices); } // https://github.com/symfony/symfony/issues/5494 @@ -166,13 +162,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred) { - return $preferred((object) ['category' => null]); + return new ChoiceListView((array) $preferred((object) ['category' => null])); }); - $this->assertFalse($this->factory->createView( - $list, - 'category.preferred' - )); + $this->assertSame([false], $this->factory->createView($list, 'category.preferred')->choices); } public function testCreateViewLabelsAsPropertyPath() @@ -183,14 +176,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label) { - return $label((object) ['property' => 'label']); + return new ChoiceListView((array) $label((object) ['property' => 'label'])); }); - $this->assertSame('label', $this->factory->createView( - $list, - null, // preferred choices - 'property' - )); + $this->assertSame(['label'], $this->factory->createView($list, null, 'property')->choices); } public function testCreateViewLabelsAsPropertyPathInstance() @@ -201,14 +190,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label) { - return $label((object) ['property' => 'label']); + return new ChoiceListView((array) $label((object) ['property' => 'label'])); }); - $this->assertSame('label', $this->factory->createView( - $list, - null, // preferred choices - new PropertyPath('property') - )); + $this->assertSame(['label'], $this->factory->createView($list, null, new PropertyPath('property'))->choices); } public function testCreateViewIndicesAsPropertyPath() @@ -219,15 +204,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index) { - return $index((object) ['property' => 'index']); + return new ChoiceListView((array) $index((object) ['property' => 'index'])); }); - $this->assertSame('index', $this->factory->createView( - $list, - null, // preferred choices - null, // label - 'property' - )); + $this->assertSame(['index'], $this->factory->createView($list, null, null, 'property')->choices); } public function testCreateViewIndicesAsPropertyPathInstance() @@ -238,15 +218,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index) { - return $index((object) ['property' => 'index']); + return new ChoiceListView((array) $index((object) ['property' => 'index'])); }); - $this->assertSame('index', $this->factory->createView( - $list, - null, // preferred choices - null, // label - new PropertyPath('property') - )); + $this->assertSame(['index'], $this->factory->createView($list, null, null, new PropertyPath('property'))->choices); } public function testCreateViewGroupsAsPropertyPath() @@ -257,16 +232,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy) { - return $groupBy((object) ['property' => 'group']); + return new ChoiceListView((array) $groupBy((object) ['property' => 'group'])); }); - $this->assertSame('group', $this->factory->createView( - $list, - null, // preferred choices - null, // label - null, // index - 'property' - )); + $this->assertSame(['group'], $this->factory->createView($list, null, null, null, 'property')->choices); } public function testCreateViewGroupsAsPropertyPathInstance() @@ -277,16 +246,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy) { - return $groupBy((object) ['property' => 'group']); + return new ChoiceListView((array) $groupBy((object) ['property' => 'group'])); }); - $this->assertSame('group', $this->factory->createView( - $list, - null, // preferred choices - null, // label - null, // index - new PropertyPath('property') - )); + $this->assertSame(['group'], $this->factory->createView($list, null, null, null, new PropertyPath('property'))->choices); } // https://github.com/symfony/symfony/issues/5494 @@ -298,16 +261,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy) { - return $groupBy((object) ['group' => null]); + return new ChoiceListView((array) $groupBy((object) ['group' => null])); }); - $this->assertNull($this->factory->createView( - $list, - null, // preferred choices - null, // label - null, // index - 'group.name' - )); + $this->assertSame([], $this->factory->createView($list, null, null, null, 'group.name')->choices); } public function testCreateViewAttrAsPropertyPath() @@ -318,17 +275,10 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy, $attr) { - return $attr((object) ['property' => 'attr']); + return new ChoiceListView((array) $attr((object) ['property' => 'attr'])); }); - $this->assertSame('attr', $this->factory->createView( - $list, - null, // preferred choices - null, // label - null, // index - null, // groups - 'property' - )); + $this->assertSame(['attr'], $this->factory->createView($list, null, null, null, null, 'property')->choices); } public function testCreateViewAttrAsPropertyPathInstance() @@ -339,16 +289,9 @@ class PropertyAccessDecoratorTest extends TestCase ->method('createView') ->with($list, null, null, null, null, $this->isInstanceOf('\Closure')) ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy, $attr) { - return $attr((object) ['property' => 'attr']); + return new ChoiceListView((array) $attr((object) ['property' => 'attr'])); }); - $this->assertSame('attr', $this->factory->createView( - $list, - null, // preferred choices - null, // label - null, // index - null, // groups - new PropertyPath('property') - )); + $this->assertSame(['attr'], $this->factory->createView($list, null, null, null, null, new PropertyPath('property'))->choices); } } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php index 0e822d50ee..50403931be 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php @@ -55,10 +55,10 @@ class LazyChoiceListTest extends TestCase // The same list is returned by the loader $this->loadedList->expects($this->exactly(2)) ->method('getChoices') - ->willReturn('RESULT'); + ->willReturn(['RESULT']); - $this->assertSame('RESULT', $this->list->getChoices()); - $this->assertSame('RESULT', $this->list->getChoices()); + $this->assertSame(['RESULT'], $this->list->getChoices()); + $this->assertSame(['RESULT'], $this->list->getChoices()); } public function testGetValuesLoadsLoadedListOnFirstCall() @@ -71,10 +71,10 @@ class LazyChoiceListTest extends TestCase // The same list is returned by the loader $this->loadedList->expects($this->exactly(2)) ->method('getValues') - ->willReturn('RESULT'); + ->willReturn(['RESULT']); - $this->assertSame('RESULT', $this->list->getValues()); - $this->assertSame('RESULT', $this->list->getValues()); + $this->assertSame(['RESULT'], $this->list->getValues()); + $this->assertSame(['RESULT'], $this->list->getValues()); } public function testGetStructuredValuesLoadsLoadedListOnFirstCall() @@ -87,10 +87,10 @@ class LazyChoiceListTest extends TestCase // The same list is returned by the loader $this->loadedList->expects($this->exactly(2)) ->method('getStructuredValues') - ->willReturn('RESULT'); + ->willReturn(['RESULT']); - $this->assertSame('RESULT', $this->list->getStructuredValues()); - $this->assertSame('RESULT', $this->list->getStructuredValues()); + $this->assertSame(['RESULT'], $this->list->getStructuredValues()); + $this->assertSame(['RESULT'], $this->list->getStructuredValues()); } public function testGetOriginalKeysLoadsLoadedListOnFirstCall() @@ -103,10 +103,10 @@ class LazyChoiceListTest extends TestCase // The same list is returned by the loader $this->loadedList->expects($this->exactly(2)) ->method('getOriginalKeys') - ->willReturn('RESULT'); + ->willReturn(['RESULT']); - $this->assertSame('RESULT', $this->list->getOriginalKeys()); - $this->assertSame('RESULT', $this->list->getOriginalKeys()); + $this->assertSame(['RESULT'], $this->list->getOriginalKeys()); + $this->assertSame(['RESULT'], $this->list->getOriginalKeys()); } public function testGetChoicesForValuesForwardsCallIfListNotLoaded() @@ -114,10 +114,10 @@ class LazyChoiceListTest extends TestCase $this->loader->expects($this->exactly(2)) ->method('loadChoicesForValues') ->with(['a', 'b']) - ->willReturn('RESULT'); + ->willReturn(['RESULT']); - $this->assertSame('RESULT', $this->list->getChoicesForValues(['a', 'b'])); - $this->assertSame('RESULT', $this->list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); } public function testGetChoicesForValuesUsesLoadedList() @@ -130,13 +130,13 @@ class LazyChoiceListTest extends TestCase $this->loader->expects($this->exactly(2)) ->method('loadChoicesForValues') ->with(['a', 'b']) - ->willReturn('RESULT'); + ->willReturn(['RESULT']); // load choice list $this->list->getChoices(); - $this->assertSame('RESULT', $this->list->getChoicesForValues(['a', 'b'])); - $this->assertSame('RESULT', $this->list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); } public function testGetValuesForChoicesUsesLoadedList() @@ -149,12 +149,12 @@ class LazyChoiceListTest extends TestCase $this->loader->expects($this->exactly(2)) ->method('loadValuesForChoices') ->with(['a', 'b']) - ->willReturn('RESULT'); + ->willReturn(['RESULT']); // load choice list $this->list->getChoices(); - $this->assertSame('RESULT', $this->list->getValuesForChoices(['a', 'b'])); - $this->assertSame('RESULT', $this->list->getValuesForChoices(['a', 'b'])); + $this->assertSame(['RESULT'], $this->list->getValuesForChoices(['a', 'b'])); + $this->assertSame(['RESULT'], $this->list->getValuesForChoices(['a', 'b'])); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php index e43adf1558..abde92b155 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php @@ -145,7 +145,7 @@ class FormTypeCsrfExtensionTest extends TypeTestCase $this->tokenManager->expects($this->once()) ->method('getToken') ->with('FORM_NAME') - ->willReturn('token'); + ->willReturn(new CsrfToken('TOKEN_ID', 'token')); $view = $this->factory ->createNamed('FORM_NAME', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, [ @@ -163,7 +163,7 @@ class FormTypeCsrfExtensionTest extends TypeTestCase $this->tokenManager->expects($this->once()) ->method('getToken') ->with('Symfony\Component\Form\Extension\Core\Type\FormType') - ->willReturn('token'); + ->willReturn(new CsrfToken('TOKEN_ID', 'token')); $view = $this->factory ->createNamed('', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, [ diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php index 0c544c3ebc..7d76f79a45 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php @@ -16,6 +16,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormView; @@ -57,7 +58,7 @@ class FormDataExtractorTest extends TestCase $type = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormTypeInterface')->getMock(); $type->expects($this->any()) ->method('getInnerType') - ->willReturn(new \stdClass()); + ->willReturn(new HiddenType()); $form = $this->createBuilder('name') ->setType($type) @@ -66,7 +67,7 @@ class FormDataExtractorTest extends TestCase $this->assertSame([ 'id' => 'name', 'name' => 'name', - 'type_class' => 'stdClass', + 'type_class' => HiddenType::class, 'synchronized' => true, 'passed_options' => [], 'resolved_options' => [], @@ -78,7 +79,7 @@ class FormDataExtractorTest extends TestCase $type = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormTypeInterface')->getMock(); $type->expects($this->any()) ->method('getInnerType') - ->willReturn(new \stdClass()); + ->willReturn(new HiddenType()); $options = [ 'b' => 'foo', @@ -96,7 +97,7 @@ class FormDataExtractorTest extends TestCase $this->assertSame([ 'id' => 'name', 'name' => 'name', - 'type_class' => 'stdClass', + 'type_class' => HiddenType::class, 'synchronized' => true, 'passed_options' => [ 'a' => 'bar', @@ -112,7 +113,7 @@ class FormDataExtractorTest extends TestCase $type = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormTypeInterface')->getMock(); $type->expects($this->any()) ->method('getInnerType') - ->willReturn(new \stdClass()); + ->willReturn(new HiddenType()); $options = [ 'b' => 'foo', @@ -127,7 +128,7 @@ class FormDataExtractorTest extends TestCase $this->assertSame([ 'id' => 'name', 'name' => 'name', - 'type_class' => 'stdClass', + 'type_class' => HiddenType::class, 'synchronized' => true, 'passed_options' => [], 'resolved_options' => [ @@ -143,7 +144,7 @@ class FormDataExtractorTest extends TestCase $type = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormTypeInterface')->getMock(); $type->expects($this->any()) ->method('getInnerType') - ->willReturn(new \stdClass()); + ->willReturn(new HiddenType()); $grandParent = $this->createBuilder('grandParent') ->setCompound(true) @@ -163,7 +164,7 @@ class FormDataExtractorTest extends TestCase $this->assertSame([ 'id' => 'grandParent_parent_name', 'name' => 'name', - 'type_class' => 'stdClass', + 'type_class' => HiddenType::class, 'synchronized' => true, 'passed_options' => [], 'resolved_options' => [], diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 93dc1ea23b..1ecc79dd89 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormTypeGuesserChain; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; @@ -179,11 +180,13 @@ class FormFactoryTest extends TestCase ->method('buildForm') ->with($this->builder, $resolvedOptions); + $form = $this->createMock(FormInterface::class); + $this->builder->expects($this->once()) ->method('getForm') - ->willReturn('FORM'); + ->willReturn($form); - $this->assertSame('FORM', $this->factory->create('TYPE', null, $options)); + $this->assertSame($form, $this->factory->create('TYPE', null, $options)); } public function testCreateNamed() @@ -210,11 +213,13 @@ class FormFactoryTest extends TestCase ->method('buildForm') ->with($this->builder, $resolvedOptions); + $form = $this->createMock(FormInterface::class); + $this->builder->expects($this->once()) ->method('getForm') - ->willReturn('FORM'); + ->willReturn($form); - $this->assertSame('FORM', $this->factory->createNamed('name', 'type', null, $options)); + $this->assertSame($form, $this->factory->createNamed('name', 'type', null, $options)); } public function testCreateBuilderForPropertyWithoutTypeGuesser() @@ -228,11 +233,11 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, []) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence() @@ -260,11 +265,11 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\PasswordType', null, ['attr' => ['maxlength' => 7]]) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testCreateBuilderCreatesTextFormIfNoGuess() @@ -279,11 +284,11 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType') - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testOptionsCanBeOverridden() @@ -302,7 +307,7 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['class' => 'foo', 'maxlength' => 11]]) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty( 'Application\Author', @@ -311,7 +316,7 @@ class FormFactoryTest extends TestCase ['attr' => ['maxlength' => 11]] ); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testCreateBuilderUsesMaxLengthIfFound() @@ -337,14 +342,14 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['maxlength' => 20]]) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName' ); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testCreateBuilderUsesMaxLengthAndPattern() @@ -370,7 +375,7 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['maxlength' => 20, 'pattern' => '.{5,}', 'class' => 'tinymce']]) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty( 'Application\Author', @@ -379,7 +384,7 @@ class FormFactoryTest extends TestCase ['attr' => ['class' => 'tinymce']] ); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() @@ -405,14 +410,14 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['required' => false]) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName' ); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } public function testCreateBuilderUsesPatternIfFound() @@ -438,14 +443,14 @@ class FormFactoryTest extends TestCase $factory->expects($this->once()) ->method('createNamedBuilder') ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['pattern' => '[a-zA-Z]']]) - ->willReturn('builderInstance'); + ->willReturn($this->builder); $this->builder = $factory->createBuilderForProperty( 'Application\Author', 'firstName' ); - $this->assertEquals('builderInstance', $this->builder); + $this->assertSame($this->builder, $this->builder); } private function getMockFactory(array $methods = []) diff --git a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php index 7b1a0ea419..b24c9cf9f9 100644 --- a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigInterface; use Symfony\Component\Form\FormTypeExtensionInterface; @@ -183,7 +184,7 @@ class ResolvedFormTypeTest extends TestCase public function testFailsCreateBuilderOnInvalidFormOptionsResolution() { $this->expectException('Symfony\Component\OptionsResolver\Exception\MissingOptionsException'); - $this->expectExceptionMessage('An error has occurred resolving the options of the form "stdClass": The required option "foo" is missing.'); + $this->expectExceptionMessage('An error has occurred resolving the options of the form "Symfony\Component\Form\Extension\Core\Type\HiddenType": The required option "foo" is missing.'); $optionsResolver = (new OptionsResolver()) ->setRequired('foo') ; @@ -198,7 +199,7 @@ class ResolvedFormTypeTest extends TestCase ; $this->resolvedType->expects($this->once()) ->method('getInnerType') - ->willReturn(new \stdClass()) + ->willReturn(new HiddenType()) ; $factory = $this->getMockFormFactory(); diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index 3f70232e09..ad839cefe4 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -319,12 +319,12 @@ class BinaryFileResponse extends Response if (null !== $content) { throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.'); } + + return $this; } /** * {@inheritdoc} - * - * @return false */ public function getContent() { diff --git a/src/Symfony/Component/HttpFoundation/FileBag.php b/src/Symfony/Component/HttpFoundation/FileBag.php index 3a131e8243..5edd372b62 100644 --- a/src/Symfony/Component/HttpFoundation/FileBag.php +++ b/src/Symfony/Component/HttpFoundation/FileBag.php @@ -75,8 +75,8 @@ class FileBag extends ParameterBag return $file; } - $file = $this->fixPhpFilesArray($file); if (\is_array($file)) { + $file = $this->fixPhpFilesArray($file); $keys = array_keys($file); sort($keys); @@ -109,14 +109,12 @@ class FileBag extends ParameterBag * It's safe to pass an already converted array, in which case this method * just returns the original array unmodified. * + * @param array $data + * * @return array */ protected function fixPhpFilesArray($data) { - if (!\is_array($data)) { - return $data; - } - $keys = array_keys($data); sort($keys); diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php index 6a6ebdf3c2..84812159e8 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php @@ -108,7 +108,7 @@ class HeaderBag implements \IteratorAggregate, \Countable { $headers = $this->all($key); - return $headers[0] ?? $default; + return isset($headers[0]) ? (string) $headers[0] : $default; } /** diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 317db3d3f7..911366fbd1 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -497,6 +497,10 @@ class Request try { $content = $this->getContent(); } catch (\LogicException $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + return trigger_error($e, E_USER_ERROR); } @@ -789,7 +793,7 @@ class Request * ("Client-Ip" for instance), configure it via the $trustedHeaderSet * argument of the Request::setTrustedProxies() method instead. * - * @return string The client IP address + * @return string|null The client IP address * * @see getClientIps() * @see https://wikipedia.org/wiki/X-Forwarded-For diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 96ddca8234..0a594f6c12 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -392,7 +392,7 @@ class Response /** * Gets the current response content. * - * @return string Content + * @return string|false */ public function getContent() { diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php index 0c4690f4b7..7e752ddaa7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php @@ -97,7 +97,7 @@ class NamespacedAttributeBag extends AttributeBag * @param string $name Key name * @param bool $writeContext Write context, default false * - * @return array + * @return array|null */ protected function &resolveAttributePath(string $name, bool $writeContext = false) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php index 97873692a7..8896964ee7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php @@ -99,7 +99,7 @@ class MemcachedSessionHandler extends AbstractSessionHandler } /** - * @return int + * @return bool */ public function gc($maxlifetime) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php index ccf23de7eb..c6b16d11c8 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php @@ -61,7 +61,7 @@ class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdat } /** - * @return int + * @return bool */ public function gc($maxlifetime) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php index 3d3d9e81df..aa0e595c6b 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php @@ -67,7 +67,7 @@ class NullSessionHandler extends AbstractSessionHandler } /** - * @return int + * @return bool */ public function gc($maxlifetime) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index 93cfc74aff..6da34d28c8 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -288,7 +288,7 @@ class PdoSessionHandler extends AbstractSessionHandler } /** - * @return int + * @return bool */ public function gc($maxlifetime) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/StrictSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/StrictSessionHandler.php index 21bb2fd235..4292a3b2f0 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/StrictSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/StrictSessionHandler.php @@ -94,7 +94,7 @@ class StrictSessionHandler extends AbstractSessionHandler } /** - * @return int + * @return bool */ public function gc($maxlifetime) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php index cc6a552772..ded79d64a6 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php @@ -31,7 +31,7 @@ abstract class AbstractProxy /** * Gets the session.save_handler name. * - * @return string + * @return string|null */ public function getSaveHandlerName() { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php index 8034b7a46b..de4f550bad 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -76,7 +76,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf } /** - * @return int + * @return bool */ public function gc($maxlifetime) { diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php index c21591be66..65ec2d9845 100644 --- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php +++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php @@ -127,8 +127,6 @@ class StreamedResponse extends Response /** * {@inheritdoc} - * - * @return false */ public function getContent() { diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index b90144809c..734f8e8454 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -107,7 +107,7 @@ class BinaryFileResponseTest extends ResponseTestCase $this->assertEquals(206, $response->getStatusCode()); $this->assertEquals($responseRange, $response->headers->get('Content-Range')); - $this->assertSame($length, $response->headers->get('Content-Length')); + $this->assertSame((string) $length, $response->headers->get('Content-Length')); } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc index 7a064c7f3f..a887f607e8 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc @@ -60,14 +60,14 @@ class TestSessionHandler extends AbstractSessionHandler $this->data = $data; } - public function open($path, $name) + public function open($path, $name): bool { echo __FUNCTION__, "\n"; return parent::open($path, $name); } - public function validateId($sessionId) + public function validateId($sessionId): bool { echo __FUNCTION__, "\n"; @@ -77,7 +77,7 @@ class TestSessionHandler extends AbstractSessionHandler /** * {@inheritdoc} */ - public function read($sessionId) + public function read($sessionId): string { echo __FUNCTION__, "\n"; @@ -87,7 +87,7 @@ class TestSessionHandler extends AbstractSessionHandler /** * {@inheritdoc} */ - public function updateTimestamp($sessionId, $data) + public function updateTimestamp($sessionId, $data): bool { echo __FUNCTION__, "\n"; @@ -97,7 +97,7 @@ class TestSessionHandler extends AbstractSessionHandler /** * {@inheritdoc} */ - public function write($sessionId, $data) + public function write($sessionId, $data): bool { echo __FUNCTION__, "\n"; @@ -107,42 +107,42 @@ class TestSessionHandler extends AbstractSessionHandler /** * {@inheritdoc} */ - public function destroy($sessionId) + public function destroy($sessionId): bool { echo __FUNCTION__, "\n"; return parent::destroy($sessionId); } - public function close() + public function close(): bool { echo __FUNCTION__, "\n"; return true; } - public function gc($maxLifetime) + public function gc($maxLifetime): bool { echo __FUNCTION__, "\n"; return true; } - protected function doRead($sessionId) + protected function doRead($sessionId): string { echo __FUNCTION__.': ', $this->data, "\n"; return $this->data; } - protected function doWrite($sessionId, $data) + protected function doWrite($sessionId, $data): bool { echo __FUNCTION__.': ', $data, "\n"; return true; } - protected function doDestroy($sessionId) + protected function doDestroy($sessionId): bool { echo __FUNCTION__, "\n"; diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php index 540d58a270..1cf4aed06a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php @@ -144,7 +144,8 @@ class SessionHandlerProxyTest extends TestCase { $mock = $this->getMockBuilder(['SessionHandlerInterface', 'SessionUpdateTimestampHandlerInterface'])->getMock(); $mock->expects($this->once()) - ->method('updateTimestamp'); + ->method('updateTimestamp') + ->willReturn(false); $proxy = new SessionHandlerProxy($mock); $proxy->updateTimestamp('id', 'data'); diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php index 07ebd0affa..61678f351b 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php @@ -82,7 +82,11 @@ class ControllerResolver implements ControllerResolverInterface return $controller; } - $callable = $this->createController($controller); + try { + $callable = $this->createController($controller); + } catch (\InvalidArgumentException $e) { + throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $e->getMessage())); + } if (!\is_callable($callable)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($callable))); @@ -95,17 +99,25 @@ class ControllerResolver implements ControllerResolverInterface * Returns a callable for the given controller. * * @return callable A PHP callable + * + * @throws \InvalidArgumentException When the controller cannot be created */ protected function createController(string $controller) { if (false === strpos($controller, '::')) { - return $this->instantiateController($controller); + $controller = $this->instantiateController($controller); + + if (!\is_callable($controller)) { + throw new \InvalidArgumentException($this->getControllerError($controller)); + } + + return $controller; } list($class, $method) = explode('::', $controller, 2); try { - return [$this->instantiateController($class), $method]; + $controller = [$this->instantiateController($class), $method]; } catch (\Error | \LogicException $e) { try { if ((new \ReflectionMethod($class, $method))->isStatic()) { @@ -117,6 +129,12 @@ class ControllerResolver implements ControllerResolverInterface throw $e; } + + if (!\is_callable($controller)) { + throw new \InvalidArgumentException($this->getControllerError($controller)); + } + + return $controller; } /** diff --git a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php index 4ea8ea643f..e73b848e60 100644 --- a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php +++ b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php @@ -50,7 +50,7 @@ class ArgumentMetadata * * The type is the PHP class in 5.5+ and additionally the basic type in PHP 7.0+. * - * @return string + * @return string|null */ public function getType() { diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php index 5920310728..b680d0d797 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php @@ -99,7 +99,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte /** * Gets the token. * - * @return string The token + * @return string|null The token */ public function getToken() { diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php index bda8aeddcf..09d6e4b472 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php @@ -55,7 +55,7 @@ class ExceptionDataCollector extends DataCollector /** * Gets the exception. * - * @return \Exception The exception + * @return \Exception|FlattenException */ public function getException() { diff --git a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php index e2059830a2..af7b1bc3db 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php @@ -75,11 +75,6 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte $this->currentRequest = null; } - /** - * Gets the logs. - * - * @return array An array of logs - */ public function getLogs() { return isset($this->data['logs']) ? $this->data['logs'] : []; diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php index d070e83868..cb490c2bb3 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php @@ -132,7 +132,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf /** * Gets the request time. * - * @return int The time + * @return float */ public function getStartTime() { diff --git a/src/Symfony/Component/HttpKernel/HttpCache/AbstractSurrogate.php b/src/Symfony/Component/HttpKernel/HttpCache/AbstractSurrogate.php index 93164555d6..ac2c341385 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/AbstractSurrogate.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/AbstractSurrogate.php @@ -110,7 +110,7 @@ abstract class AbstractSurrogate implements SurrogateInterface } } - return null; + return ''; } /** diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php b/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php index 9b2358c836..587c43a0eb 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php @@ -95,6 +95,6 @@ class Ssi extends AbstractSurrogate // remove SSI/1.0 from the Surrogate-Control header $this->removeFromControl($response); - return null; + return $response; } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 595cbbf06e..f73c25e883 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -194,7 +194,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl /** * Gets a HTTP kernel from the container. * - * @return HttpKernel + * @return HttpKernelInterface */ protected function getHttpKernel() { @@ -340,7 +340,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ public function getStartTime() { - return $this->debug ? $this->startTime : -INF; + return $this->debug && null !== $this->startTime ? $this->startTime : -INF; } /** diff --git a/src/Symfony/Component/HttpKernel/KernelInterface.php b/src/Symfony/Component/HttpKernel/KernelInterface.php index 16ebc97cd9..4673bb9383 100644 --- a/src/Symfony/Component/HttpKernel/KernelInterface.php +++ b/src/Symfony/Component/HttpKernel/KernelInterface.php @@ -114,7 +114,7 @@ interface KernelInterface extends HttpKernelInterface /** * Gets the request start time (not available if debug is disabled). * - * @return int The request start timestamp + * @return float The request start timestamp */ public function getStartTime(); diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profile.php b/src/Symfony/Component/HttpKernel/Profiler/Profile.php index 28fefd25fa..c18e9980a1 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/Profile.php +++ b/src/Symfony/Component/HttpKernel/Profiler/Profile.php @@ -94,7 +94,7 @@ class Profile /** * Returns the IP. * - * @return string The IP + * @return string|null The IP */ public function getIp() { @@ -107,7 +107,9 @@ class Profile } /** - * @return string The request method + * Returns the request method. + * + * @return string|null The request method */ public function getMethod() { @@ -120,7 +122,9 @@ class Profile } /** - * @return string The URL + * Returns the URL. + * + * @return string|null The URL */ public function getUrl() { @@ -155,7 +159,7 @@ class Profile } /** - * @return int + * @return int|null */ public function getStatusCode() { diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php index e773dde1b1..6a32d5af21 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php +++ b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php @@ -63,12 +63,12 @@ class Profiler implements ResetInterface /** * Loads the Profile for the given Response. * - * @return Profile|false A Profile instance + * @return Profile|null A Profile instance */ public function loadProfileFromResponse(Response $response) { if (!$token = $response->headers->get('X-Debug-Token')) { - return false; + return null; } return $this->loadProfile($token); @@ -77,7 +77,7 @@ class Profiler implements ResetInterface /** * Loads the Profile for the given token. * - * @return Profile A Profile instance + * @return Profile|null A Profile instance */ public function loadProfile(string $token) { diff --git a/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php b/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php index be03734dc4..46dcee2162 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php @@ -28,6 +28,9 @@ class BundleTest extends TestCase ); } + /** + * @group legacy + */ public function testGetContainerExtensionWithInvalidClass() { $this->expectException('LogicException'); diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php index 3010c5e02e..adfba5d422 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php @@ -27,7 +27,7 @@ class LoggerDataCollectorTest extends TestCase ->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface') ->setMethods(['countErrors', 'getLogs', 'clear']) ->getMock(); - $logger->expects($this->once())->method('countErrors')->willReturn('foo'); + $logger->expects($this->once())->method('countErrors')->willReturn(123); $logger->expects($this->exactly(2))->method('getLogs')->willReturn([]); $c = new LoggerDataCollector($logger, __DIR__.'/'); diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/TimeDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/TimeDataCollectorTest.php index e044e5e1ad..9de9eb599a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/TimeDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/TimeDataCollectorTest.php @@ -44,7 +44,7 @@ class TimeDataCollectorTest extends TestCase $this->assertEquals(0, $c->getStartTime()); $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock(); - $kernel->expects($this->once())->method('getStartTime')->willReturn(123456); + $kernel->expects($this->once())->method('getStartTime')->willReturn(123456.0); $c = new TimeDataCollector($kernel); $request = new Request(); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php index 37d471e815..5a2faf4243 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php @@ -160,7 +160,7 @@ class HttpKernelBrowserTest extends TestCase ; $file->expects($this->any()) ->method('getClientSize') - ->willReturn(INF) + ->willReturn(PHP_INT_MAX) ; $client->request('POST', '/', [], [$file]); diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index aff5e27ec7..e50af3fac0 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -21,6 +21,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; +use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest; @@ -439,8 +440,8 @@ EOF; { $this->expectException('LogicException'); $this->expectExceptionMessage('Trying to register two bundles with the same name "DuplicateName"'); - $fooBundle = $this->getBundle(null, null, 'FooBundle', 'DuplicateName'); - $barBundle = $this->getBundle(null, null, 'BarBundle', 'DuplicateName'); + $fooBundle = $this->getBundle(__DIR__.'/Fixtures/FooBundle', null, 'FooBundle', 'DuplicateName'); + $barBundle = $this->getBundle(__DIR__.'/Fixtures/BarBundle', null, 'BarBundle', 'DuplicateName'); $kernel = $this->getKernel([], [$fooBundle, $barBundle]); $kernel->boot(); diff --git a/src/Symfony/Component/HttpKernel/Tests/Logger.php b/src/Symfony/Component/HttpKernel/Tests/Logger.php index d15e79a6c0..b6875793bc 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Logger.php +++ b/src/Symfony/Component/HttpKernel/Tests/Logger.php @@ -22,7 +22,7 @@ class Logger implements LoggerInterface $this->clear(); } - public function getLogs($level = false) + public function getLogs($level = false): array { return false === $level ? $this->logs : $this->logs[$level]; } diff --git a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index fc3ab1f5e4..fee4f0a5d9 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -414,7 +414,7 @@ abstract class IntlDateFormatter * contain -1 otherwise it will contain the position at which parsing * ended. If $parse_pos > strlen($value), the parse fails immediately. * - * @return int Parsed value as a timestamp + * @return int|false Parsed value as a timestamp * * @see https://php.net/intldateformatter.parse * diff --git a/src/Symfony/Component/Ldap/Security/LdapUserProvider.php b/src/Symfony/Component/Ldap/Security/LdapUserProvider.php index 48864761c1..0ed0566b10 100644 --- a/src/Symfony/Component/Ldap/Security/LdapUserProvider.php +++ b/src/Symfony/Component/Ldap/Security/LdapUserProvider.php @@ -144,7 +144,7 @@ class LdapUserProvider implements UserProviderInterface, PasswordUpgraderInterfa /** * Loads a user from an LDAP entry. * - * @return LdapUser + * @return UserInterface */ protected function loadUser(string $username, Entry $entry) { diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index db9e7a2735..4dea2c5703 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -69,7 +69,7 @@ class Process implements \IteratorAggregate private $status = self::STATUS_READY; private $incrementalOutputOffset = 0; private $incrementalErrorOutputOffset = 0; - private $tty; + private $tty = false; private $pty; private $useFileHandles = false; @@ -891,7 +891,7 @@ class Process implements \IteratorAggregate * @param int|float $timeout The timeout in seconds * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9) * - * @return int The exit-code of the process + * @return int|null The exit-code of the process or null if it's not running */ public function stop(float $timeout = 10, int $signal = null) { diff --git a/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php b/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php index db998839d7..1ec48da2be 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php +++ b/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php @@ -193,7 +193,7 @@ class PropertyPathBuilder /** * Returns the current property path. * - * @return PropertyPathInterface The constructed property path + * @return PropertyPathInterface|null The constructed property path */ public function getPropertyPath() { diff --git a/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php b/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php index e4134584ea..e22563fb9b 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php +++ b/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php @@ -40,7 +40,7 @@ interface PropertyPathInterface extends \Traversable * * If this property path only contains one item, null is returned. * - * @return PropertyPath|null The parent path or null + * @return self|null The parent path or null */ public function getParent(); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/NullExtractor.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/NullExtractor.php index 6878db7cf3..acae86a06f 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/NullExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/NullExtractor.php @@ -31,6 +31,8 @@ class NullExtractor implements PropertyListExtractorInterface, PropertyDescripti { $this->assertIsString($class); $this->assertIsString($property); + + return null; } /** @@ -40,6 +42,8 @@ class NullExtractor implements PropertyListExtractorInterface, PropertyDescripti { $this->assertIsString($class); $this->assertIsString($property); + + return null; } /** @@ -49,6 +53,8 @@ class NullExtractor implements PropertyListExtractorInterface, PropertyDescripti { $this->assertIsString($class); $this->assertIsString($property); + + return null; } /** @@ -58,6 +64,8 @@ class NullExtractor implements PropertyListExtractorInterface, PropertyDescripti { $this->assertIsString($class); $this->assertIsString($property); + + return null; } /** @@ -67,6 +75,8 @@ class NullExtractor implements PropertyListExtractorInterface, PropertyDescripti { $this->assertIsString($class); $this->assertIsString($property); + + return null; } /** @@ -75,6 +85,8 @@ class NullExtractor implements PropertyListExtractorInterface, PropertyDescripti public function getProperties($class, array $context = []) { $this->assertIsString($class); + + return null; } /** diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index b595fe6725..ad015ce448 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -256,9 +256,9 @@ class Router implements RouterInterface, RequestMatcherInterface } /** - * Gets the UrlMatcher instance associated with this Router. + * Gets the UrlMatcher or RequestMatcher instance associated with this Router. * - * @return UrlMatcherInterface A UrlMatcherInterface instance + * @return UrlMatcherInterface|RequestMatcherInterface */ public function getMatcher() { diff --git a/src/Symfony/Component/Routing/Tests/Loader/ObjectLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/ObjectLoaderTest.php index 779c7f1622..f3ece536e9 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/ObjectLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/ObjectLoaderTest.php @@ -62,6 +62,9 @@ class ObjectLoaderTest extends TestCase ]; } + /** + * @group legacy + */ public function testExceptionOnNoObjectReturned() { $this->expectException('LogicException'); diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 9fbed4215a..d003c0ba71 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -40,6 +40,7 @@ CHANGELOG * Added `Guard\PasswordAuthenticatedInterface`, an optional interface for "guard" authenticators that deal with user passwords * Marked all dispatched event classes as `@final` + * Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`. 4.3.0 ----- diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php index acee9a19e3..50140227aa 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php @@ -23,6 +23,9 @@ use Symfony\Component\Security\Core\User\UserProviderInterface; class DaoAuthenticationProviderTest extends TestCase { + /** + * @group legacy + */ public function testRetrieveUserWhenProviderDoesNotReturnAnUserInterface() { $this->expectException('Symfony\Component\Security\Core\Exception\AuthenticationServiceException'); diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php index e59a7bc743..c02836abb0 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php @@ -61,6 +61,9 @@ class UserAuthenticationProviderTest extends TestCase $provider->authenticate($this->getSupportedToken()); } + /** + * @group legacy + */ public function testAuthenticateWhenProviderDoesNotReturnAnUserInterface() { $this->expectException('Symfony\Component\Security\Core\Exception\AuthenticationServiceException'); diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php index 5df07a2248..f9e157c697 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php @@ -233,7 +233,7 @@ class TraceableAccessDecisionManagerTest extends TestCase ->method('vote') ->willReturnCallback(function (TokenInterface $token, $subject, array $attributes) use ($sut, $voter3) { if (\in_array('attr2', $attributes) && $subject) { - $vote = $sut->decide($token, $attributes); + $vote = $sut->decide($token, $attributes) ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_DENIED; } else { $vote = VoterInterface::ACCESS_ABSTAIN; } diff --git a/src/Symfony/Component/Security/Guard/AuthenticatorInterface.php b/src/Symfony/Component/Security/Guard/AuthenticatorInterface.php index 03428bb987..7dfbeff70e 100644 --- a/src/Symfony/Component/Security/Guard/AuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Guard/AuthenticatorInterface.php @@ -83,9 +83,8 @@ interface AuthenticatorInterface extends AuthenticationEntryPointInterface /** * Returns true if the credentials are valid. * - * If any value other than true is returned, authentication will - * fail. You may also throw an AuthenticationException if you wish - * to cause authentication to fail. + * If false is returned, authentication will fail. You may also throw + * an AuthenticationException if you wish to cause authentication to fail. * * The *credentials* are the return value from getCredentials() * diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index ac295a6d08..3212973d96 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php @@ -113,7 +113,11 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface } $this->userChecker->checkPreAuth($user); - if (true !== $guardAuthenticator->checkCredentials($token->getCredentials(), $user)) { + if (true !== $checkCredentialsResult = $guardAuthenticator->checkCredentials($token->getCredentials(), $user)) { + if (false !== $checkCredentialsResult) { + @trigger_error(sprintf('%s::checkCredentials() must return a boolean value. You returned %s. This behavior is deprecated in Symfony 4.4 and will trigger a TypeError in Symfony 5.', \get_class($guardAuthenticator), \is_object($checkCredentialsResult) ? \get_class($checkCredentialsResult) : \gettype($checkCredentialsResult)), E_USER_DEPRECATED); + } + throw new BadCredentialsException(sprintf('Authentication failed because %s::checkCredentials() did not return true.', \get_class($guardAuthenticator))); } if ($this->userProvider instanceof PasswordUpgraderInterface && $guardAuthenticator instanceof PasswordAuthenticatedInterface && null !== $this->passwordEncoder && (null !== $password = $guardAuthenticator->getPassword($token->getCredentials())) && method_exists($this->passwordEncoder, 'needsRehash') && $this->passwordEncoder->needsRehash($user)) { diff --git a/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php b/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php index 6de6ec029a..f1a56fe1fc 100644 --- a/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php @@ -12,10 +12,11 @@ namespace Symfony\Component\Security\Guard\Tests\Provider; use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Guard\AuthenticatorInterface; use Symfony\Component\Security\Guard\Provider\GuardAuthenticationProvider; +use Symfony\Component\Security\Guard\Token\GuardTokenInterface; use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken; use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken; @@ -68,7 +69,7 @@ class GuardAuthenticationProviderTest extends TestCase ->with($enteredCredentials, $mockedUser) // authentication works! ->willReturn(true); - $authedToken = $this->getMockBuilder(TokenInterface::class)->getMock(); + $authedToken = $this->getMockBuilder(GuardTokenInterface::class)->getMock(); $authenticatorB->expects($this->once()) ->method('createAuthenticatedToken') ->with($mockedUser, $providerKey) @@ -87,6 +88,41 @@ class GuardAuthenticationProviderTest extends TestCase $this->assertSame($authedToken, $actualAuthedToken); } + public function testCheckCredentialsReturningFalseFailsAuthentication() + { + $this->expectException(BadCredentialsException::class); + $providerKey = 'my_uncool_firewall'; + + $authenticator = $this->createMock(AuthenticatorInterface::class); + + // make sure the authenticator is used + $this->preAuthenticationToken->expects($this->any()) + ->method('getGuardProviderKey') + // the 0 index, to match the only authenticator + ->willReturn('my_uncool_firewall_0'); + + $this->preAuthenticationToken->expects($this->atLeastOnce()) + ->method('getCredentials') + ->willReturn('non-null-value'); + + $mockedUser = $this->createMock(UserInterface::class); + $authenticator->expects($this->once()) + ->method('getUser') + ->willReturn($mockedUser); + // checkCredentials is called + $authenticator->expects($this->once()) + ->method('checkCredentials') + // authentication fails :( + ->willReturn(false); + + $provider = new GuardAuthenticationProvider([$authenticator], $this->userProvider, $providerKey, $this->userChecker); + $provider->authenticate($this->preAuthenticationToken); + } + + /** + * @group legacy + * @expectedDeprecation %s::checkCredentials() must return a boolean value. You returned NULL. This behavior is deprecated in Symfony 4.4 and will trigger a TypeError in Symfony 5. + */ public function testCheckCredentialsReturningNonTrueFailsAuthentication() { $this->expectException('Symfony\Component\Security\Core\Exception\BadCredentialsException'); diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php index ce8c27ba7d..b1e6e27186 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticationSuccessHandlerInterface.php @@ -31,7 +31,7 @@ interface AuthenticationSuccessHandlerInterface * is called by authentication listeners inheriting from * AbstractAuthenticationListener. * - * @return Response never null + * @return Response */ public function onAuthenticationSuccess(Request $request, TokenInterface $token); } diff --git a/src/Symfony/Component/Security/Http/RememberMe/RememberMeServicesInterface.php b/src/Symfony/Component/Security/Http/RememberMe/RememberMeServicesInterface.php index fe8b0faee5..ae52591da0 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/RememberMeServicesInterface.php +++ b/src/Symfony/Component/Security/Http/RememberMe/RememberMeServicesInterface.php @@ -46,7 +46,7 @@ interface RememberMeServicesInterface * make sure to throw an AuthenticationException as this will consequentially * result in a call to loginFail() and therefore an invalidation of the cookie. * - * @return TokenInterface + * @return TokenInterface|null */ public function autoLogin(Request $request); diff --git a/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php index e7588e275a..8fe7ce0c86 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Http\Tests\Authentication; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Core\Security; @@ -62,7 +63,7 @@ class DefaultAuthenticationFailureHandlerTest extends TestCase public function testRedirect() { - $response = new Response(); + $response = new RedirectResponse('/login'); $this->httpUtils->expects($this->once()) ->method('createRedirectResponse')->with($this->request, '/login') ->willReturn($response); diff --git a/src/Symfony/Component/Security/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php b/src/Symfony/Component/Security/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php index 999ff728bf..05c5930ec8 100644 --- a/src/Symfony/Component/Security/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php +++ b/src/Symfony/Component/Security/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Http\Tests\EntryPoint; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint; @@ -21,7 +22,7 @@ class FormAuthenticationEntryPointTest extends TestCase public function testStart() { $request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->disableOriginalClone()->getMock(); - $response = new Response(); + $response = new RedirectResponse('/the/login/path'); $httpKernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); $httpUtils = $this->getMockBuilder('Symfony\Component\Security\Http\HttpUtils')->getMock(); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 28e4889594..2e4ded6b03 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -72,6 +72,9 @@ class ExceptionListenerTest extends TestCase ]; } + /** + * @group legacy + */ public function testExceptionWhenEntryPointReturnsBadValue() { $event = $this->createEvent(new AuthenticationException()); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php index f6d206c483..7cb438e3a7 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php @@ -123,6 +123,9 @@ class LogoutListenerTest extends TestCase $listener($event); } + /** + * @group legacy + */ public function testSuccessHandlerReturnsNonResponse() { $this->expectException('RuntimeException'); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php index c83d7e8787..0676490fc0 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Tests\Http\Firewall; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\RequestEvent; @@ -40,6 +41,10 @@ class UsernamePasswordFormAuthenticationListenerTest extends TestCase ->method('checkRequestPath') ->willReturn(true) ; + $httpUtils + ->method('createRedirectResponse') + ->willReturn(new RedirectResponse('/hello')) + ; $failureHandler = $this->getMockBuilder('Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface')->getMock(); $failureHandler @@ -52,7 +57,7 @@ class UsernamePasswordFormAuthenticationListenerTest extends TestCase $authenticationManager ->expects($ok ? $this->once() : $this->never()) ->method('authenticate') - ->willReturn(new Response()) + ->willReturnArgument(0) ; $listener = new UsernamePasswordFormAuthenticationListener( @@ -61,7 +66,7 @@ class UsernamePasswordFormAuthenticationListenerTest extends TestCase $this->getMockBuilder('Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface')->getMock(), $httpUtils, 'TheProviderKey', - $this->getMockBuilder('Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface')->getMock(), + new DefaultAuthenticationSuccessHandler($httpUtils), $failureHandler, ['require_previous_session' => false] ); diff --git a/src/Symfony/Component/Security/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php index 926f8cc4b2..d0c6383236 100644 --- a/src/Symfony/Component/Security/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Security\Http\Tests\Logout; use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler; class DefaultLogoutSuccessHandlerTest extends TestCase @@ -20,7 +20,7 @@ class DefaultLogoutSuccessHandlerTest extends TestCase public function testLogout() { $request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock(); - $response = new Response(); + $response = new RedirectResponse('/dashboard'); $httpUtils = $this->getMockBuilder('Symfony\Component\Security\Http\HttpUtils')->getMock(); $httpUtils->expects($this->once()) diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index c476e65403..8dc2042f12 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -39,6 +39,9 @@ class AbstractRememberMeServicesTest extends TestCase $this->assertNull($service->autoLogin(new Request())); } + /** + * @group legacy + */ public function testAutoLoginThrowsExceptionWhenImplementationDoesNotReturnUserInterface() { $this->expectException('RuntimeException'); diff --git a/src/Symfony/Component/Serializer/SerializerInterface.php b/src/Symfony/Component/Serializer/SerializerInterface.php index 55866d7004..8a1bf53187 100644 --- a/src/Symfony/Component/Serializer/SerializerInterface.php +++ b/src/Symfony/Component/Serializer/SerializerInterface.php @@ -34,7 +34,7 @@ interface SerializerInterface * * @param mixed $data * - * @return object + * @return object|array */ public function deserialize($data, string $type, string $format, array $context = []); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 11ce50a7a4..edcce4a9ba 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -15,10 +15,12 @@ use Doctrine\Common\Annotations\AnnotationReader; use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping; use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; @@ -155,26 +157,28 @@ class AbstractObjectNormalizerTest extends TestCase public function testDenormalizeWithDiscriminatorMapUsesCorrectClassname() { $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $loaderMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock(); - $loaderMock->method('hasMetadataFor')->willReturnMap([ - [ - AbstractDummy::class, - true, - ], - ]); - $loaderMock->method('getMetadataFor')->willReturnMap([ - [ - AbstractDummy::class, - new ClassMetadata( - AbstractDummy::class, - new ClassDiscriminatorMapping('type', [ - 'first' => AbstractDummyFirstChild::class, - 'second' => AbstractDummySecondChild::class, - ]) - ), - ], - ]); + $loaderMock = new class() implements ClassMetadataFactoryInterface { + public function getMetadataFor($value): ClassMetadataInterface + { + if (AbstractDummy::class === $value) { + return new ClassMetadata( + AbstractDummy::class, + new ClassDiscriminatorMapping('type', [ + 'first' => AbstractDummyFirstChild::class, + 'second' => AbstractDummySecondChild::class, + ]) + ); + } + + throw new InvalidArgumentException; + } + + public function hasMetadataFor($value): bool + { + return $value === AbstractDummy::class; + } + }; $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock); $normalizer = new AbstractObjectNormalizerDummy($factory, null, new PhpDocExtractor(), $discriminatorResolver); diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index e979aeb837..7eea79337d 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -16,9 +16,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping; use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; @@ -379,26 +381,27 @@ class SerializerTest extends TestCase $example = new AbstractDummyFirstChild('foo-value', 'bar-value'); $example->setQuux(new DummyFirstChildQuux('quux')); - $loaderMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock(); - $loaderMock->method('hasMetadataFor')->willReturnMap([ - [ - AbstractDummy::class, - true, - ], - ]); + $loaderMock = new class() implements ClassMetadataFactoryInterface { + public function getMetadataFor($value): ClassMetadataInterface + { + if (AbstractDummy::class === $value) { + return new ClassMetadata( + AbstractDummy::class, + new ClassDiscriminatorMapping('type', [ + 'first' => AbstractDummyFirstChild::class, + 'second' => AbstractDummySecondChild::class, + ]) + ); + } - $loaderMock->method('getMetadataFor')->willReturnMap([ - [ - AbstractDummy::class, - new ClassMetadata( - AbstractDummy::class, - new ClassDiscriminatorMapping('type', [ - 'first' => AbstractDummyFirstChild::class, - 'second' => AbstractDummySecondChild::class, - ]) - ), - ], - ]); + throw new InvalidArgumentException(); + } + + public function hasMetadataFor($value): bool + { + return $value === AbstractDummy::class; + } + }; $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock); $serializer = new Serializer([new ObjectNormalizer(null, null, null, new PhpDocExtractor(), $discriminatorResolver)], ['json' => new JsonEncoder()]); diff --git a/src/Symfony/Component/Templating/PhpEngine.php b/src/Symfony/Component/Templating/PhpEngine.php index 1e1d9faa63..76cbe96659 100644 --- a/src/Symfony/Component/Templating/PhpEngine.php +++ b/src/Symfony/Component/Templating/PhpEngine.php @@ -285,7 +285,7 @@ class PhpEngine implements EngineInterface, \ArrayAccess * * @param mixed $value A variable to escape * - * @return string The escaped value + * @return mixed The escaped value */ public function escape($value, string $context = 'html') { diff --git a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php index a1e0b82514..c030b11014 100644 --- a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php +++ b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php @@ -60,7 +60,7 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto } /** - * @return array + * @return array|Data */ public function getMessages() { diff --git a/src/Symfony/Component/Translation/Extractor/AbstractFileExtractor.php b/src/Symfony/Component/Translation/Extractor/AbstractFileExtractor.php index f532f51c4a..ac6dae5399 100644 --- a/src/Symfony/Component/Translation/Extractor/AbstractFileExtractor.php +++ b/src/Symfony/Component/Translation/Extractor/AbstractFileExtractor.php @@ -21,13 +21,13 @@ use Symfony\Component\Translation\Exception\InvalidArgumentException; abstract class AbstractFileExtractor { /** - * @param string|array $resource Files, a file or a directory + * @param string|iterable $resource Files, a file or a directory * - * @return array + * @return iterable */ protected function extractFiles($resource) { - if (\is_array($resource) || $resource instanceof \Traversable) { + if (\is_iterable($resource)) { $files = []; foreach ($resource as $file) { if ($this->canBeExtracted($file)) { @@ -70,7 +70,7 @@ abstract class AbstractFileExtractor /** * @param string|array $resource Files, a file or a directory * - * @return array files to be extracted + * @return iterable files to be extracted */ abstract protected function extractFromDirectory($resource); } diff --git a/src/Symfony/Component/Translation/Extractor/PhpExtractor.php b/src/Symfony/Component/Translation/Extractor/PhpExtractor.php index aa2ebc637d..549754a506 100644 --- a/src/Symfony/Component/Translation/Extractor/PhpExtractor.php +++ b/src/Symfony/Component/Translation/Extractor/PhpExtractor.php @@ -82,7 +82,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface * * @param mixed $token * - * @return string + * @return string|null */ protected function normalizeToken($token) { @@ -236,9 +236,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface } /** - * @param string|array $directory - * - * @return array + * {@inheritdoc} */ protected function extractFromDirectory($directory) { diff --git a/src/Symfony/Component/Translation/Loader/YamlFileLoader.php b/src/Symfony/Component/Translation/Loader/YamlFileLoader.php index 584a055cdb..438d7d7642 100644 --- a/src/Symfony/Component/Translation/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/YamlFileLoader.php @@ -45,6 +45,10 @@ class YamlFileLoader extends FileLoader throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e); } - return $messages; + if (null !== $messages && !\is_array($messages)) { + throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); + } + + return $messages ?: []; } } diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index 76216641ef..4b87111dbe 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -280,7 +280,7 @@ interface ExecutionContextInterface /** * Returns the validation group that is currently being validated. * - * @return string The current validation group + * @return string|null The current validation group */ public function getGroup(); diff --git a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php index b697123d7b..f0808f9723 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php @@ -128,7 +128,7 @@ Root.property.path: toString EOF; $this->assertSame($expected, (string) $violation); - $this->assertSame($message, $violation->getMessage()); + $this->assertSame((string) $message, $violation->getMessage()); } public function testMessageCannotBeArray() diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php index 5060955efc..1a00038786 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -35,7 +35,7 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface protected $indentPad = ' '; protected $flags; - private $charset; + private $charset = ''; /** * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php index 862a7a992a..713cd45ca8 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php @@ -8,6 +8,8 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInt use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Role\RoleHierarchy; +use Symfony\Component\Validator\ConstraintViolation; +use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\EventListener\ExpressionLanguage; @@ -173,7 +175,7 @@ class GuardListenerTest extends TestCase $this->validator ->expects($this->once()) ->method('validate') - ->willReturn($valid ? [] : ['a violation']) + ->willReturn(new ConstraintViolationList($valid ? [] : [new ConstraintViolation('a violation', null, [], '', null, '')])) ; } } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 25e519fc56..9827500a1c 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -20,6 +20,9 @@ class WorkflowTest extends TestCase { use WorkflowBuilderTrait; + /** + * @group legacy + */ public function testGetMarkingWithInvalidStoreReturn() { $this->expectException('Symfony\Component\Workflow\Exception\LogicException');