merged 2.0 branch

This commit is contained in:
Fabien Potencier 2011-09-15 07:39:20 +02:00
commit 3a4d1a6a22
14 changed files with 177 additions and 54 deletions

View File

@ -69,6 +69,7 @@ class TestSessionListener
if ($session = $event->getRequest()->getSession()) {
$session->save();
$session->close();
$params = session_get_cookie_params();

View File

@ -32,7 +32,7 @@
</trans-unit>
<trans-unit id="8">
<source>One or more of the given values is invalid</source>
<target>One or more of the given values is invalid</target>
<target>Ett eller fler av de valda värdena är ogiltigt</target>
</trans-unit>
<trans-unit id="9">
<source>The fields {{ fields }} were not expected</source>

View File

@ -157,18 +157,19 @@ class DateType extends AbstractType
public function getDefaultOptions(array $options)
{
return array(
'years' => range(date('Y') - 5, date('Y') + 5),
'months' => range(1, 12),
'days' => range(1, 31),
'widget' => 'choice',
'input' => 'datetime',
'format' => \IntlDateFormatter::MEDIUM,
'data_timezone' => null,
'user_timezone' => null,
'empty_value' => null,
'years' => range(date('Y') - 5, date('Y') + 5),
'months' => range(1, 12),
'days' => range(1, 31),
'widget' => 'choice',
'input' => 'datetime',
'format' => \IntlDateFormatter::MEDIUM,
'data_timezone' => null,
'user_timezone' => null,
'empty_value' => null,
// Don't modify \DateTime classes by reference, we treat
// them like immutable value objects
'by_reference' => false,
'by_reference' => false,
'error_bubbling' => false,
);
}

View File

@ -123,18 +123,19 @@ class TimeType extends AbstractType
public function getDefaultOptions(array $options)
{
return array(
'hours' => range(0, 23),
'minutes' => range(0, 59),
'seconds' => range(0, 59),
'widget' => 'choice',
'input' => 'datetime',
'with_seconds' => false,
'data_timezone' => null,
'user_timezone' => null,
'empty_value' => null,
'hours' => range(0, 23),
'minutes' => range(0, 59),
'seconds' => range(0, 59),
'widget' => 'choice',
'input' => 'datetime',
'with_seconds' => false,
'data_timezone' => null,
'user_timezone' => null,
'empty_value' => null,
// Don't modify \DateTime classes by reference, we treat
// them like immutable value objects
'by_reference' => false,
'by_reference' => false,
'error_bubbling' => false,
);
}

View File

@ -11,8 +11,6 @@
namespace Symfony\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage;
/**
* Request represents an HTTP request.
*
@ -298,15 +296,15 @@ class Request
$dup->server = new ServerBag($server);
$dup->headers = new HeaderBag($dup->server->getHeaders());
}
$this->languages = null;
$this->charsets = null;
$this->acceptableContentTypes = null;
$this->pathInfo = null;
$this->requestUri = null;
$this->baseUrl = null;
$this->basePath = null;
$this->method = null;
$this->format = null;
$dup->languages = null;
$dup->charsets = null;
$dup->acceptableContentTypes = null;
$dup->pathInfo = null;
$dup->requestUri = null;
$dup->baseUrl = null;
$dup->basePath = null;
$dup->method = null;
$dup->format = null;
return $dup;
}

View File

@ -29,7 +29,7 @@ class Session implements \Serializable
protected $oldFlashes;
protected $locale;
protected $defaultLocale;
protected $saved;
protected $closed;
/**
* Constructor.
@ -47,7 +47,7 @@ class Session implements \Serializable
$this->attributes = array();
$this->setPhpDefaultLocale($this->defaultLocale);
$this->started = false;
$this->saved = false;
$this->closed = false;
}
/**
@ -194,7 +194,7 @@ class Session implements \Serializable
public function invalidate()
{
$this->clear();
$this->storage->regenerate();
$this->storage->regenerate(true);
}
/**
@ -358,12 +358,22 @@ class Session implements \Serializable
'flashes' => $this->flashes,
'locale' => $this->locale,
));
$this->saved = true;
}
/**
* This method should be called when you don't want the session to be saved
* when the Session object is garbaged collected (useful for instance when
* you want to simulate the interaction of several users/sessions in a single
* PHP process).
*/
public function close()
{
$this->closed = true;
}
public function __destruct()
{
if (true === $this->started && !$this->saved) {
if (true === $this->started && !$this->closed) {
$this->save();
}
}

View File

@ -25,6 +25,7 @@ class MessageCatalogue implements MessageCatalogueInterface
private $messages = array();
private $locale;
private $resources;
private $fallbackCatalogue;
/**
* Constructor.
@ -91,6 +92,22 @@ class MessageCatalogue implements MessageCatalogueInterface
* @api
*/
public function has($id, $domain = 'messages')
{
if (isset($this->messages[$domain][$id])) {
return true;
}
if (null !== $this->fallbackCatalogue) {
return $this->fallbackCatalogue->has($id, $domain);
}
return false;
}
/**
* {@inheritdoc}
*/
public function defines($id, $domain = 'messages')
{
return isset($this->messages[$domain][$id]);
}
@ -102,7 +119,15 @@ class MessageCatalogue implements MessageCatalogueInterface
*/
public function get($id, $domain = 'messages')
{
return isset($this->messages[$domain][$id]) ? $this->messages[$domain][$id] : $id;
if (isset($this->messages[$domain][$id])) {
return $this->messages[$domain][$id];
}
if (null !== $this->fallbackCatalogue) {
return $this->fallbackCatalogue->get($id, $domain);
}
return $id;
}
/**
@ -158,13 +183,7 @@ class MessageCatalogue implements MessageCatalogueInterface
*/
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
{
foreach ($catalogue->getDomains() as $domain) {
foreach ($catalogue->all($domain) as $id => $translation) {
if (false === $this->has($id, $domain)) {
$this->set($id, $translation, $domain);
}
}
}
$this->fallbackCatalogue = $catalogue;
foreach ($catalogue->getResources() as $resource) {
$this->addResource($resource);

View File

@ -76,6 +76,18 @@ interface MessageCatalogueInterface
*/
function has($id, $domain = 'messages');
/**
* Checks if a message has a translation (it does not take into account the fallback mechanism).
*
* @param string $id The message id
* @param string $domain The domain name
*
* @return Boolean true if the message has a translation, false otherwise
*
* @api
*/
function defines($id, $domain = 'messages');
/**
* Gets a message translation.
*

View File

@ -54,9 +54,9 @@ class MessageSelector
foreach ($parts as $part) {
$part = trim($part);
if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s+(?P<message>.+?)$/x', $part, $matches)) {
if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s*(?P<message>.*?)$/x', $part, $matches)) {
$explicitRules[$matches['interval']] = $matches['message'];
} elseif (preg_match('/^\w+\: +(.+)$/', $part, $matches)) {
} elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
$standardRules[] = $matches[1];
} else {
$standardRules[] = $part;

View File

@ -142,6 +142,11 @@ class Translator implements TranslatorInterface
$this->loadCatalogue($locale);
}
if (!$this->catalogues[$locale]->defines((string) $id, $domain)) {
// we will use the fallback
$locale = $this->computeFallbackLocale($locale);
}
return strtr($this->selector->choose($this->catalogues[$locale]->get((string) $id, $domain), (int) $number, $locale), $parameters);
}
@ -163,13 +168,7 @@ class Translator implements TranslatorInterface
private function optimizeCatalogue($locale)
{
if (strlen($locale) > 3) {
$fallback = substr($locale, 0, -strlen(strrchr($locale, '_')));
} else {
$fallback = $this->fallbackLocale;
}
if (!$fallback) {
if (!$fallback = $this->computeFallbackLocale($locale)) {
return;
}
@ -179,4 +178,13 @@ class Translator implements TranslatorInterface
$this->catalogues[$locale]->addFallbackCatalogue($this->catalogues[$fallback]);
}
private function computeFallbackLocale($locale)
{
if (strlen($locale) > 3) {
return substr($locale, 0, -strlen(strrchr($locale, '_')));
} else {
return $this->fallbackLocale;
}
}
}

View File

@ -1120,6 +1120,17 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
);
}
public function testDateErrorBubbling()
{
$child = $this->factory->createNamed('date', 'date');
$form = $this->factory->createNamed('form', 'form')->add($child);
$child->addError(new FormError('Error!'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
$this->assertNotEmpty($this->renderErrors($view['date']));
}
public function testBirthDay()
{
$form = $this->factory->createNamed('birthday', 'na&me', '2000-02-03', array(
@ -1646,6 +1657,17 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
);
}
public function testTimeErrorBubbling()
{
$child = $this->factory->createNamed('time', 'time');
$form = $this->factory->createNamed('form', 'form')->add($child);
$child->addError(new FormError('Error!'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
$this->assertNotEmpty($this->renderErrors($view['time']));
}
public function testTimezone()
{
$form = $this->factory->createNamed('timezone', 'na&me', 'Europe/Vienna', array(

View File

@ -200,6 +200,38 @@ class SessionTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array(), $this->session->getFlashes());
$this->assertSame(array(), $this->session->all());
}
public function testSavedOnDestruct()
{
$this->session->set('foo', 'bar');
$this->session->__destruct();
$expected = array(
'attributes'=>array('foo'=>'bar'),
'flashes'=>array(),
'locale'=>'en'
);
$saved = $this->storage->read('_symfony2');
$this->assertSame($expected, $saved);
}
public function testSavedOnDestructAfterManualSave()
{
$this->session->set('foo', 'nothing');
$this->session->save();
$this->session->set('foo', 'bar');
$this->session->__destruct();
$expected = array(
'attributes'=>array('foo'=>'bar'),
'flashes'=>array(),
'locale'=>'en'
);
$saved = $this->storage->read('_symfony2');
$this->assertSame($expected, $saved);
}
public function testStorageRegenerate()
{

View File

@ -39,8 +39,14 @@ class MessageSelectorTest extends \PHPUnit_Framework_TestCase
{
return array(
array('There is no apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
array('There is no apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
array('There is no apples', '{0}There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
array('There is one apple', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 1),
array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10),
array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf]There is %count% apples', 10),
array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10),
array('There is %count% apples', 'There is one apple|There is %count% apples', 0),
array('There is one apple', 'There is one apple|There is %count% apples', 1),
@ -53,6 +59,9 @@ class MessageSelectorTest extends \PHPUnit_Framework_TestCase
array('There is no apples', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 0),
array('There is one apple', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 1),
array('There is %count% apples', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 10),
array('', '{0}|{1} There is one apple|]1,Inf] There is %count% apples', 0),
array('', '{0} There is no apples|{1}|]1,Inf] There is %count% apples', 1),
);
}
}

View File

@ -163,6 +163,16 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
array('Il y a 0 pomme', new String('{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
);
}
public function testTransChoiceFallback()
{
$translator = new Translator('ru', new MessageSelector());
$translator->setFallbackLocale('en');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
}
}
class String