Merge branch '3.1'

* 3.1:
  fixed CS
  Properly format value in UniqueEntityValidator
  [Translation][fallback] add missing resources in parent catalogues.
  removed a deprecation notice
  [Form] Fix show float values as choices values in ChoiceType
  Remove double use Statement
  Improved the design of the metrics in the profiler
  [Yaml] set arguments depending on the PHP version
  [Console] Fix infinite loop on missing input
  [HttpFoundation][Session] memcached connection should not be closed
This commit is contained in:
Fabien Potencier 2016-11-06 08:24:48 -08:00
commit 832686b7a2
18 changed files with 255 additions and 43 deletions

View File

@ -12,6 +12,8 @@
namespace Symfony\Bridge\Doctrine\Test;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\ORM\EntityManager;
@ -25,22 +27,19 @@ class DoctrineTestHelper
/**
* Returns an entity manager for testing.
*
* @param Configuration|null $config
*
* @return EntityManager
*/
public static function createTestEntityManager()
public static function createTestEntityManager(Configuration $config = null)
{
if (!extension_loaded('pdo_sqlite')) {
\PHPUnit_Framework_TestCase::markTestSkipped('Extension pdo_sqlite is required.');
}
$config = new \Doctrine\ORM\Configuration();
$config->setEntityNamespaces(array('SymfonyTestsDoctrine' => 'Symfony\Bridge\Doctrine\Tests\Fixtures'));
$config->setAutoGenerateProxyClasses(true);
$config->setProxyDir(\sys_get_temp_dir());
$config->setProxyNamespace('SymfonyTests\Doctrine');
$config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader()));
$config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache());
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache());
if (null === $config) {
$config = self::createTestConfiguration();
}
$params = array(
'driver' => 'pdo_sqlite',
@ -50,6 +49,23 @@ class DoctrineTestHelper
return EntityManager::create($params, $config);
}
/**
* @return Configuration
*/
public static function createTestConfiguration()
{
$config = new Configuration();
$config->setEntityNamespaces(array('SymfonyTestsDoctrine' => 'Symfony\Bridge\Doctrine\Tests\Fixtures'));
$config->setAutoGenerateProxyClasses(true);
$config->setProxyDir(\sys_get_temp_dir());
$config->setProxyNamespace('SymfonyTests\Doctrine');
$config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader()));
$config->setQueryCacheImpl(new ArrayCache());
$config->setMetadataCacheImpl(new ArrayCache());
return $config;
}
/**
* This class cannot be instantiated.
*/

View File

@ -0,0 +1,66 @@
<?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\Bridge\Doctrine\Test;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Repository\RepositoryFactory;
/**
* @author Andreas Braun <alcaeus@alcaeus.org>
*/
final class TestRepositoryFactory implements RepositoryFactory
{
/**
* @var ObjectRepository[]
*/
private $repositoryList = array();
/**
* {@inheritdoc}
*/
public function getRepository(EntityManagerInterface $entityManager, $entityName)
{
$repositoryHash = $this->getRepositoryHash($entityManager, $entityName);
if (isset($this->repositoryList[$repositoryHash])) {
return $this->repositoryList[$repositoryHash];
}
return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName);
}
public function setRepository(EntityManagerInterface $entityManager, $entityName, ObjectRepository $repository)
{
$repositoryHash = $this->getRepositoryHash($entityManager, $entityName);
$this->repositoryList[$repositoryHash] = $repository;
}
/**
* @return ObjectRepository
*/
private function createRepository(EntityManagerInterface $entityManager, $entityName)
{
/* @var $metadata ClassMetadata */
$metadata = $entityManager->getClassMetadata($entityName);
$repositoryClassName = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
return new $repositoryClassName($entityManager, $metadata);
}
private function getRepositoryHash(EntityManagerInterface $entityManager, $entityName)
{
return $entityManager->getClassMetadata($entityName)->getName().spl_object_hash($entityManager);
}
}

View File

@ -24,6 +24,9 @@ class SingleIntIdEntity
/** @Column(type="string", nullable=true) */
public $name;
/** @Column(type="array", nullable=true) */
public $phoneNumbers = array();
public function __construct($id, $name)
{
$this->id = $id;

View File

@ -16,6 +16,7 @@ use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\ObjectRepository;
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
use Symfony\Bridge\Doctrine\Test\TestRepositoryFactory;
use Symfony\Bridge\Doctrine\Tests\Fixtures\Employee;
use Symfony\Bridge\Doctrine\Tests\Fixtures\Person;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
@ -52,9 +53,16 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
*/
protected $repository;
protected $repositoryFactory;
protected function setUp()
{
$this->em = DoctrineTestHelper::createTestEntityManager();
$this->repositoryFactory = new TestRepositoryFactory();
$config = DoctrineTestHelper::createTestConfiguration();
$config->setRepositoryFactory($this->repositoryFactory);
$this->em = DoctrineTestHelper::createTestEntityManager($config);
$this->registry = $this->createRegistryMock($this->em);
$this->createSchema($this->em);
@ -170,7 +178,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.name')
->setParameter('{{ value }}', 'Foo')
->setParameter('{{ value }}', '"Foo"')
->setInvalidValue('Foo')
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
@ -195,7 +203,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.bar')
->setParameter('{{ value }}', 'Foo')
->setParameter('{{ value }}', '"Foo"')
->setInvalidValue('Foo')
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
@ -248,7 +256,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.name')
->setParameter('{{ value }}', 'Foo')
->setParameter('{{ value }}', '"Foo"')
->setInvalidValue('Foo')
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
@ -281,7 +289,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.name2')
->setParameter('{{ value }}', 'Bar')
->setParameter('{{ value }}', '"Bar"')
->setInvalidValue('Bar')
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
@ -452,7 +460,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.single')
->setParameter('{{ value }}', $expectedValue)
->setParameter('{{ value }}', '"'.$expectedValue.'"')
->setInvalidValue($expectedValue)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
@ -478,6 +486,44 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->assertNoViolation();
}
public function testValidateUniquenessWithArrayValue()
{
$repository = $this->createRepositoryMock();
$this->repositoryFactory->setRepository($this->em, 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity', $repository);
$constraint = new UniqueEntity(array(
'message' => 'myMessage',
'fields' => array('phoneNumbers'),
'em' => self::EM_NAME,
'repositoryMethod' => 'findByCustom',
));
$entity1 = new SingleIntIdEntity(1, 'foo');
$entity1->phoneNumbers[] = 123;
$repository->expects($this->once())
->method('findByCustom')
->will($this->returnValue(array($entity1)))
;
$this->em->persist($entity1);
$this->em->flush();
$entity2 = new SingleIntIdEntity(2, 'bar');
$entity2->phoneNumbers[] = 123;
$this->em->persist($entity2);
$this->em->flush();
$this->validator->validate($entity2, $constraint);
$this->buildViolation('myMessage')
->atPath('property.path.phoneNumbers')
->setParameter('{{ value }}', 'array')
->setInvalidValue(array(123))
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
}
/**
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
* @expectedExceptionMessage Object manager "foo" does not exist.

View File

@ -147,7 +147,7 @@ class UniqueEntityValidator extends ConstraintValidator
$this->context->buildViolation($constraint->message)
->atPath($errorPath)
->setParameter('{{ value }}', $invalidValue)
->setParameter('{{ value }}', $this->formatValue($invalidValue, static::OBJECT_TO_STRING | static::PRETTY_DATE))
->setInvalidValue($invalidValue)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->addViolation();

View File

@ -49,7 +49,7 @@ class TranslationDefaultDomainNodeVisitor extends \Twig_BaseNodeVisitor
return $node;
} else {
$var = $env->getParser()->getVarName();
$var = $this->getVarName();
$name = new \Twig_Node_Expression_AssignName($var, $node->getTemplateLine());
$this->scope->set('domain', new \Twig_Node_Expression_Name($var, $node->getTemplateLine()));
@ -123,4 +123,9 @@ class TranslationDefaultDomainNodeVisitor extends \Twig_BaseNodeVisitor
return false;
}
private function getVarName()
{
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
}
}

View File

@ -60,10 +60,19 @@
<span class="label">Symfony initialization</span>
</div>
{% if profile.collectors.memory %}
<div class="metric">
<span class="value">{{ '%.2f'|format(profile.collectors.memory.memory / 1024 / 1024) }} <span class="unit">MB</span></span>
<span class="label">Peak memory usage</span>
</div>
{% endif %}
{% if profile.children|length > 0 %}
<div class="metric-divider"></div>
<div class="metric">
<span class="value">{{ profile.children|length }}</span>
<span class="label">Sub-Requests</span>
<span class="label">Sub-Request{{ profile.children|length > 1 ? 's' }}</span>
</div>
{% set subrequests_time = 0 %}
@ -73,14 +82,7 @@
<div class="metric">
<span class="value">{{ subrequests_time }} <span class="unit">ms</span></span>
<span class="label">Sub-Requests time</span>
</div>
{% endif %}
{% if profile.collectors.memory %}
<div class="metric">
<span class="value">{{ '%.2f'|format(profile.collectors.memory.memory / 1024 / 1024) }} <span class="unit">MB</span></span>
<span class="label">Peak memory usage</span>
<span class="label">Sub-Request{{ profile.children|length > 1 ? 's' }} time</span>
</div>
{% endif %}
</div>

View File

@ -257,12 +257,12 @@ table tbody ul {
{# Metrics
------------------------------------------------------------------------- #}
.metrics {
margin: 1em 0;
margin: 1em 0 0;
overflow: auto;
}
.metrics .metric {
float: left;
margin-right: 1em;
margin: 0 1em 1em 0;
}
.metric {
@ -317,6 +317,12 @@ table tbody ul {
vertical-align: middle;
}
.metric-divider {
float: left;
margin: 0 1em;
min-height: 1px; {# required to apply 'margin' to an empty 'div' #}
}
{# Cards
------------------------------------------------------------------------- #}
.card {

View File

@ -149,7 +149,7 @@ class QuestionHelper extends Helper
if (false === $ret) {
$ret = fgets($inputStream, 4096);
if (false === $ret) {
throw new \RuntimeException('Aborted');
throw new RuntimeException('Aborted');
}
$ret = trim($ret);
}
@ -412,6 +412,8 @@ class QuestionHelper extends Helper
try {
return call_user_func($question->getValidator(), $interviewer());
} catch (RuntimeException $e) {
throw $e;
} catch (\Exception $error) {
}
}

View File

@ -744,6 +744,37 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$dialog->ask($this->createInputInterfaceMock(), $output, $question);
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted
*/
public function testAskThrowsExceptionOnMissingInput()
{
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream(''));
$dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?'));
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted
*/
public function testAskThrowsExceptionOnMissingInputWithValidator()
{
$dialog = new QuestionHelper();
$dialog->setInputStream($this->getInputStream(''));
$question = new Question('What\'s your name?');
$question->setValidator(function () {
if (!$value) {
throw new \Exception('A value is required.');
}
});
$dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question);
}
protected function getInputStream($input)
{
$stream = fopen('php://memory', 'r+', false);

View File

@ -101,6 +101,18 @@ class SymfonyQuestionHelperTest extends AbstractQuestionHelperTest
$this->assertOutputContains('Do you want a \?', $output);
}
/**
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
* @expectedExceptionMessage Aborted
*/
public function testAskThrowsExceptionOnMissingInput()
{
$dialog = new SymfonyQuestionHelper();
$dialog->setInputStream($this->getInputStream(''));
$dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?'));
}
protected function getInputStream($input)
{
$stream = fopen('php://memory', 'r+', false);

View File

@ -230,7 +230,11 @@ class ArrayChoiceList implements ChoiceListInterface
continue;
} elseif (!is_scalar($choice)) {
return false;
} elseif (isset($cache[$choice])) {
}
$choice = false === $choice ? '0' : (string) $choice;
if (isset($cache[$choice])) {
return false;
}

View File

@ -34,12 +34,12 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
protected function getChoices()
{
return array(0, 1, '1', 'a', false, true, $this->object, null);
return array(0, 1, 1.5, '1', 'a', false, true, $this->object, null);
}
protected function getValues()
{
return array('0', '1', '2', '3', '4', '5', '6', '7');
return array('0', '1', '2', '3', '4', '5', '6', '7', '8');
}
public function testCreateChoiceListWithValueCallback()
@ -154,4 +154,13 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
$this->assertSame(array(0 => true), $choiceList->getChoicesForValues(array('1')));
$this->assertSame(array(0 => false), $choiceList->getChoicesForValues(array('0')));
}
public function testGetChoicesForValuesWithContainingEmptyStringAndFloats()
{
$choiceList = new ArrayChoiceList(array('Empty String' => '', '1/3' => 0.3, '1/2' => 0.5));
$this->assertSame(array(0 => ''), $choiceList->getChoicesForValues(array('')));
$this->assertSame(array(0 => 0.3), $choiceList->getChoicesForValues(array('0.3')));
$this->assertSame(array(0 => 0.5), $choiceList->getChoicesForValues(array('0.5')));
}
}

View File

@ -71,7 +71,7 @@ class MemcacheSessionHandler implements \SessionHandlerInterface
*/
public function close()
{
return $this->memcache->close();
return true;
}
/**

View File

@ -56,12 +56,6 @@ class MemcacheSessionHandlerTest extends \PHPUnit_Framework_TestCase
public function testCloseSession()
{
$this->memcache
->expects($this->once())
->method('close')
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->close());
}

View File

@ -179,6 +179,10 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
if ($c->getLocale() === $catalogue->getLocale()) {
throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
}
foreach ($catalogue->getResources() as $resource) {
$c->addResource($resource);
}
} while ($c = $c->parent);
$catalogue->parent = $this;

View File

@ -110,18 +110,25 @@ class MessageCatalogueTest extends \PHPUnit_Framework_TestCase
$r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
$r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
$catalogue = new MessageCatalogue('en_US', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
$r2 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
$r2->expects($this->any())->method('__toString')->will($this->returnValue('r2'));
$catalogue = new MessageCatalogue('fr_FR', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
$catalogue->addResource($r);
$catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1')));
$catalogue1 = new MessageCatalogue('fr', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1')));
$catalogue1->addResource($r1);
$catalogue2 = new MessageCatalogue('en');
$catalogue2->addResource($r2);
$catalogue->addFallbackCatalogue($catalogue1);
$catalogue1->addFallbackCatalogue($catalogue2);
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
$this->assertEquals(array($r, $r1), $catalogue->getResources());
$this->assertEquals(array($r, $r1, $r2), $catalogue->getResources());
}
/**

View File

@ -566,7 +566,12 @@ class InlineTest extends \PHPUnit_Framework_TestCase
$expected = new \DateTime($yaml);
$expected->setTimeZone(new \DateTimeZone('UTC'));
$expected->setDate($year, $month, $day);
@$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second));
if (PHP_VERSION_ID >= 70100) {
$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second));
} else {
$expected->setTime($hour, $minute, $second);
}
$this->assertEquals($expected, Inline::parse($yaml, Yaml::PARSE_DATETIME));
}