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:
Nicolas Grekas 2016-12-08 16:18:22 +01:00
commit a28c522790
50 changed files with 507 additions and 92 deletions

View File

@ -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
-----------

View File

@ -72,8 +72,7 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase
}
/**
* @expectedException \Twig_Error
* @expectedExceptionMessageRegExp /Unclosed "block" in ".*extractor(\/|\\)syntax_error\.twig" at line 1/
* @expectedException \Twig_Error
* @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);
$extractor->extract($resources, new MessageCatalogue('en'));
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;
}
}
/**

View File

@ -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;

View File

@ -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(

View File

@ -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));
}

View File

@ -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')) {

View File

@ -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) {
}
}

View File

@ -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;

View File

@ -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 -%}
{% with { collector: profile.getcollector(name), profiler_markup_version: profiler_markup_version } %}
{{- block('menu', template) -}}
{% endwith %}
{% 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' : '' }}">

View File

@ -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;

View File

@ -13,17 +13,19 @@
<div id="sfToolbarMainContent-{{ token }}" class="sf-toolbarreset clear-fix" data-no-turbolink>
{% for name, template in templates %}
{% with {
collector: profile.getcollector(name),
profiler_url: profiler_url,
token: profile.token,
name: name,
profiler_markup_version: profiler_markup_version,
csp_script_nonce: csp_script_nonce,
csp_style_nonce: csp_style_nonce
} %}
{{ block('toolbar', template) }}
{% endwith %}
{% if block('toolbar', template) is defined %}
{% with {
collector: profile.getcollector(name),
profiler_url: profiler_url,
token: profile.token,
name: name,
profiler_markup_version: profiler_markup_version,
csp_script_nonce: csp_script_nonce,
csp_style_nonce: csp_style_nonce
} %}
{{ block('toolbar', template) }}
{% endwith %}
{% endif %}
{% endfor %}
{% if 'normal' != position %}

View File

@ -826,7 +826,13 @@ class Application
}
if (null === $this->dispatcher) {
return $command->run($input, $output);
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

View File

@ -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',
$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',
$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);

View File

@ -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

View File

@ -1,2 +1,2 @@
<info>argument_name</info> multiline
argument description
argument description

View File

@ -1,2 +1,2 @@
<info>-o, --option_name=OPTION_NAME</info> multiline
option description
option description

View File

@ -60,15 +60,19 @@ class CheckCircularReferencesPass implements CompilerPassInterface
$id = $node->getId();
if (empty($this->checkedNodes[$id])) {
$searchKey = array_search($id, $this->currentPath);
$this->currentPath[] = $id;
if (false !== $searchKey) {
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
// don't check circular dependencies for lazy services
if (!$node->getValue() || !$node->getValue()->isLazy()) {
$searchKey = array_search($id, $this->currentPath);
$this->currentPath[] = $id;
if (false !== $searchKey) {
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
}
$this->checkOutEdges($node->getOutEdges());
}
$this->checkOutEdges($node->getOutEdges());
$this->checkedNodes[$id] = true;
array_pop($this->currentPath);
}

View File

@ -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)) {

View File

@ -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;
} 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');
} 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);
}
}
switch ($arg->getAttribute('type')) {

View File

@ -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();
}
}

View File

@ -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 '';
}
}

View File

@ -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>

View File

@ -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());
}
}

View File

@ -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,
));
}

View File

@ -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(

View File

@ -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());
}
/**

View File

@ -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)) {

View File

@ -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
*/

View File

@ -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

View File

@ -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]);
}

View File

@ -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()
{

View File

@ -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
*/

View File

@ -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())
{

View File

@ -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
*/

View File

@ -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
{

View File

@ -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.
*

View File

@ -36,7 +36,7 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface
const OBJECT_TO_STRING = 2;
/**
* @var ExecutionContextInterface2Dot5
* @var ExecutionContextInterface
*/
protected $context;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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());

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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'),
);
}
}

View File

@ -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();

View File

@ -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) {

View File

@ -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));
}
/**

View File

@ -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" }