Merge branch '3.1' into 3.2
* 3.1: (28 commits) Fix merge [Validator] add class name to the cache key [Serializer] Remove AbstractObjectNormalizer::isAttributeToNormalize Throw less misleading exception when property access not found [Twig] Fix deprecations with Twig 1.29 Fixed typo [FrameworkBundle] Removed the kernel.debug parameter from the cache pool namespace seed Fix email address fix the docblock in regard to the role argument Don't use the "app" global variable in the profiler [VarDumper] fix tests when xdebug is enabled Fix merge FIXED NON EXISTING TYPE DECLARATION [Cache] Fix dumping SplDoublyLinkedList iter mode [Console] fixed PHP7 Errors when not using Dispatcher Regression test for missing controller arguments (3.1) Regression test for missing controller arguments fix a test checking for a value [Form][DX] FileType "multiple" fixes fixed CS ...
This commit is contained in:
commit
a28c522790
@ -111,6 +111,10 @@ Serializer
|
||||
deprecated and will not be supported in Symfony 4.0. You should use the
|
||||
`CacheClassMetadataFactory` class instead.
|
||||
|
||||
* The `AbstractObjectNormalizer::isAttributeToNormalize()` method has been removed
|
||||
because it was initially added by mistake, has never been used and is not tested
|
||||
nor documented.
|
||||
|
||||
Translation
|
||||
-----------
|
||||
|
||||
|
@ -73,7 +73,6 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Twig_Error
|
||||
* @expectedExceptionMessageRegExp /Unclosed "block" in ".*extractor(\/|\\)syntax_error\.twig" at line 1/
|
||||
* @dataProvider resourcesWithSyntaxErrorsProvider
|
||||
*/
|
||||
public function testExtractSyntaxError($resources)
|
||||
@ -82,7 +81,19 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase
|
||||
$twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface')));
|
||||
|
||||
$extractor = new TwigExtractor($twig);
|
||||
|
||||
try {
|
||||
$extractor->extract($resources, new MessageCatalogue('en'));
|
||||
} catch (\Twig_Error $e) {
|
||||
if (method_exists($e, 'getSourceContext')) {
|
||||
$this->assertSame(dirname(__DIR__).strtr('/Fixtures/extractor/syntax_error.twig', '/', DIRECTORY_SEPARATOR), $e->getFile());
|
||||
$this->assertSame(1, $e->getLine());
|
||||
$this->assertSame('Unclosed "block".', $e->getMessage());
|
||||
} else {
|
||||
$this->expectExceptionMessageRegExp('/Unclosed "block" in ".*extractor(\\/|\\\\)syntax_error\\.twig" at line 1/');
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,10 +61,14 @@ class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
try {
|
||||
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
|
||||
} catch (\Twig_Error $e) {
|
||||
if ($file instanceof SplFileInfo) {
|
||||
$e->setTemplateName($file->getRelativePathname());
|
||||
} elseif ($file instanceof \SplFileInfo) {
|
||||
$e->setTemplateName($file->getRealPath() ?: $file->getPathname());
|
||||
if ($file instanceof \SplFileInfo) {
|
||||
$path = $file->getRealPath() ?: $file->getPathname();
|
||||
$name = $file instanceof SplFileInfo ? $file->getRelativePathname() : $path;
|
||||
if (method_exists($e, 'setSourceContext')) {
|
||||
$e->setSourceContext(new \Twig_Source('', $name, $path));
|
||||
} else {
|
||||
$e->setTemplateName($name);
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
|
@ -34,7 +34,7 @@ class CachePoolPass implements CompilerPassInterface
|
||||
} else {
|
||||
$seed = '_'.$container->getParameter('kernel.root_dir');
|
||||
}
|
||||
$seed .= '.'.$container->getParameter('kernel.name').'.'.$container->getParameter('kernel.environment').'.'.$container->getParameter('kernel.debug');
|
||||
$seed .= '.'.$container->getParameter('kernel.name').'.'.$container->getParameter('kernel.environment');
|
||||
|
||||
$aliases = $container->getAliases();
|
||||
$attributes = array(
|
||||
|
@ -45,7 +45,7 @@ class CachePoolPassTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->cachePoolPass->process($container);
|
||||
|
||||
$this->assertSame('C42Pcl9VBJ', $cachePool->getArgument(0));
|
||||
$this->assertSame('D07rhFx97S', $cachePool->getArgument(0));
|
||||
}
|
||||
|
||||
public function testArgsAreReplaced()
|
||||
@ -69,7 +69,7 @@ class CachePoolPassTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertInstanceOf(Reference::class, $cachePool->getArgument(0));
|
||||
$this->assertSame('foobar', (string) $cachePool->getArgument(0));
|
||||
$this->assertSame('KO3xHaFEZU', $cachePool->getArgument(1));
|
||||
$this->assertSame('itantF+pIq', $cachePool->getArgument(1));
|
||||
$this->assertSame(3, $cachePool->getArgument(2));
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -74,7 +75,7 @@ class ExtensionPass implements CompilerPassInterface
|
||||
$loader->addTag('twig.loader');
|
||||
$loader->setMethodCalls($container->getDefinition('twig.loader.filesystem')->getMethodCalls());
|
||||
|
||||
$container->setDefinition('twig.loader.filesystem', $loader);
|
||||
$container->setAlias('twig.loader.filesystem', new Alias('twig.loader.native_filesystem', false));
|
||||
}
|
||||
|
||||
if ($container->has('assets.packages')) {
|
||||
|
@ -52,7 +52,13 @@ class TwigEngine extends BaseEngine implements EngineInterface
|
||||
if ($name instanceof TemplateReference) {
|
||||
try {
|
||||
// try to get the real name of the template where the error occurred
|
||||
$e->setTemplateName(sprintf('%s', $this->locator->locate($this->parser->parse($e->getTemplateName()))));
|
||||
$name = $e->getTemplateName();
|
||||
$path = (string) $this->locator->locate($this->parser->parse($name));
|
||||
if (method_exists($e, 'setSourceContext')) {
|
||||
$e->setSourceContext(new \Twig_Source('', $name, $path));
|
||||
} else {
|
||||
$e->setTemplateName($path);
|
||||
}
|
||||
} catch (\Exception $e2) {
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.sf-reset .traces li {
|
||||
ccolor: #222;
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
padding: 5px 0;
|
||||
list-style-type: decimal;
|
||||
|
@ -39,7 +39,7 @@
|
||||
{%- else -%}
|
||||
{{ redirect_route }}
|
||||
{%- endif %}
|
||||
(<a href="{{ path('_profiler', { token: redirect.token }) }}">{{ redirect.token }}</a>)
|
||||
(<a href="{{ path('_profiler', { token: redirect.token, panel: request.query.get('panel', 'request') }) }}">{{ redirect.token }}</a>)
|
||||
</dd>
|
||||
</dl>
|
||||
{%- endif %}
|
||||
@ -113,9 +113,11 @@
|
||||
<ul id="menu-profiler">
|
||||
{% for name, template in templates %}
|
||||
{% set menu -%}
|
||||
{% if block('menu', template) is defined %}
|
||||
{% with { collector: profile.getcollector(name), profiler_markup_version: profiler_markup_version } %}
|
||||
{{- block('menu', template) -}}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{%- endset %}
|
||||
{% if menu is not empty %}
|
||||
<li class="{{ name }} {{ name == panel ? 'selected' : '' }}">
|
||||
|
@ -375,11 +375,13 @@
|
||||
border-color: #777;
|
||||
border-radius: 0;
|
||||
margin: 6px 0 12px 0;
|
||||
width: 200px;
|
||||
}
|
||||
.sf-toolbar-block-dump pre.sf-dump:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.sf-toolbar-block-dump .sf-toolbar-info-piece {
|
||||
display: block;
|
||||
}
|
||||
.sf-toolbar-block-dump .sf-toolbar-info-piece .sf-toolbar-file-line {
|
||||
color: #AAA;
|
||||
margin-left: 4px;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
<div id="sfToolbarMainContent-{{ token }}" class="sf-toolbarreset clear-fix" data-no-turbolink>
|
||||
{% for name, template in templates %}
|
||||
{% if block('toolbar', template) is defined %}
|
||||
{% with {
|
||||
collector: profile.getcollector(name),
|
||||
profiler_url: profiler_url,
|
||||
@ -24,6 +25,7 @@
|
||||
} %}
|
||||
{{ block('toolbar', template) }}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if 'normal' != position %}
|
||||
|
@ -826,7 +826,13 @@ class Application
|
||||
}
|
||||
|
||||
if (null === $this->dispatcher) {
|
||||
try {
|
||||
return $command->run($input, $output);
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
} catch (\Throwable $e) {
|
||||
throw new FatalThrowableError($e);
|
||||
}
|
||||
}
|
||||
|
||||
// bind before the console.command event, so the listeners have access to input options/arguments
|
||||
|
@ -38,13 +38,13 @@ class TextDescriptor extends Descriptor
|
||||
}
|
||||
|
||||
$totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName());
|
||||
$spacingWidth = $totalWidth - strlen($argument->getName()) + 2;
|
||||
$spacingWidth = $totalWidth - strlen($argument->getName());
|
||||
|
||||
$this->writeText(sprintf(' <info>%s</info> %s%s%s',
|
||||
$argument->getName(),
|
||||
str_repeat(' ', $spacingWidth),
|
||||
// + 17 = 2 spaces + <info> + </info> + 2 spaces
|
||||
preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $argument->getDescription()),
|
||||
// + 4 = 2 spaces before <info>, 2 spaces after </info>
|
||||
preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
|
||||
$default
|
||||
), $options);
|
||||
}
|
||||
@ -75,13 +75,13 @@ class TextDescriptor extends Descriptor
|
||||
sprintf('--%s%s', $option->getName(), $value)
|
||||
);
|
||||
|
||||
$spacingWidth = $totalWidth - strlen($synopsis) + 2;
|
||||
$spacingWidth = $totalWidth - strlen($synopsis);
|
||||
|
||||
$this->writeText(sprintf(' <info>%s</info> %s%s%s%s',
|
||||
$synopsis,
|
||||
str_repeat(' ', $spacingWidth),
|
||||
// + 17 = 2 spaces + <info> + </info> + 2 spaces
|
||||
preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $option->getDescription()),
|
||||
// + 4 = 2 spaces before <info>, 2 spaces after </info>
|
||||
preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
|
||||
$default,
|
||||
$option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
|
||||
), $options);
|
||||
|
@ -944,6 +944,24 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertContains('before.foo.caught.after.', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testRunWithError()
|
||||
{
|
||||
$this->setExpectedException('Exception', 'dymerr');
|
||||
|
||||
$application = new Application();
|
||||
$application->setAutoExit(false);
|
||||
$application->setCatchExceptions(false);
|
||||
|
||||
$application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) {
|
||||
$output->write('dym.');
|
||||
|
||||
throw new \Error('dymerr');
|
||||
});
|
||||
|
||||
$tester = new ApplicationTester($application);
|
||||
$tester->run(array('command' => 'dym'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage caught
|
||||
|
@ -60,6 +60,9 @@ class CheckCircularReferencesPass implements CompilerPassInterface
|
||||
$id = $node->getId();
|
||||
|
||||
if (empty($this->checkedNodes[$id])) {
|
||||
|
||||
// don't check circular dependencies for lazy services
|
||||
if (!$node->getValue() || !$node->getValue()->isLazy()) {
|
||||
$searchKey = array_search($id, $this->currentPath);
|
||||
$this->currentPath[] = $id;
|
||||
|
||||
@ -68,6 +71,7 @@ class CheckCircularReferencesPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
}
|
||||
|
||||
$this->checkedNodes[$id] = true;
|
||||
array_pop($this->currentPath);
|
||||
|
@ -1310,6 +1310,13 @@ EOF;
|
||||
$visited[$argumentId] = true;
|
||||
|
||||
$service = $this->container->getDefinition($argumentId);
|
||||
|
||||
// if the proxy manager is enabled, disable searching for references in lazy services,
|
||||
// as these services will be instantiated lazily and don't have direct related references.
|
||||
if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
|
||||
|
||||
if ($this->hasReference($id, $arguments, $deep, $visited)) {
|
||||
|
@ -346,21 +346,22 @@ class XmlFileLoader extends FileLoader
|
||||
$arg->setAttribute('key', $arg->getAttribute('name'));
|
||||
}
|
||||
|
||||
if (!$arg->hasAttribute('key')) {
|
||||
$key = !$arguments ? 0 : max(array_keys($arguments)) + 1;
|
||||
// this is used by DefinitionDecorator to overwrite a specific
|
||||
// argument of the parent definition
|
||||
if ($arg->hasAttribute('index')) {
|
||||
$key = 'index_'.$arg->getAttribute('index');
|
||||
} elseif (!$arg->hasAttribute('key')) {
|
||||
// Append an empty argument, then fetch its key to overwrite it later
|
||||
$arguments[] = null;
|
||||
$keys = array_keys($arguments);
|
||||
$key = array_pop($keys);
|
||||
} else {
|
||||
$key = $arg->getAttribute('key');
|
||||
}
|
||||
|
||||
// parameter keys are case insensitive
|
||||
if ('parameter' == $name && $lowercase) {
|
||||
$key = strtolower($key);
|
||||
}
|
||||
|
||||
// this is used by DefinitionDecorator to overwrite a specific
|
||||
// argument of the parent definition
|
||||
if ($arg->hasAttribute('index')) {
|
||||
$key = 'index_'.$arg->getAttribute('index');
|
||||
}
|
||||
|
||||
switch ($arg->getAttribute('type')) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Dumper;
|
||||
|
||||
use DummyProxyDumper;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
|
||||
@ -21,6 +22,8 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Variable;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
require_once __DIR__.'/../Fixtures/includes/classes.php';
|
||||
|
||||
class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
@ -340,4 +343,52 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
||||
$container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls();
|
||||
$this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls');
|
||||
}
|
||||
|
||||
public function testCircularReferenceAllowanceForLazyServices()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
|
||||
$container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'));
|
||||
$container->compile();
|
||||
|
||||
$dumper = new PhpDumper($container);
|
||||
$dumper->dump();
|
||||
}
|
||||
|
||||
public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices()
|
||||
{
|
||||
/*
|
||||
* test graph:
|
||||
* [connection] -> [event_manager] --> [entity_manager](lazy)
|
||||
* |
|
||||
* --(call)- addEventListener ("@lazy_service")
|
||||
*
|
||||
* [lazy_service](lazy) -> [entity_manager](lazy)
|
||||
*
|
||||
*/
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$eventManagerDefinition = new Definition('stdClass');
|
||||
|
||||
$connectionDefinition = $container->register('connection', 'stdClass');
|
||||
$connectionDefinition->addArgument($eventManagerDefinition);
|
||||
|
||||
$container->register('entity_manager', 'stdClass')
|
||||
->setLazy(true)
|
||||
->addArgument(new Reference('connection'));
|
||||
|
||||
$lazyServiceDefinition = $container->register('lazy_service', 'stdClass');
|
||||
$lazyServiceDefinition->setLazy(true);
|
||||
$lazyServiceDefinition->addArgument(new Reference('entity_manager'));
|
||||
|
||||
$eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service')));
|
||||
|
||||
$container->compile();
|
||||
|
||||
$dumper = new PhpDumper($container);
|
||||
|
||||
$dumper->setProxyDumper(new DummyProxyDumper());
|
||||
$dumper->dump();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
|
||||
|
||||
function sc_configure($instance)
|
||||
{
|
||||
$instance->configure();
|
||||
@ -76,3 +79,21 @@ class MethodCallClass
|
||||
return $this->callPassed;
|
||||
}
|
||||
}
|
||||
|
||||
class DummyProxyDumper implements ProxyDumper
|
||||
{
|
||||
public function isProxyCandidate(Definition $definition)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getProxyFactoryCode(Definition $definition, $id)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getProxyCode(Definition $definition)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
<services>
|
||||
<service id="foo" class="Foo">
|
||||
<argument key="type">foo</argument>
|
||||
<argument>bar</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -571,4 +571,13 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertTrue($container->has('bar'));
|
||||
}
|
||||
|
||||
public function testArgumentWithKeyOutsideCollection()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
|
||||
$loader->load('with_key_outside_collection.xml');
|
||||
|
||||
$this->assertSame(array('type' => 'foo', 'bar'), $container->getDefinition('foo')->getArguments());
|
||||
}
|
||||
}
|
||||
|
@ -12,12 +12,37 @@
|
||||
namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class FileType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
if ($options['multiple']) {
|
||||
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
|
||||
$form = $event->getForm();
|
||||
$data = $event->getData();
|
||||
|
||||
// submitted data for an input file (not required) without choosing any file
|
||||
if (array(null) === $data) {
|
||||
$emptyData = $form->getConfig()->getEmptyData();
|
||||
|
||||
$data = is_callable($emptyData) ? call_user_func($emptyData, $form, $data) : $emptyData;
|
||||
$event->setData($data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -39,9 +64,7 @@ class FileType extends AbstractType
|
||||
*/
|
||||
public function finishView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view
|
||||
->vars['multipart'] = true
|
||||
;
|
||||
$view->vars['multipart'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,10 +72,18 @@ class FileType extends AbstractType
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$dataClass = function (Options $options) {
|
||||
return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File';
|
||||
};
|
||||
|
||||
$emptyData = function (Options $options) {
|
||||
return $options['multiple'] ? array() : null;
|
||||
};
|
||||
|
||||
$resolver->setDefaults(array(
|
||||
'compound' => false,
|
||||
'data_class' => 'Symfony\Component\HttpFoundation\File\File',
|
||||
'empty_data' => null,
|
||||
'data_class' => $dataClass,
|
||||
'empty_data' => $emptyData,
|
||||
'multiple' => false,
|
||||
));
|
||||
}
|
||||
|
@ -44,6 +44,33 @@ class FileTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
||||
$this->assertNull($form->getData());
|
||||
}
|
||||
|
||||
public function testSubmitEmptyMultiple()
|
||||
{
|
||||
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FileType', null, array(
|
||||
'multiple' => true,
|
||||
))->getForm();
|
||||
|
||||
// submitted data when an input file is uploaded without choosing any file
|
||||
$form->submit(array(null));
|
||||
|
||||
$this->assertSame(array(), $form->getData());
|
||||
}
|
||||
|
||||
public function testSetDataMultiple()
|
||||
{
|
||||
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FileType', null, array(
|
||||
'multiple' => true,
|
||||
))->getForm();
|
||||
|
||||
$data = array(
|
||||
$this->createUploadedFileMock('abcdef', 'first.jpg', true),
|
||||
$this->createUploadedFileMock('zyxwvu', 'second.jpg', true),
|
||||
);
|
||||
|
||||
$form->setData($data);
|
||||
$this->assertSame($data, $form->getData());
|
||||
}
|
||||
|
||||
public function testSubmitMultiple()
|
||||
{
|
||||
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FileType', null, array(
|
||||
|
@ -27,7 +27,7 @@ final class DefaultValueResolver implements ArgumentValueResolverInterface
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument)
|
||||
{
|
||||
return $argument->hasDefaultValue() || ($argument->isNullable() && !$argument->isVariadic());
|
||||
return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +36,13 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve
|
||||
*/
|
||||
private $supportsVariadic;
|
||||
|
||||
/**
|
||||
* If scalar types exists.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $supportsScalarTypes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@ -46,6 +53,7 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve
|
||||
$this->logger = $logger;
|
||||
|
||||
$this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic');
|
||||
$this->supportsScalarTypes = method_exists('ReflectionParameter', 'getType');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,7 +148,7 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve
|
||||
$arguments[] = $request;
|
||||
} elseif ($param->isDefaultValueAvailable()) {
|
||||
$arguments[] = $param->getDefaultValue();
|
||||
} elseif ($param->allowsNull()) {
|
||||
} elseif ($this->supportsScalarTypes && $param->hasType() && $param->allowsNull()) {
|
||||
$arguments[] = null;
|
||||
} else {
|
||||
if (is_array($controller)) {
|
||||
|
@ -203,6 +203,17 @@ class ArgumentResolverTest extends \PHPUnit_Framework_TestCase
|
||||
$resolver->getArguments($request, $controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testIfExceptionIsThrownWhenMissingAnArgument()
|
||||
{
|
||||
$request = Request::create('/');
|
||||
$controller = array($this, 'controllerWithFoo');
|
||||
|
||||
self::$resolver->getArguments($request, $controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7.1
|
||||
*/
|
||||
|
@ -227,6 +227,20 @@ class ControllerResolverTest extends \PHPUnit_Framework_TestCase
|
||||
$mock->getController($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @group legacy
|
||||
*/
|
||||
public function testIfExceptionIsThrownWhenMissingAnArgument()
|
||||
{
|
||||
$resolver = new ControllerResolver();
|
||||
$request = Request::create('/');
|
||||
|
||||
$controller = array($this, 'controllerMethod1');
|
||||
|
||||
$resolver->getArguments($request, $controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7.1
|
||||
* @group legacy
|
||||
|
@ -645,6 +645,8 @@ class PropertyAccessor implements PropertyAccessorInterface
|
||||
$object->$property = $value;
|
||||
} elseif (self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]) {
|
||||
$object->{$access[self::ACCESS_NAME]}($value);
|
||||
} elseif (self::ACCESS_TYPE_NOT_FOUND === $access[self::ACCESS_TYPE]) {
|
||||
throw new NoSuchPropertyException(sprintf('Could not determine access type for property "%s".', $property));
|
||||
} else {
|
||||
throw new NoSuchPropertyException($access[self::ACCESS_NAME]);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ abstract class PropertyAccessorCollectionTest extends PropertyAccessorArrayAcces
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||
* @expectedExceptionMessage Neither the property "axes" nor one of the methods "addAx()"/"removeAx()", "addAxe()"/"removeAxe()", "addAxis()"/"removeAxis()", "setAxes()", "axes()", "__set()" or "__call()" exist and have public access in class "Mock_PropertyAccessorCollectionTest_CarNoAdderAndRemover
|
||||
* @expectedExceptionMessage Could not determine access type for property "axes".
|
||||
*/
|
||||
public function testSetValueFailsIfNoAdderNorRemoverFound()
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ abstract class AbstractToken implements TokenInterface
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RoleInterface[]|string[] $roles An array of roles
|
||||
* @param (RoleInterface|string)[] $roles An array of roles
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@ class PreAuthenticatedToken extends AbstractToken
|
||||
* @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string
|
||||
* @param mixed $credentials The user credentials
|
||||
* @param string $providerKey The provider key
|
||||
* @param RoleInterface[]|string[] $roles An array of roles
|
||||
* @param (RoleInterface|string)[] $roles An array of roles
|
||||
*/
|
||||
public function __construct($user, $credentials, $providerKey, array $roles = array())
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ class UsernamePasswordToken extends AbstractToken
|
||||
* @param string|object $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method
|
||||
* @param string $credentials This usually is the password of the user
|
||||
* @param string $providerKey The provider key
|
||||
* @param RoleInterface[]|string[] $roles An array of roles
|
||||
* @param (RoleInterface|string)[] $roles An array of roles
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||
* If you're using Guard authentication, you *must* use a class that implements
|
||||
* GuardTokenInterface as your authenticated token (like this class).
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>n@gmail.com>
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*/
|
||||
class PostAuthenticationGuardToken extends AbstractToken implements GuardTokenInterface
|
||||
{
|
||||
|
@ -208,20 +208,6 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
||||
*/
|
||||
abstract protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array());
|
||||
|
||||
/**
|
||||
* Should this attribute be normalized?
|
||||
*
|
||||
* @param mixed $object
|
||||
* @param string $attributeName
|
||||
* @param array $context
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAttributeToNormalize($object, $attributeName, &$context)
|
||||
{
|
||||
return !in_array($attributeName, $this->ignoredAttributes) && !$this->isMaxDepthReached(get_class($object), $attributeName, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the submitted data and denormalizes it.
|
||||
*
|
||||
|
@ -36,7 +36,7 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface
|
||||
const OBJECT_TO_STRING = 2;
|
||||
|
||||
/**
|
||||
* @var ExecutionContextInterface2Dot5
|
||||
* @var ExecutionContextInterface
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Constraints\Fixtures;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class ChildA
|
||||
{
|
||||
/**
|
||||
* @Assert\Valid
|
||||
* @Assert\NotNull
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* @var ChildB
|
||||
* @Assert\Valid
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
public $childB;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Constraints\Fixtures;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class ChildB
|
||||
{
|
||||
/**
|
||||
* @Assert\Valid
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* @var ChildA
|
||||
* @Assert\Valid
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
public $childA;
|
||||
}
|
@ -33,6 +33,14 @@ class Entity extends EntityParent implements EntityInterfaceB
|
||||
* @Assert\Choice(choices={"A", "B"}, message="Must be one of %choices%")
|
||||
*/
|
||||
public $firstName;
|
||||
/**
|
||||
* @Assert\Valid
|
||||
*/
|
||||
public $childA;
|
||||
/**
|
||||
* @Assert\Valid
|
||||
*/
|
||||
public $childB;
|
||||
protected $lastName;
|
||||
public $reference;
|
||||
public $reference2;
|
||||
@ -97,4 +105,36 @@ class Entity extends EntityParent implements EntityInterfaceB
|
||||
public static function validateMeStatic($object, ExecutionContextInterface $context)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getChildA()
|
||||
{
|
||||
return $this->childA;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $childA
|
||||
*/
|
||||
public function setChildA($childA)
|
||||
{
|
||||
$this->childA = $childA;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getChildB()
|
||||
{
|
||||
return $this->childB;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $childB
|
||||
*/
|
||||
public function setChildB($childB)
|
||||
{
|
||||
$this->childB = $childB;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\Validator\Constraints\Collection;
|
||||
use Symfony\Component\Validator\Constraints\NotNull;
|
||||
use Symfony\Component\Validator\Constraints\Range;
|
||||
use Symfony\Component\Validator\Constraints\IsTrue;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
@ -67,6 +68,8 @@ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
'message' => 'Must be one of %choices%',
|
||||
'choices' => array('A', 'B'),
|
||||
)));
|
||||
$expected->addPropertyConstraint('childA', new Valid());
|
||||
$expected->addPropertyConstraint('childB', new Valid());
|
||||
$expected->addGetterConstraint('lastName', new NotNull());
|
||||
$expected->addGetterConstraint('valid', new IsTrue());
|
||||
$expected->addGetterConstraint('permissions', new IsTrue());
|
||||
@ -137,6 +140,8 @@ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
'message' => 'Must be one of %choices%',
|
||||
'choices' => array('A', 'B'),
|
||||
)));
|
||||
$expected->addPropertyConstraint('childA', new Valid());
|
||||
$expected->addPropertyConstraint('childB', new Valid());
|
||||
$expected->addGetterConstraint('lastName', new NotNull());
|
||||
$expected->addGetterConstraint('valid', new IsTrue());
|
||||
$expected->addGetterConstraint('permissions', new IsTrue());
|
||||
|
@ -15,6 +15,8 @@ use Symfony\Component\Translation\IdentityTranslator;
|
||||
use Symfony\Component\Validator\ConstraintValidatorFactory;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextFactory;
|
||||
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
|
||||
use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildA;
|
||||
use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildB;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\Entity;
|
||||
use Symfony\Component\Validator\Validator\RecursiveValidator;
|
||||
|
||||
@ -34,6 +36,45 @@ class RecursiveValidatorTest extends AbstractTest
|
||||
public function testEmptyGroupsArrayDoesNotTriggerDeprecation()
|
||||
{
|
||||
$entity = new Entity();
|
||||
$childA = new ChildA();
|
||||
$childB = new ChildB();
|
||||
$childA->name = false;
|
||||
$childB->name = 'fake';
|
||||
$entity->childA = array($childA);
|
||||
$entity->childB = array($childB);
|
||||
$validatorContext = $this->getMock('Symfony\Component\Validator\Validator\ContextualValidatorInterface');
|
||||
$validatorContext
|
||||
->expects($this->once())
|
||||
->method('validate')
|
||||
->with($entity, null, array())
|
||||
->willReturnSelf();
|
||||
|
||||
$validator = $this
|
||||
->getMockBuilder('Symfony\Component\Validator\Validator\RecursiveValidator')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('startContext'))
|
||||
->getMock();
|
||||
$validator
|
||||
->expects($this->once())
|
||||
->method('startContext')
|
||||
->willReturn($validatorContext);
|
||||
|
||||
$validator->validate($entity, null, array());
|
||||
}
|
||||
|
||||
public function testRelationBetweenChildAAndChildB()
|
||||
{
|
||||
$entity = new Entity();
|
||||
$childA = new ChildA();
|
||||
$childB = new ChildB();
|
||||
|
||||
$childA->childB = $childB;
|
||||
$childB->childA = $childA;
|
||||
|
||||
$childA->name = false;
|
||||
$childB->name = 'fake';
|
||||
$entity->childA = array($childA);
|
||||
$entity->childB = array($childB);
|
||||
|
||||
$validatorContext = $this->getMock('Symfony\Component\Validator\Validator\ContextualValidatorInterface');
|
||||
$validatorContext
|
||||
|
@ -224,7 +224,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
||||
$this->validateGenericNode(
|
||||
$propertyValue,
|
||||
$object,
|
||||
$cacheKey.':'.$propertyName,
|
||||
$cacheKey.':'.get_class($object).':'.$propertyName,
|
||||
$propertyMetadata,
|
||||
$propertyPath,
|
||||
$groups,
|
||||
@ -280,7 +280,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
||||
$this->validateGenericNode(
|
||||
$value,
|
||||
$object,
|
||||
$cacheKey.':'.$propertyName,
|
||||
$cacheKey.':'.get_class($object).':'.$propertyName,
|
||||
$propertyMetadata,
|
||||
$propertyPath,
|
||||
$groups,
|
||||
@ -589,7 +589,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
||||
$this->validateGenericNode(
|
||||
$propertyValue,
|
||||
$object,
|
||||
$cacheKey.':'.$propertyName,
|
||||
$cacheKey.':'.get_class($object).':'.$propertyName,
|
||||
$propertyMetadata,
|
||||
PropertyPath::append($propertyPath, $propertyName),
|
||||
$groups,
|
||||
|
@ -71,7 +71,7 @@ class SplCaster
|
||||
$c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
|
||||
|
||||
$a += array(
|
||||
$prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_KEEP) ? 'IT_MODE_KEEP' : 'IT_MODE_DELETE'), $mode),
|
||||
$prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode),
|
||||
$prefix.'dllist' => iterator_to_array($c),
|
||||
);
|
||||
$c->setIteratorMode($mode);
|
||||
|
@ -147,6 +147,10 @@ EOTXT
|
||||
*/
|
||||
public function testGenerator()
|
||||
{
|
||||
if (extension_loaded('xdebug')) {
|
||||
$this->markTestSkipped('xdebug is active');
|
||||
}
|
||||
|
||||
$g = new GeneratorDemo();
|
||||
$g = $g->baz();
|
||||
$r = new \ReflectionGenerator($g);
|
||||
|
@ -117,4 +117,30 @@ SplFileObject {
|
||||
EOTXT;
|
||||
$this->assertDumpMatchesFormat($dump, $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideCastSplDoublyLinkedList
|
||||
*/
|
||||
public function testCastSplDoublyLinkedList($modeValue, $modeDump)
|
||||
{
|
||||
$var = new \SplDoublyLinkedList();
|
||||
$var->setIteratorMode($modeValue);
|
||||
$dump = <<<EOTXT
|
||||
SplDoublyLinkedList {
|
||||
%Amode: $modeDump
|
||||
dllist: []
|
||||
}
|
||||
EOTXT;
|
||||
$this->assertDumpMatchesFormat($dump, $var);
|
||||
}
|
||||
|
||||
public function provideCastSplDoublyLinkedList()
|
||||
{
|
||||
return array(
|
||||
array(\SplDoublyLinkedList::IT_MODE_FIFO, 'IT_MODE_FIFO | IT_MODE_KEEP'),
|
||||
array(\SplDoublyLinkedList::IT_MODE_LIFO, 'IT_MODE_LIFO | IT_MODE_KEEP'),
|
||||
array(\SplDoublyLinkedList::IT_MODE_FIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_FIFO | IT_MODE_DELETE'),
|
||||
array(\SplDoublyLinkedList::IT_MODE_LIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_LIFO | IT_MODE_DELETE'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +157,10 @@ EOTXT;
|
||||
|
||||
public function testJsonCast()
|
||||
{
|
||||
if (ini_get('xdebug.overload_var_dump') == 2) {
|
||||
$this->markTestSkipped('xdebug is active');
|
||||
}
|
||||
|
||||
$data = (array) json_decode('{"1":{}}');
|
||||
|
||||
$cloner = new VarCloner();
|
||||
|
@ -88,7 +88,7 @@ class Dumper
|
||||
$isAHash = Inline::isHash($input);
|
||||
|
||||
foreach ($input as $key => $value) {
|
||||
if ($inline > 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && is_string($value) && false !== strpos($value, "\n")) {
|
||||
if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && is_string($value) && false !== strpos($value, "\n")) {
|
||||
$output .= sprintf("%s%s%s |\n", $prefix, $isAHash ? Inline::dump($key, $flags).':' : '-', '');
|
||||
|
||||
foreach (preg_split('/\n|\r\n/', $value) as $row) {
|
||||
|
@ -342,7 +342,7 @@ EOF;
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block.yml'), $this->dumper->dump($data, 3, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
|
||||
$this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,5 +10,4 @@ data:
|
||||
empty line:
|
||||
|
||||
baz
|
||||
nested_inlined_multi_line_string:
|
||||
inlined_multi_line: "foo\nbar\r\nempty line:\n\nbaz"
|
||||
nested_inlined_multi_line_string: { inlined_multi_line: "foo\nbar\r\nempty line:\n\nbaz" }
|
||||
|
Reference in New Issue
Block a user