diff --git a/src/Symfony/Bridge/Monolog/Handler/SwiftMailerHandler.php b/src/Symfony/Bridge/Monolog/Handler/SwiftMailerHandler.php new file mode 100644 index 0000000000..29134115f3 --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Handler/SwiftMailerHandler.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler; + +use Monolog\Handler\SwiftMailerHandler as BaseSwiftMailerHandler; +use Symfony\Component\HttpKernel\Event\PostResponseEvent; + +/** + * Extended SwiftMailerHandler that flushes mail queue if necessary + * + * @author Philipp Kräutli + */ +class SwiftMailerHandler extends BaseSwiftMailerHandler +{ + protected $transport; + + protected $instantFlush = false; + + /** + * @param \Swift_Transport $transport + */ + public function setTransport(\Swift_Transport $transport) + { + $this->transport = $transport; + } + + /** + * After the kernel has been terminated we will always flush messages + * + * @param PostResponseEvent $event + */ + public function onKernelTerminate(PostResponseEvent $event) + { + $this->instantFlush = true; + } + + /** + * {@inheritdoc} + */ + protected function send($content, array $records) + { + parent::send($content, $records); + + if ($this->instantFlush) { + $this->flushMemorySpool(); + } + } + + /** + * Flushes the mail queue if a memory spool is used + */ + private function flushMemorySpool() + { + $mailerTransport = $this->mailer->getTransport(); + if (!$mailerTransport instanceof \Swift_Transport_SpoolTransport) { + return; + } + + $spool = $mailerTransport->getSpool(); + if (!$spool instanceof \Swift_MemorySpool) { + return; + } + + if (null === $this->transport) { + throw new \Exception('No transport available to flush mail queue'); + } + + $spool->flushQueue($this->transport); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php index 25dcd22869..c0dd358e85 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php @@ -86,7 +86,7 @@ class NamespacedAttributeBag extends AttributeBag $retval = null; $attributes = & $this->resolveAttributePath($name); $name = $this->resolveKey($name); - if (array_key_exists($name, $attributes)) { + if (null !== $attributes && array_key_exists($name, $attributes)) { $retval = $attributes[$name]; unset($attributes[$name]); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php index c11d0d6513..0c46a515a0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php @@ -143,6 +143,16 @@ class NamespacedAttributeBagTest extends \PHPUnit_Framework_TestCase $this->assertNull($this->bag->get('user.login')); } + public function testRemoveExistingNamespacedAttribute() + { + $this->assertSame('cod', $this->bag->remove('category/fishing/first')); + } + + public function testRemoveNonexistingNamespacedAttribute() + { + $this->assertNull($this->bag->remove('foo/bar/baz')); + } + public function testClear() { $this->bag->clear(); diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 5a230780fa..56ce5aac7b 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -167,17 +167,7 @@ class Process public function __clone() { - $this->callback = null; - $this->exitcode = null; - $this->fallbackExitcode = null; - $this->processInformation = null; - $this->stdout = null; - $this->stderr = null; - $this->pipes = null; - $this->process = null; - $this->status = self::STATUS_READY; - $this->fileHandles = null; - $this->readBytes = null; + $this->resetProcessData(); } /** @@ -233,11 +223,8 @@ class Process throw new RuntimeException('Process is already running'); } + $this->resetProcessData(); $this->starttime = microtime(true); - $this->stdout = ''; - $this->stderr = ''; - $this->incrementalOutputOffset = 0; - $this->incrementalErrorOutputOffset = 0; $this->callback = $this->buildCallback($callback); $descriptors = $this->getDescriptors(); @@ -1280,4 +1267,25 @@ class Process return $this->exitcode; } + + /** + * Resets data related to the latest run of the process. + */ + private function resetProcessData() + { + $this->starttime = null; + $this->callback = null; + $this->exitcode = null; + $this->fallbackExitcode = null; + $this->processInformation = null; + $this->stdout = null; + $this->stderr = null; + $this->pipes = null; + $this->process = null; + $this->status = self::STATUS_READY; + $this->fileHandles = null; + $this->readBytes = null; + $this->incrementalOutputOffset = 0; + $this->incrementalErrorOutputOffset = 0; + } } diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php index 36936a54b5..6ed22c1b35 100644 --- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php +++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php @@ -243,6 +243,27 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $this->assertTrue(strlen($process->getOutput()) > 0); } + public function testGetExitCodeIsNullOnStart() + { + $process = $this->getProcess('php -r "usleep(200000);"'); + $this->assertNull($process->getExitCode()); + $process->start(); + $this->assertNull($process->getExitCode()); + $process->wait(); + $this->assertEquals(0, $process->getExitCode()); + } + + public function testGetExitCodeIsNullOnWhenStartingAgain() + { + $process = $this->getProcess('php -r "usleep(200000);"'); + $process->run(); + $this->assertEquals(0, $process->getExitCode()); + $process->start(); + $this->assertNull($process->getExitCode()); + $process->wait(); + $this->assertEquals(0, $process->getExitCode()); + } + public function testGetExitCode() { $process = $this->getProcess('php -m'); diff --git a/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php b/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php index 32b8270d04..71d4ef265e 100644 --- a/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php +++ b/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php @@ -21,6 +21,22 @@ class SigchildDisabledProcessTest extends AbstractProcessTest parent::testGetExitCode(); } + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetExitCodeIsNullOnStart() + { + parent::testGetExitCodeIsNullOnStart(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetExitCodeIsNullOnWhenStartingAgain() + { + parent::testGetExitCodeIsNullOnWhenStartingAgain(); + } + /** * @expectedException \Symfony\Component\Process\Exception\RuntimeException */ diff --git a/src/Symfony/Component/Translation/IdentityTranslator.php b/src/Symfony/Component/Translation/IdentityTranslator.php index f30556b588..8564aa7b3c 100644 --- a/src/Symfony/Component/Translation/IdentityTranslator.php +++ b/src/Symfony/Component/Translation/IdentityTranslator.php @@ -21,6 +21,7 @@ namespace Symfony\Component\Translation; class IdentityTranslator implements TranslatorInterface { private $selector; + private $locale; /** * Constructor. @@ -41,6 +42,7 @@ class IdentityTranslator implements TranslatorInterface */ public function setLocale($locale) { + $this->locale = $locale; } /** @@ -50,6 +52,7 @@ class IdentityTranslator implements TranslatorInterface */ public function getLocale() { + return $this->locale ?: \Locale::getDefault(); } /** @@ -69,6 +72,6 @@ class IdentityTranslator implements TranslatorInterface */ public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null) { - return strtr($this->selector->choose((string) $id, (int) $number, $locale), $parameters); + return strtr($this->selector->choose((string) $id, (int) $number, $locale ?: $this->getLocale()), $parameters); } } diff --git a/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php b/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php index 435f0c2803..ce60995426 100644 --- a/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php @@ -29,19 +29,43 @@ class IdentityTranslatorTest extends \PHPUnit_Framework_TestCase /** * @dataProvider getTransChoiceTests */ - public function testTransChoice($expected, $id, $number, $parameters) + public function testTransChoiceWithExplicitLocale($expected, $id, $number, $parameters) { + $translator = new IdentityTranslator(new MessageSelector()); + $translator->setLocale('en'); + + $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters)); + } + + /** + * @dataProvider getTransChoiceTests + */ + public function testTransChoiceWithDefaultLocale($expected, $id, $number, $parameters) + { + \Locale::setDefault('en'); + $translator = new IdentityTranslator(new MessageSelector()); $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters)); } - // noop public function testGetSetLocale() { $translator = new IdentityTranslator(new MessageSelector()); $translator->setLocale('en'); - $translator->getLocale(); + + $this->assertEquals('en', $translator->getLocale()); + } + + public function testGetLocaleReturnsDefaultLocaleIfNotSet() + { + $translator = new IdentityTranslator(new MessageSelector()); + + \Locale::setDefault('en'); + $this->assertEquals('en', $translator->getLocale()); + + \Locale::setDefault('pt_BR'); + $this->assertEquals('pt_BR', $translator->getLocale()); } public function getTransTests() @@ -55,7 +79,12 @@ class IdentityTranslatorTest extends \PHPUnit_Framework_TestCase public function getTransChoiceTests() { return array( - array('There is 10 apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10, array('%count%' => 10)), + array('There is no apple', '{0} There is no apple|{1} There is one apple|]1,Inf] There are %count% apples', 0, array('%count%' => 0)), + array('There is one apple', '{0} There is no apple|{1} There is one apple|]1,Inf] There are %count% apples', 1, array('%count%' => 1)), + array('There are 10 apples', '{0} There is no apple|{1} There is one apple|]1,Inf] There are %count% apples', 10, array('%count%' => 10)), + array('There are 0 apples', 'There is 1 apple|There are %count% apples', 0, array('%count%' => 0)), + array('There is 1 apple', 'There is 1 apple|There are %count% apples', 1, array('%count%' => 1)), + array('There are 10 apples', 'There is 1 apple|There are %count% apples', 10, array('%count%' => 10)), ); } }