Merge branch '3.4' into 4.1
* 3.4: [Debug] ignore underscore vs backslash namespaces in DebugClassLoader [TwigBridge][Form] Prevent multiple rendering of form collection prototypes [FrameworkBundle] fix describing routes with no controllers [DI] move RegisterServiceSubscribersPass before DecoratorServicePass Update ValidationListener.php [Yaml] ensures that the mb_internal_encoding is reset to its initial value [WebLink] Fixed documentation link [Security] getTargetPath of TargetPathTrait must return string or null [Hackday][Serializer] Deserialization ignores argument type hint from phpdoc for array in constructor argument [Security] defer log message in guard authenticator merge conflicts Fix HeaderBag::get phpdoc
This commit is contained in:
commit
547bf26eee
@ -28,7 +28,7 @@
|
|||||||
{%- endblock form_widget_compound -%}
|
{%- endblock form_widget_compound -%}
|
||||||
|
|
||||||
{%- block collection_widget -%}
|
{%- block collection_widget -%}
|
||||||
{% if prototype is defined %}
|
{% if prototype is defined and not prototype.rendered %}
|
||||||
{%- set attr = attr|merge({'data-prototype': form_row(prototype) }) -%}
|
{%- set attr = attr|merge({'data-prototype': form_row(prototype) }) -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{- block('form_widget') -}}
|
{{- block('form_widget') -}}
|
||||||
|
@ -56,7 +56,7 @@ class TextDescriptor extends Descriptor
|
|||||||
|
|
||||||
if ($showControllers) {
|
if ($showControllers) {
|
||||||
$controller = $route->getDefault('_controller');
|
$controller = $route->getDefault('_controller');
|
||||||
$row[] = $this->formatCallable($controller);
|
$row[] = $controller ? $this->formatCallable($controller) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$tableRows[] = $row;
|
$tableRows[] = $row;
|
||||||
|
@ -214,7 +214,7 @@ class DebugClassLoader
|
|||||||
$len = 0;
|
$len = 0;
|
||||||
$ns = '';
|
$ns = '';
|
||||||
} else {
|
} else {
|
||||||
$ns = \substr($class, 0, $len);
|
$ns = \str_replace('_', '\\', \substr($class, 0, $len));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect annotations on the class
|
// Detect annotations on the class
|
||||||
@ -245,13 +245,13 @@ class DebugClassLoader
|
|||||||
if (!isset(self::$checkedClasses[$use])) {
|
if (!isset(self::$checkedClasses[$use])) {
|
||||||
$this->checkClass($use);
|
$this->checkClass($use);
|
||||||
}
|
}
|
||||||
if (isset(self::$deprecated[$use]) && \strncmp($ns, $use, $len)) {
|
if (isset(self::$deprecated[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) {
|
||||||
$type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
|
$type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
|
||||||
$verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
|
$verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
|
||||||
|
|
||||||
$deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]);
|
$deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]);
|
||||||
}
|
}
|
||||||
if (isset(self::$internal[$use]) && \strncmp($ns, $use, $len)) {
|
if (isset(self::$internal[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) {
|
||||||
$deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class);
|
$deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,11 @@ class PassConfig
|
|||||||
new ValidateEnvPlaceholdersPass(),
|
new ValidateEnvPlaceholdersPass(),
|
||||||
new ResolveChildDefinitionsPass(),
|
new ResolveChildDefinitionsPass(),
|
||||||
new ServiceLocatorTagPass(),
|
new ServiceLocatorTagPass(),
|
||||||
|
new RegisterServiceSubscribersPass(),
|
||||||
new DecoratorServicePass(),
|
new DecoratorServicePass(),
|
||||||
new ResolveParameterPlaceHoldersPass(false),
|
new ResolveParameterPlaceHoldersPass(false),
|
||||||
new ResolveFactoryClassPass(),
|
new ResolveFactoryClassPass(),
|
||||||
new CheckDefinitionValidityPass(),
|
new CheckDefinitionValidityPass(),
|
||||||
new RegisterServiceSubscribersPass(),
|
|
||||||
new ResolveNamedArgumentsPass(),
|
new ResolveNamedArgumentsPass(),
|
||||||
new AutowireRequiredMethodsPass(),
|
new AutowireRequiredMethodsPass(),
|
||||||
new ResolveBindingsPass(),
|
new ResolveBindingsPass(),
|
||||||
|
@ -94,39 +94,40 @@ class ServiceLocator implements PsrContainerInterface
|
|||||||
$class = isset($class[2]['object']) ? \get_class($class[2]['object']) : null;
|
$class = isset($class[2]['object']) ? \get_class($class[2]['object']) : null;
|
||||||
$externalId = $this->externalId ?: $class;
|
$externalId = $this->externalId ?: $class;
|
||||||
|
|
||||||
$msg = sprintf('Service "%s" not found: ', $id);
|
$msg = array();
|
||||||
|
$msg[] = sprintf('Service "%s" not found:', $id);
|
||||||
|
|
||||||
if (!$this->container) {
|
if (!$this->container) {
|
||||||
$class = null;
|
$class = null;
|
||||||
} elseif ($this->container->has($id) || isset($this->container->getRemovedIds()[$id])) {
|
} elseif ($this->container->has($id) || isset($this->container->getRemovedIds()[$id])) {
|
||||||
$msg .= 'even though it exists in the app\'s container, ';
|
$msg[] = 'even though it exists in the app\'s container,';
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
$this->container->get($id);
|
$this->container->get($id);
|
||||||
$class = null;
|
$class = null;
|
||||||
} catch (ServiceNotFoundException $e) {
|
} catch (ServiceNotFoundException $e) {
|
||||||
if ($e->getAlternatives()) {
|
if ($e->getAlternatives()) {
|
||||||
$msg .= sprintf(' did you mean %s? Anyway, ', $this->formatAlternatives($e->getAlternatives(), 'or'));
|
$msg[] = sprintf('did you mean %s? Anyway,', $this->formatAlternatives($e->getAlternatives(), 'or'));
|
||||||
} else {
|
} else {
|
||||||
$class = null;
|
$class = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($externalId) {
|
if ($externalId) {
|
||||||
$msg .= sprintf('the container inside "%s" is a smaller service locator that %s', $externalId, $this->formatAlternatives());
|
$msg[] = sprintf('the container inside "%s" is a smaller service locator that %s', $externalId, $this->formatAlternatives());
|
||||||
} else {
|
} else {
|
||||||
$msg .= sprintf('the current service locator %s', $this->formatAlternatives());
|
$msg[] = sprintf('the current service locator %s', $this->formatAlternatives());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$class) {
|
if (!$class) {
|
||||||
// no-op
|
// no-op
|
||||||
} elseif (is_subclass_of($class, ServiceSubscriberInterface::class)) {
|
} elseif (is_subclass_of($class, ServiceSubscriberInterface::class)) {
|
||||||
$msg .= sprintf(' Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".', preg_replace('/([^\\\\]++\\\\)++/', '', $class));
|
$msg[] = sprintf('Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".', preg_replace('/([^\\\\]++\\\\)++/', '', $class));
|
||||||
} else {
|
} else {
|
||||||
$msg .= 'Try using dependency injection instead.';
|
$msg[] = 'Try using dependency injection instead.';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $msg;
|
return implode(' ', $msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formatAlternatives(array $alternatives = null, $separator = 'and')
|
private function formatAlternatives(array $alternatives = null, $separator = 'and')
|
||||||
|
@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Alias;
|
|||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class tests the integration of the different compiler passes.
|
* This class tests the integration of the different compiler passes.
|
||||||
@ -120,6 +121,21 @@ class IntegrationTest extends TestCase
|
|||||||
$this->assertFalse($container->hasDefinition('c'), 'Service C was not inlined.');
|
$this->assertFalse($container->hasDefinition('c'), 'Service C was not inlined.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCanDecorateServiceSubscriber()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->register(ServiceSubscriberStub::class)
|
||||||
|
->addTag('container.service_subscriber')
|
||||||
|
->setPublic(true);
|
||||||
|
|
||||||
|
$container->register(DecoratedServiceSubscriber::class)
|
||||||
|
->setDecoratedService(ServiceSubscriberStub::class);
|
||||||
|
|
||||||
|
$container->compile();
|
||||||
|
|
||||||
|
$this->assertInstanceOf(DecoratedServiceSubscriber::class, $container->get(ServiceSubscriberStub::class));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getYamlCompileTests
|
* @dataProvider getYamlCompileTests
|
||||||
*/
|
*/
|
||||||
@ -220,6 +236,18 @@ class IntegrationTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ServiceSubscriberStub implements ServiceSubscriberInterface
|
||||||
|
{
|
||||||
|
public static function getSubscribedServices()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DecoratedServiceSubscriber
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
class IntegrationTestStub extends IntegrationTestStubParent
|
class IntegrationTestStub extends IntegrationTestStubParent
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,20 @@ class ServiceLocatorTest extends TestCase
|
|||||||
$subscriber->getFoo();
|
$subscriber->getFoo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
|
||||||
|
* @expectedExceptionMessage Service "foo" not found: even though it exists in the app's container, the container inside "foo" is a smaller service locator that is empty... Try using dependency injection instead.
|
||||||
|
*/
|
||||||
|
public function testGetThrowsServiceNotFoundException()
|
||||||
|
{
|
||||||
|
$container = new Container();
|
||||||
|
$container->set('foo', new \stdClass());
|
||||||
|
|
||||||
|
$locator = new ServiceLocator(array());
|
||||||
|
$locator = $locator->withContext('foo', $container);
|
||||||
|
$locator->get('foo');
|
||||||
|
}
|
||||||
|
|
||||||
public function testInvoke()
|
public function testInvoke()
|
||||||
{
|
{
|
||||||
$locator = new ServiceLocator(array(
|
$locator = new ServiceLocator(array(
|
||||||
|
@ -51,7 +51,7 @@ class ValidationListener implements EventSubscriberInterface
|
|||||||
$form = $event->getForm();
|
$form = $event->getForm();
|
||||||
|
|
||||||
if ($form->isRoot()) {
|
if ($form->isRoot()) {
|
||||||
// Validate the form in group "Default"
|
// Form groups are validated internally (FormValidator). Here we don't set groups as they are retrieved into the validator.
|
||||||
foreach ($this->validator->validate($form) as $violation) {
|
foreach ($this->validator->validate($form) as $violation) {
|
||||||
// Allow the "invalid" constraint to be put onto
|
// Allow the "invalid" constraint to be put onto
|
||||||
// non-synchronized forms
|
// non-synchronized forms
|
||||||
|
@ -102,7 +102,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
|
|||||||
* Returns a header value by name.
|
* Returns a header value by name.
|
||||||
*
|
*
|
||||||
* @param string $key The header name
|
* @param string $key The header name
|
||||||
* @param string|string[]|null $default The default value
|
* @param string|null $default The default value
|
||||||
* @param bool $first Whether to return the first value or all header values
|
* @param bool $first Whether to return the first value or all header values
|
||||||
*
|
*
|
||||||
* @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise
|
* @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise
|
||||||
|
@ -96,14 +96,22 @@ class GuardAuthenticationListener implements ListenerInterface
|
|||||||
$request = $event->getRequest();
|
$request = $event->getRequest();
|
||||||
try {
|
try {
|
||||||
if (null !== $this->logger) {
|
if (null !== $this->logger) {
|
||||||
$this->logger->debug('Calling getCredentials() on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)));
|
$this->logger->debug('Checking support on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// abort the execution of the authenticator if it doesn't support the request
|
// abort the execution of the authenticator if it doesn't support the request
|
||||||
if (!$guardAuthenticator->supports($request)) {
|
if (!$guardAuthenticator->supports($request)) {
|
||||||
|
if (null !== $this->logger) {
|
||||||
|
$this->logger->debug('Guard authenticator does not support the request.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)));
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $this->logger) {
|
||||||
|
$this->logger->debug('Calling getCredentials() on guard authenticator.', array('firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)));
|
||||||
|
}
|
||||||
|
|
||||||
// allow the authenticator to fetch authentication info from the request
|
// allow the authenticator to fetch authentication info from the request
|
||||||
$credentials = $guardAuthenticator->getCredentials($request);
|
$credentials = $guardAuthenticator->getCredentials($request);
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ trait TargetPathTrait
|
|||||||
* @param SessionInterface $session
|
* @param SessionInterface $session
|
||||||
* @param string $providerKey The name of your firewall
|
* @param string $providerKey The name of your firewall
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
private function getTargetPath(SessionInterface $session, $providerKey)
|
private function getTargetPath(SessionInterface $session, $providerKey)
|
||||||
{
|
{
|
||||||
|
@ -358,25 +358,9 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
|
|||||||
unset($data[$key]);
|
unset($data[$key]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
if (null !== $constructorParameter->getClass()) {
|
|
||||||
if (!$this->serializer instanceof DenormalizerInterface) {
|
|
||||||
throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $constructorParameter->getClass(), static::class));
|
|
||||||
}
|
|
||||||
$parameterClass = $constructorParameter->getClass()->getName();
|
|
||||||
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $paramName));
|
|
||||||
}
|
|
||||||
} catch (\ReflectionException $e) {
|
|
||||||
throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e);
|
|
||||||
} catch (MissingConstructorArgumentsException $e) {
|
|
||||||
if (!$constructorParameter->getType()->allowsNull()) {
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
$parameterData = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't run set for a parameter passed to the constructor
|
// Don't run set for a parameter passed to the constructor
|
||||||
$params[] = $parameterData;
|
$params[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format);
|
||||||
unset($data[$key]);
|
unset($data[$key]);
|
||||||
} elseif (array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? array())) {
|
} elseif (array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? array())) {
|
||||||
$params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];
|
$params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];
|
||||||
@ -397,6 +381,31 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
|
|||||||
return new $class();
|
return new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, $parameterName, $parameterData, array $context, $format = null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (null !== $parameter->getClass()) {
|
||||||
|
if (!$this->serializer instanceof DenormalizerInterface) {
|
||||||
|
throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $parameter->getClass(), static::class));
|
||||||
|
}
|
||||||
|
$parameterClass = $parameter->getClass()->getName();
|
||||||
|
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName));
|
||||||
|
}
|
||||||
|
} catch (\ReflectionException $e) {
|
||||||
|
throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e);
|
||||||
|
} catch (MissingConstructorArgumentsException $e) {
|
||||||
|
if (!$parameter->getType()->allowsNull()) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
$parameterData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parameterData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $parentContext
|
* @param array $parentContext
|
||||||
* @param string $attribute
|
* @param string $attribute
|
||||||
|
@ -357,6 +357,18 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
|||||||
throw new NotNormalizableValueException(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), \gettype($data)));
|
throw new NotNormalizableValueException(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), \gettype($data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, $parameterName, $parameterData, array $context, $format = null)
|
||||||
|
{
|
||||||
|
if (null === $this->propertyTypeExtractor || null === $types = $this->propertyTypeExtractor->getTypes($class->getName(), $parameterName)) {
|
||||||
|
return parent::denormalizeParameter($class, $parameter, $parameterName, $parameterData, $context, $format);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->validateAndDenormalize($class->getName(), $parameterName, $parameterData, $format, $context);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Type[]|null
|
* @return Type[]|null
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
<?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\Serializer\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
||||||
|
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Serializer;
|
||||||
|
|
||||||
|
class DeserializeNestedArrayOfObjectsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function provider()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
//from property PhpDoc
|
||||||
|
array(Zoo::class),
|
||||||
|
//from argument constructor PhpDoc
|
||||||
|
array(ZooImmutable::class),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provider
|
||||||
|
*/
|
||||||
|
public function testPropertyPhpDoc($class)
|
||||||
|
{
|
||||||
|
//GIVEN
|
||||||
|
$json = <<<EOF
|
||||||
|
{
|
||||||
|
"animals": [
|
||||||
|
{"name": "Bug"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF;
|
||||||
|
$serializer = new Serializer(array(
|
||||||
|
new ObjectNormalizer(null, null, null, new PhpDocExtractor()),
|
||||||
|
new ArrayDenormalizer(),
|
||||||
|
), array('json' => new JsonEncoder()));
|
||||||
|
//WHEN
|
||||||
|
/** @var Zoo $zoo */
|
||||||
|
$zoo = $serializer->deserialize($json, $class, 'json');
|
||||||
|
//THEN
|
||||||
|
self::assertCount(1, $zoo->getAnimals());
|
||||||
|
self::assertInstanceOf(Animal::class, $zoo->getAnimals()[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Zoo
|
||||||
|
{
|
||||||
|
/** @var Animal[] */
|
||||||
|
private $animals = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Animal[]
|
||||||
|
*/
|
||||||
|
public function getAnimals()
|
||||||
|
{
|
||||||
|
return $this->animals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Animal[] $animals
|
||||||
|
*/
|
||||||
|
public function setAnimals(array $animals)
|
||||||
|
{
|
||||||
|
$this->animals = $animals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZooImmutable
|
||||||
|
{
|
||||||
|
/** @var Animal[] */
|
||||||
|
private $animals = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Animal[] $animals
|
||||||
|
*/
|
||||||
|
public function __construct(array $animals = array())
|
||||||
|
{
|
||||||
|
$this->animals = $animals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Animal[]
|
||||||
|
*/
|
||||||
|
public function getAnimals()
|
||||||
|
{
|
||||||
|
return $this->animals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Animal
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
echo '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $name
|
||||||
|
*/
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ It can also be used with extensions defined in the [HTML5 link type extensions w
|
|||||||
Resources
|
Resources
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* [Documentation](https://symfony.com/doc/current/components/weblink/introduction.html)
|
* [Documentation](https://symfony.com/doc/current/components/web_link.html)
|
||||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||||
|
@ -78,6 +78,7 @@ class Inline
|
|||||||
mb_internal_encoding('ASCII');
|
mb_internal_encoding('ASCII');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$tag = self::parseTag($value, $i, $flags);
|
$tag = self::parseTag($value, $i, $flags);
|
||||||
switch ($value[$i]) {
|
switch ($value[$i]) {
|
||||||
@ -102,11 +103,12 @@ class Inline
|
|||||||
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
} finally {
|
||||||
if (isset($mbEncoding)) {
|
if (isset($mbEncoding)) {
|
||||||
mb_internal_encoding($mbEncoding);
|
mb_internal_encoding($mbEncoding);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user