[FrameworkBundle][Validator] Move the PSR-11 factory to the component
This commit is contained in:
parent
2642e725da
commit
68c1917af9
|
@ -203,11 +203,6 @@ FrameworkBundle
|
||||||
deprecated and will be removed in 4.0. Use the `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass`
|
deprecated and will be removed in 4.0. Use the `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass`
|
||||||
class instead.
|
class instead.
|
||||||
|
|
||||||
* The `ConstraintValidatorFactory::$validators` and `$container` properties
|
|
||||||
have been deprecated and will be removed in 4.0.
|
|
||||||
|
|
||||||
* Extending `ConstraintValidatorFactory` is deprecated and won't be supported in 4.0.
|
|
||||||
|
|
||||||
* Class parameters related to routing have been deprecated and will be removed in 4.0.
|
* Class parameters related to routing have been deprecated and will be removed in 4.0.
|
||||||
* router.options.generator_class
|
* router.options.generator_class
|
||||||
* router.options.generator_base_class
|
* router.options.generator_base_class
|
||||||
|
@ -246,9 +241,9 @@ FrameworkBundle
|
||||||
class has been deprecated and will be removed in 4.0. Use the
|
class has been deprecated and will be removed in 4.0. Use the
|
||||||
`Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass` class instead.
|
`Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass` class instead.
|
||||||
|
|
||||||
* Passing an array of validators or validator aliases as the second argument of
|
* The `Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory`
|
||||||
`ConstraintValidatorFactory::__construct()` is deprecated since 3.3 and will
|
class has been deprecated and will be removed in 4.0.
|
||||||
be removed in 4.0. Use the service locator instead.
|
Use `Symfony\Component\Validator\ContainerConstraintValidatorFactory` instead.
|
||||||
|
|
||||||
HttpFoundation
|
HttpFoundation
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -294,15 +294,6 @@ FrameworkBundle
|
||||||
removed. Use the `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass`
|
removed. Use the `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass`
|
||||||
class instead.
|
class instead.
|
||||||
|
|
||||||
* The `ConstraintValidatorFactory::$validators` and `$container` properties
|
|
||||||
have been removed.
|
|
||||||
|
|
||||||
* Extending `ConstraintValidatorFactory` is not supported anymore.
|
|
||||||
|
|
||||||
* Passing an array of validators or validator aliases as the second argument of
|
|
||||||
`ConstraintValidatorFactory::__construct()` has been removed.
|
|
||||||
Use the service locator instead.
|
|
||||||
|
|
||||||
* Class parameters related to routing have been removed
|
* Class parameters related to routing have been removed
|
||||||
* router.options.generator_class
|
* router.options.generator_class
|
||||||
* router.options.generator_base_class
|
* router.options.generator_base_class
|
||||||
|
@ -335,6 +326,9 @@ FrameworkBundle
|
||||||
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ValidateWorkflowsPass` class
|
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ValidateWorkflowsPass` class
|
||||||
has been removed. Use the `Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass`
|
has been removed. Use the `Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass`
|
||||||
class instead.
|
class instead.
|
||||||
|
|
||||||
|
* The `Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory` class has been removed.
|
||||||
|
Use `Symfony\Component\Validator\ContainerConstraintValidatorFactory` instead.
|
||||||
|
|
||||||
HttpFoundation
|
HttpFoundation
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -31,7 +31,6 @@ CHANGELOG
|
||||||
* Deprecated `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ConfigCachePass`.
|
* Deprecated `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ConfigCachePass`.
|
||||||
Use `Symfony\Component\Console\DependencyInjection\ConfigCachePass` instead.
|
Use `Symfony\Component\Console\DependencyInjection\ConfigCachePass` instead.
|
||||||
* Deprecated `PropertyInfoPass`, use `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass` instead
|
* Deprecated `PropertyInfoPass`, use `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass` instead
|
||||||
* Deprecated extending `ConstraintValidatorFactory`
|
|
||||||
* Deprecated `ControllerArgumentValueResolverPass`. Use
|
* Deprecated `ControllerArgumentValueResolverPass`. Use
|
||||||
`Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass` instead
|
`Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass` instead
|
||||||
* Deprecated `RoutingResolverPass`, use `Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` instead
|
* Deprecated `RoutingResolverPass`, use `Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` instead
|
||||||
|
@ -47,9 +46,10 @@ CHANGELOG
|
||||||
`Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass` instead
|
`Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass` instead
|
||||||
* Deprecated `AddConstraintValidatorsPass`, use
|
* Deprecated `AddConstraintValidatorsPass`, use
|
||||||
`Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass` instead
|
`Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass` instead
|
||||||
* Deprecated `ValidateWorkflowsPass`, use
|
* Deprecated `ValidateWorkflowsPass`, use
|
||||||
`Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass` instead
|
`Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass` instead
|
||||||
* Deprecated `ConstraintValidatorFactory::__construct()` second argument.
|
* Deprecated `ConstraintValidatorFactory`, use
|
||||||
|
`Symfony\Component\Validator\ContainerConstraintValidatorFactory` instead.
|
||||||
|
|
||||||
3.2.0
|
3.2.0
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
</argument>
|
</argument>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="validator.validator_factory" class="Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory">
|
<service id="validator.validator_factory" class="Symfony\Component\Validator\ContainerConstraintValidatorFactory">
|
||||||
<argument /> <!-- Constraint validators locator -->
|
<argument /> <!-- Constraint validators locator -->
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\Constraints\Blank as BlankConstraint;
|
use Symfony\Component\Validator\Constraints\Blank as BlankConstraint;
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
class ConstraintValidatorFactoryTest extends TestCase
|
class ConstraintValidatorFactoryTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGetInstanceCreatesValidator()
|
public function testGetInstanceCreatesValidator()
|
||||||
|
@ -27,7 +30,7 @@ class ConstraintValidatorFactoryTest extends TestCase
|
||||||
|
|
||||||
$constraint = $this->getMockBuilder('Symfony\\Component\\Validator\\Constraint')->getMock();
|
$constraint = $this->getMockBuilder('Symfony\\Component\\Validator\\Constraint')->getMock();
|
||||||
$constraint
|
$constraint
|
||||||
->expects($this->once())
|
->expects($this->exactly(2))
|
||||||
->method('validatedBy')
|
->method('validatedBy')
|
||||||
->will($this->returnValue($class));
|
->will($this->returnValue($class));
|
||||||
|
|
||||||
|
@ -63,7 +66,7 @@ class ConstraintValidatorFactoryTest extends TestCase
|
||||||
|
|
||||||
$constraint = $this->getMockBuilder(Constraint::class)->getMock();
|
$constraint = $this->getMockBuilder(Constraint::class)->getMock();
|
||||||
$constraint
|
$constraint
|
||||||
->expects($this->once())
|
->expects($this->exactly(2))
|
||||||
->method('validatedBy')
|
->method('validatedBy')
|
||||||
->will($this->returnValue($service));
|
->will($this->returnValue($service));
|
||||||
|
|
||||||
|
@ -71,10 +74,6 @@ class ConstraintValidatorFactoryTest extends TestCase
|
||||||
$this->assertSame($validator, $factory->getInstance($constraint));
|
$this->assertSame($validator, $factory->getInstance($constraint));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @group legacy
|
|
||||||
* @expectedDeprecation Passing an array of validators or validator aliases as the second argument of "Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory::__construct" is deprecated since 3.3 and will be removed in 4.0. Use the service locator instead.
|
|
||||||
*/
|
|
||||||
public function testGetInstanceReturnsServiceWithAlias()
|
public function testGetInstanceReturnsServiceWithAlias()
|
||||||
{
|
{
|
||||||
$service = 'validator_constraint_service';
|
$service = 'validator_constraint_service';
|
||||||
|
@ -106,7 +105,7 @@ class ConstraintValidatorFactoryTest extends TestCase
|
||||||
{
|
{
|
||||||
$constraint = $this->getMockBuilder('Symfony\\Component\\Validator\\Constraint')->getMock();
|
$constraint = $this->getMockBuilder('Symfony\\Component\\Validator\\Constraint')->getMock();
|
||||||
$constraint
|
$constraint
|
||||||
->expects($this->once())
|
->expects($this->exactly(2))
|
||||||
->method('validatedBy')
|
->method('validatedBy')
|
||||||
->will($this->returnValue('Fully\\Qualified\\ConstraintValidator\\Class\\Name'));
|
->will($this->returnValue('Fully\\Qualified\\ConstraintValidator\\Class\\Name'));
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,12 @@ namespace Symfony\Bundle\FrameworkBundle\Validator;
|
||||||
|
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
|
|
||||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||||
use Symfony\Component\Validator\Exception\ValidatorException;
|
use Symfony\Component\Validator\ContainerConstraintValidatorFactory;
|
||||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||||
|
|
||||||
|
@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use %s instead.', ConstraintValidatorFactory::class, ContainerConstraintValidatorFactory::class), E_USER_DEPRECATED);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses a service container to create constraint validators.
|
* Uses a service container to create constraint validators.
|
||||||
|
@ -38,24 +40,19 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
*
|
*
|
||||||
* @author Kris Wallsmith <kris@symfony.com>
|
* @author Kris Wallsmith <kris@symfony.com>
|
||||||
*
|
*
|
||||||
* @final since version 3.3
|
* @deprecated since version 3.3
|
||||||
*/
|
*/
|
||||||
class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
|
class ConstraintValidatorFactory extends ContainerConstraintValidatorFactory
|
||||||
{
|
{
|
||||||
protected $container;
|
protected $container;
|
||||||
protected $validators;
|
protected $validators;
|
||||||
|
|
||||||
public function __construct(ContainerInterface $container, array $validators = null)
|
public function __construct(ContainerInterface $container, array $validators = array())
|
||||||
{
|
{
|
||||||
$this->container = $container;
|
parent::__construct($container);
|
||||||
|
|
||||||
if (null !== $validators) {
|
|
||||||
@trigger_error(sprintf('Passing an array of validators or validator aliases as the second argument of "%s" is deprecated since 3.3 and will be removed in 4.0. Use the service locator instead.', __METHOD__), E_USER_DEPRECATED);
|
|
||||||
} else {
|
|
||||||
$validators = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->validators = $validators;
|
$this->validators = $validators;
|
||||||
|
$this->container = $container;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,17 +70,10 @@ class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
|
||||||
$name = $constraint->validatedBy();
|
$name = $constraint->validatedBy();
|
||||||
|
|
||||||
if (!isset($this->validators[$name])) {
|
if (!isset($this->validators[$name])) {
|
||||||
if ($this->container->has($name)) {
|
return parent::getInstance($constraint);
|
||||||
$this->validators[$name] = $this->container->get($name);
|
}
|
||||||
} else {
|
|
||||||
if (!class_exists($name)) {
|
|
||||||
throw new ValidatorException(sprintf('Constraint validator "%s" does not exist or it is not enabled. Check the "validatedBy" method in your constraint class "%s".', $name, get_class($constraint)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->validators[$name] = new $name();
|
if (is_string($this->validators[$name])) {
|
||||||
}
|
|
||||||
} elseif (is_string($this->validators[$name])) {
|
|
||||||
// To be removed in 4.0
|
|
||||||
$this->validators[$name] = $this->container->get($this->validators[$name]);
|
$this->validators[$name] = $this->container->get($this->validators[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
"symfony/serializer": "~3.3",
|
"symfony/serializer": "~3.3",
|
||||||
"symfony/translation": "~3.2",
|
"symfony/translation": "~3.2",
|
||||||
"symfony/templating": "~2.8|~3.0",
|
"symfony/templating": "~2.8|~3.0",
|
||||||
"symfony/validator": "~3.3",
|
"symfony/validator": "~3.3-rc2",
|
||||||
"symfony/workflow": "~3.3",
|
"symfony/workflow": "~3.3",
|
||||||
"symfony/yaml": "~3.2",
|
"symfony/yaml": "~3.2",
|
||||||
"symfony/property-info": "~3.3",
|
"symfony/property-info": "~3.3",
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
"symfony/property-info": "<3.3",
|
"symfony/property-info": "<3.3",
|
||||||
"symfony/serializer": "<3.3",
|
"symfony/serializer": "<3.3",
|
||||||
"symfony/translation": "<3.2",
|
"symfony/translation": "<3.2",
|
||||||
"symfony/validator": "<3.3",
|
"symfony/validator": "<3.3-rc2",
|
||||||
"symfony/workflow": "<3.3"
|
"symfony/workflow": "<3.3"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
|
|
@ -6,6 +6,7 @@ CHANGELOG
|
||||||
|
|
||||||
* added `AddValidatorInitializersPass`
|
* added `AddValidatorInitializersPass`
|
||||||
* added `AddConstraintValidatorsPass`
|
* added `AddConstraintValidatorsPass`
|
||||||
|
* added `ContainerConstraintValidatorFactory`
|
||||||
|
|
||||||
3.2.0
|
3.2.0
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?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;
|
||||||
|
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses a service container to create constraint validators.
|
||||||
|
*
|
||||||
|
* @author Kris Wallsmith <kris@symfony.com>
|
||||||
|
*/
|
||||||
|
class ContainerConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
|
||||||
|
{
|
||||||
|
private $container;
|
||||||
|
private $validators;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
$this->validators = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @throws ValidatorException When the validator class does not exist
|
||||||
|
* @throws UnexpectedTypeException When the validator is not an instance of ConstraintValidatorInterface
|
||||||
|
*/
|
||||||
|
public function getInstance(Constraint $constraint)
|
||||||
|
{
|
||||||
|
$name = $constraint->validatedBy();
|
||||||
|
|
||||||
|
if (!isset($this->validators[$name])) {
|
||||||
|
if ($this->container->has($name)) {
|
||||||
|
$this->validators[$name] = $this->container->get($name);
|
||||||
|
} else {
|
||||||
|
if (!class_exists($name)) {
|
||||||
|
throw new ValidatorException(sprintf('Constraint validator "%s" does not exist or it is not enabled. Check the "validatedBy" method in your constraint class "%s".', $name, get_class($constraint)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->validators[$name] = new $name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->validators[$name] instanceof ConstraintValidatorInterface) {
|
||||||
|
throw new UnexpectedTypeException($this->validators[$name], ConstraintValidatorInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->validators[$name];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?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;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\DependencyInjection\Container;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\Constraints\Blank as BlankConstraint;
|
||||||
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
use Symfony\Component\Validator\ContainerConstraintValidatorFactory;
|
||||||
|
|
||||||
|
class ContainerConstraintValidatorFactoryTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetInstanceCreatesValidator()
|
||||||
|
{
|
||||||
|
$class = get_class($this->getMockForAbstractClass(ConstraintValidator::class));
|
||||||
|
|
||||||
|
$constraint = $this->getMockBuilder(Constraint::class)->getMock();
|
||||||
|
$constraint
|
||||||
|
->expects($this->once())
|
||||||
|
->method('validatedBy')
|
||||||
|
->will($this->returnValue($class));
|
||||||
|
|
||||||
|
$factory = new ContainerConstraintValidatorFactory(new Container());
|
||||||
|
$this->assertInstanceOf($class, $factory->getInstance($constraint));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInstanceReturnsExistingValidator()
|
||||||
|
{
|
||||||
|
$factory = new ContainerConstraintValidatorFactory(new Container());
|
||||||
|
$v1 = $factory->getInstance(new BlankConstraint());
|
||||||
|
$v2 = $factory->getInstance(new BlankConstraint());
|
||||||
|
$this->assertSame($v1, $v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInstanceReturnsService()
|
||||||
|
{
|
||||||
|
$service = 'validator_constraint_service';
|
||||||
|
$validator = $this->getMockForAbstractClass(ConstraintValidator::class);
|
||||||
|
|
||||||
|
// mock ContainerBuilder b/c it implements TaggedContainerInterface
|
||||||
|
$container = $this->getMockBuilder(ContainerBuilder::class)->setMethods(array('get', 'has'))->getMock();
|
||||||
|
$container
|
||||||
|
->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($service)
|
||||||
|
->willReturn($validator);
|
||||||
|
$container
|
||||||
|
->expects($this->once())
|
||||||
|
->method('has')
|
||||||
|
->with($service)
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$constraint = $this->getMockBuilder(Constraint::class)->getMock();
|
||||||
|
$constraint
|
||||||
|
->expects($this->once())
|
||||||
|
->method('validatedBy')
|
||||||
|
->will($this->returnValue($service));
|
||||||
|
|
||||||
|
$factory = new ContainerConstraintValidatorFactory($container);
|
||||||
|
$this->assertSame($validator, $factory->getInstance($constraint));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Validator\Exception\ValidatorException
|
||||||
|
*/
|
||||||
|
public function testGetInstanceInvalidValidatorClass()
|
||||||
|
{
|
||||||
|
$constraint = $this->getMockBuilder(Constraint::class)->getMock();
|
||||||
|
$constraint
|
||||||
|
->expects($this->once())
|
||||||
|
->method('validatedBy')
|
||||||
|
->will($this->returnValue('Fully\\Qualified\\ConstraintValidator\\Class\\Name'));
|
||||||
|
|
||||||
|
$factory = new ContainerConstraintValidatorFactory(new Container());
|
||||||
|
$factory->getInstance($constraint);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue