Merge branch '4.0'
* 4.0: [HttpKernel] Make ServiceValueResolver work if controller namespace starts with a backslash in routing Add d-block to bootstrap 4 alerts [Console] Don't go past exact matches when autocompleting [DI] Improve error message for non-autowirable scalar argument Disable autoloader call on interface_exists check [Validator] Fix LazyLoadingMetadataFactory with PSR6Cache for non classname if tested values isn't an existing class [HttpKernel] Dont create mock cookie for new sessions in tests
This commit is contained in:
commit
782ffe2fd2
@ -283,7 +283,7 @@
|
|||||||
|
|
||||||
{% block form_errors -%}
|
{% block form_errors -%}
|
||||||
{%- if errors|length > 0 -%}
|
{%- if errors|length > 0 -%}
|
||||||
<span class="{% if form is not rootform %}invalid-feedback d-block{% else %}alert alert-danger{% endif %}">
|
<span class="{% if form is not rootform %}invalid-feedback{% else %}alert alert-danger{% endif %} d-block">
|
||||||
{%- for error in errors -%}
|
{%- for error in errors -%}
|
||||||
<span class="mb-0 d-block">
|
<span class="mb-0 d-block">
|
||||||
<span class="initialism form-error-icon badge badge-danger">{{ 'Error'|trans({}, 'validators') }}</span> <span class="form-error-message">{{ error.message }}</span>
|
<span class="initialism form-error-icon badge badge-danger">{{ 'Error'|trans({}, 'validators') }}</span> <span class="form-error-message">{{ error.message }}</span>
|
||||||
|
@ -261,7 +261,7 @@ class QuestionHelper extends Helper
|
|||||||
|
|
||||||
foreach ($autocomplete as $value) {
|
foreach ($autocomplete as $value) {
|
||||||
// If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
|
// If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
|
||||||
if (0 === strpos($value, $ret) && $i !== strlen($value)) {
|
if (0 === strpos($value, $ret)) {
|
||||||
$matches[$numMatches++] = $value;
|
$matches[$numMatches++] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,29 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
|||||||
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAskWithAutocompleteWithExactMatch()
|
||||||
|
{
|
||||||
|
if (!$this->hasSttyAvailable()) {
|
||||||
|
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputStream = $this->getInputStream("b\n");
|
||||||
|
|
||||||
|
$possibleChoices = array(
|
||||||
|
'a' => 'berlin',
|
||||||
|
'b' => 'copenhagen',
|
||||||
|
'c' => 'amsterdam',
|
||||||
|
);
|
||||||
|
|
||||||
|
$dialog = new QuestionHelper();
|
||||||
|
$dialog->setHelperSet(new HelperSet(array(new FormatterHelper())));
|
||||||
|
|
||||||
|
$question = new ChoiceQuestion('Please select a city', $possibleChoices);
|
||||||
|
$question->setMaxAttempts(1);
|
||||||
|
|
||||||
|
$this->assertSame('b', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||||
|
}
|
||||||
|
|
||||||
public function testAutocompleteWithTrailingBackslash()
|
public function testAutocompleteWithTrailingBackslash()
|
||||||
{
|
{
|
||||||
if (!$this->hasSttyAvailable()) {
|
if (!$this->hasSttyAvailable()) {
|
||||||
|
@ -207,7 +207,10 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
if ($parameter->isOptional()) {
|
if ($parameter->isOptional()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
throw new AutowiringFailedException($this->currentId, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
|
$type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false);
|
||||||
|
$type = $type ? sprintf('is type-hinted "%s"', $type) : 'has no type-hint';
|
||||||
|
|
||||||
|
throw new AutowiringFailedException($this->currentId, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" %s, you should configure its value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method, $type));
|
||||||
}
|
}
|
||||||
|
|
||||||
// specifically pass the default value
|
// specifically pass the default value
|
||||||
|
@ -377,6 +377,7 @@ class AutowirePassTest extends TestCase
|
|||||||
// args are: A, Foo, Dunglas
|
// args are: A, Foo, Dunglas
|
||||||
->setArguments(array(
|
->setArguments(array(
|
||||||
1 => new Reference('foo'),
|
1 => new Reference('foo'),
|
||||||
|
3 => array('bar'),
|
||||||
));
|
));
|
||||||
|
|
||||||
(new ResolveClassPass())->process($container);
|
(new ResolveClassPass())->process($container);
|
||||||
@ -388,6 +389,7 @@ class AutowirePassTest extends TestCase
|
|||||||
new TypedReference(A::class, A::class),
|
new TypedReference(A::class, A::class),
|
||||||
new Reference('foo'),
|
new Reference('foo'),
|
||||||
new TypedReference(Dunglas::class, Dunglas::class),
|
new TypedReference(Dunglas::class, Dunglas::class),
|
||||||
|
array('bar'),
|
||||||
),
|
),
|
||||||
$definition->getArguments()
|
$definition->getArguments()
|
||||||
);
|
);
|
||||||
@ -395,12 +397,30 @@ class AutowirePassTest extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
||||||
* @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" must have a type-hint or be given a value explicitly.
|
* @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$bar" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" is type-hinted "array", you should configure its value explicitly.
|
||||||
*/
|
*/
|
||||||
public function testScalarArgsCannotBeAutowired()
|
public function testScalarArgsCannotBeAutowired()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register(A::class);
|
||||||
|
$container->register(Dunglas::class);
|
||||||
|
$container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
|
||||||
|
->setArguments(array(1 => 'foo'))
|
||||||
|
->setAutowired(true);
|
||||||
|
|
||||||
|
(new ResolveClassPass())->process($container);
|
||||||
|
(new AutowirePass())->process($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
||||||
|
* @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" has no type-hint, you should configure its value explicitly.
|
||||||
|
*/
|
||||||
|
public function testNoTypeArgsCannotBeAutowired()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
$container->register(A::class);
|
$container->register(A::class);
|
||||||
$container->register(Dunglas::class);
|
$container->register(Dunglas::class);
|
||||||
$container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
|
$container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
|
||||||
|
@ -183,7 +183,7 @@ class NotGuessableArgumentForSubclass
|
|||||||
}
|
}
|
||||||
class MultipleArguments
|
class MultipleArguments
|
||||||
{
|
{
|
||||||
public function __construct(A $k, $foo, Dunglas $dunglas)
|
public function __construct(A $k, $foo, Dunglas $dunglas, array $bar)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ abstract class AbstractBootstrap4HorizontalLayoutTest extends AbstractBootstrap4
|
|||||||
[
|
[
|
||||||
./label[@for="name"]
|
./label[@for="name"]
|
||||||
[
|
[
|
||||||
./span[@class="alert alert-danger"]
|
./span[@class="alert alert-danger d-block"]
|
||||||
[./span[@class="mb-0 d-block"]
|
[./span[@class="mb-0 d-block"]
|
||||||
[./span[.="[trans]Error[/trans]"]]
|
[./span[.="[trans]Error[/trans]"]]
|
||||||
[./span[.="[trans]Error![/trans]"]]
|
[./span[.="[trans]Error![/trans]"]]
|
||||||
|
@ -32,7 +32,7 @@ abstract class AbstractBootstrap4LayoutTest extends AbstractBootstrap3LayoutTest
|
|||||||
[
|
[
|
||||||
./label[@for="name"]
|
./label[@for="name"]
|
||||||
[
|
[
|
||||||
./span[@class="alert alert-danger"]
|
./span[@class="alert alert-danger d-block"]
|
||||||
[./span[@class="mb-0 d-block"]
|
[./span[@class="mb-0 d-block"]
|
||||||
[./span[.="[trans]Error[/trans]"]]
|
[./span[.="[trans]Error[/trans]"]]
|
||||||
[./span[.="[trans]Error![/trans]"]]
|
[./span[.="[trans]Error![/trans]"]]
|
||||||
@ -178,7 +178,7 @@ abstract class AbstractBootstrap4LayoutTest extends AbstractBootstrap3LayoutTest
|
|||||||
|
|
||||||
$this->assertMatchesXpath($html,
|
$this->assertMatchesXpath($html,
|
||||||
'/span
|
'/span
|
||||||
[@class="alert alert-danger"]
|
[@class="alert alert-danger d-block"]
|
||||||
[
|
[
|
||||||
./span[@class="mb-0 d-block"]
|
./span[@class="mb-0 d-block"]
|
||||||
[./span[.="[trans]Error[/trans]"]]
|
[./span[.="[trans]Error[/trans]"]]
|
||||||
|
@ -40,9 +40,15 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
|
|||||||
|
|
||||||
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
|
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
|
||||||
$controller = $controller[0].'::'.$controller[1];
|
$controller = $controller[0].'::'.$controller[1];
|
||||||
|
} elseif (!\is_string($controller) || '' === $controller) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return \is_string($controller) && $this->container->has($controller) && $this->container->get($controller)->has($argument->getName());
|
if ('\\' === $controller[0]) {
|
||||||
|
$controller = ltrim($controller, '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->container->has($controller) && $this->container->get($controller)->has($argument->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +60,10 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
|
|||||||
$controller = $controller[0].'::'.$controller[1];
|
$controller = $controller[0].'::'.$controller[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('\\' === $controller[0]) {
|
||||||
|
$controller = ltrim($controller, '\\');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield $this->container->get($controller)->get($argument->getName());
|
yield $this->container->get($controller)->get($argument->getName());
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
|
@ -69,7 +69,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
|
|||||||
$session->save();
|
$session->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($session instanceof Session ? !$session->isEmpty() || $session->getId() !== $this->sessionId : $wasStarted) {
|
if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) {
|
||||||
$params = session_get_cookie_params();
|
$params = session_get_cookie_params();
|
||||||
$event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']));
|
$event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']));
|
||||||
$this->sessionId = $session->getId();
|
$this->sessionId = $session->getId();
|
||||||
|
@ -47,6 +47,25 @@ class ServiceValueResolverTest extends TestCase
|
|||||||
$this->assertYieldEquals(array(new DummyService()), $resolver->resolve($request, $argument));
|
$this->assertYieldEquals(array(new DummyService()), $resolver->resolve($request, $argument));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testExistingControllerWithATrailingBackSlash()
|
||||||
|
{
|
||||||
|
$resolver = new ServiceValueResolver(new ServiceLocator(array(
|
||||||
|
'App\\Controller\\Mine::method' => function () {
|
||||||
|
return new ServiceLocator(array(
|
||||||
|
'dummy' => function () {
|
||||||
|
return new DummyService();
|
||||||
|
},
|
||||||
|
));
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
|
||||||
|
$request = $this->requestWithAttributes(array('_controller' => '\\App\\Controller\\Mine::method'));
|
||||||
|
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
|
||||||
|
|
||||||
|
$this->assertTrue($resolver->supports($request, $argument));
|
||||||
|
$this->assertYieldEquals(array(new DummyService()), $resolver->resolve($request, $argument));
|
||||||
|
}
|
||||||
|
|
||||||
public function testControllerNameIsAnArray()
|
public function testControllerNameIsAnArray()
|
||||||
{
|
{
|
||||||
$resolver = new ServiceValueResolver(new ServiceLocator(array(
|
$resolver = new ServiceValueResolver(new ServiceLocator(array(
|
||||||
|
@ -13,7 +13,6 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener;
|
|||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
|
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
|
||||||
use Symfony\Component\HttpFoundation\Cookie;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||||
@ -46,6 +45,9 @@ class TestSessionListenerTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->listener = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\EventListener\AbstractTestSessionListener');
|
$this->listener = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\EventListener\AbstractTestSessionListener');
|
||||||
$this->session = $this->getSession();
|
$this->session = $this->getSession();
|
||||||
|
$this->listener->expects($this->any())
|
||||||
|
->method('getSession')
|
||||||
|
->will($this->returnValue($this->session));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testShouldSaveMasterRequestSession()
|
public function testShouldSaveMasterRequestSession()
|
||||||
@ -95,7 +97,7 @@ class TestSessionListenerTest extends TestCase
|
|||||||
$this->fixSessionId('456');
|
$this->fixSessionId('456');
|
||||||
|
|
||||||
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
|
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
|
||||||
$request = Request::create('/', 'GET', array(), array(new Cookie('MOCKSESSID', '123')));
|
$request = Request::create('/', 'GET', array(), array('MOCKSESSID' => '123'));
|
||||||
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
|
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
|
||||||
$this->listener->onKernelRequest($event);
|
$this->listener->onKernelRequest($event);
|
||||||
|
|
||||||
|
@ -88,6 +88,10 @@ class LazyLoadingMetadataFactory implements MetadataFactoryInterface
|
|||||||
return $this->loadedClasses[$class];
|
return $this->loadedClasses[$class];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!class_exists($class) && !interface_exists($class, false)) {
|
||||||
|
throw new NoSuchMetadataException(sprintf('The class or interface "%s" does not exist.', $class));
|
||||||
|
}
|
||||||
|
|
||||||
if (null !== $this->cache && false !== ($metadata = $this->cache->read($class))) {
|
if (null !== $this->cache && false !== ($metadata = $this->cache->read($class))) {
|
||||||
// Include constraints from the parent class
|
// Include constraints from the parent class
|
||||||
$this->mergeConstraints($metadata);
|
$this->mergeConstraints($metadata);
|
||||||
@ -95,10 +99,6 @@ class LazyLoadingMetadataFactory implements MetadataFactoryInterface
|
|||||||
return $this->loadedClasses[$class] = $metadata;
|
return $this->loadedClasses[$class] = $metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!class_exists($class) && !interface_exists($class)) {
|
|
||||||
throw new NoSuchMetadataException(sprintf('The class or interface "%s" does not exist.', $class));
|
|
||||||
}
|
|
||||||
|
|
||||||
$metadata = new ClassMetadata($class);
|
$metadata = new ClassMetadata($class);
|
||||||
|
|
||||||
if (null !== $this->loader) {
|
if (null !== $this->loader) {
|
||||||
|
@ -149,6 +149,21 @@ class LazyLoadingMetadataFactoryTest extends TestCase
|
|||||||
$this->assertEquals($metadata, $factory->getMetadataFor(self::PARENT_CLASS));
|
$this->assertEquals($metadata, $factory->getMetadataFor(self::PARENT_CLASS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
|
||||||
|
*/
|
||||||
|
public function testNonClassNameStringValues()
|
||||||
|
{
|
||||||
|
$testedValue = 'error@example.com';
|
||||||
|
$loader = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Loader\LoaderInterface')->getMock();
|
||||||
|
$cache = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Cache\CacheInterface')->getMock();
|
||||||
|
$factory = new LazyLoadingMetadataFactory($loader, $cache);
|
||||||
|
$cache
|
||||||
|
->expects($this->never())
|
||||||
|
->method('read');
|
||||||
|
$factory->getMetadataFor($testedValue);
|
||||||
|
}
|
||||||
|
|
||||||
public function testMetadataCacheWithRuntimeConstraint()
|
public function testMetadataCacheWithRuntimeConstraint()
|
||||||
{
|
{
|
||||||
$cache = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Cache\CacheInterface')->getMock();
|
$cache = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Cache\CacheInterface')->getMock();
|
||||||
|
Reference in New Issue
Block a user