diff --git a/CHANGELOG-2.2.md b/CHANGELOG-2.2.md
index 74f7e2c303..8abd730929 100644
--- a/CHANGELOG-2.2.md
+++ b/CHANGELOG-2.2.md
@@ -7,6 +7,62 @@ in 2.2 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.2.0...v2.2.1
+* 2.2.1 (2013-04-06)
+
+ * 751abe1: Doctrine cannot handle bare random non-utf8 strings
+ * 673fd9b: idAsIndex should be true with a smallint or bigint id field.
+ * 64a1d39: Fixed long multibyte parameter logging in DbalLogger:startQuery
+ * 4cf06c1: Keep the file extension in the temporary copy and test that it exists (closes #7482)
+ * 64ac34d: [Security] fixed wrong interface
+ * 9875c4b: Added '@@' escaping strategy for YamlFileLoader and YamlDumper
+ * bbcdfe2: [Yaml] fixed bugs with folded scalar parsing
+ * 5afea04: [Form] made DefaultCsrfProvider using session_status() when available
+ * c928ddc: [HttpFoudantion] fixed Request::getPreferredLanguage()
+ * e6b7515: [DomCrawler] added support for query string with slash
+ * 633c051: Fixed invalid file path for hiddeninput.exe on Windows.
+ * 7ef90d2: fix xsd definition for strict-requirements
+ * 39445c5: [WebProfilerBundle] Fixed the toolbar styles to apply them in IE8
+ * 601da45: [ClassLoader] fixed heredocs handling
+ * 17dc2ff: [HttpRequest] fixes Request::getLanguages() bug
+ * 67fbbac: [DoctrineBridge] Fixed non-utf-8 recognition
+ * e51432a: sub-requests are now created with the same class as their parent
+ * cc3a40e: [FrameworkBundle] changed temp kernel name in cache:clear
+ * d7a7434: [Routing] fix url generation for optional parameter having a null value
+ * ef53456: [DoctrineBridge] Avoids blob values to be logged by doctrine
+ * 6575df6: [Security] use current request attributes to generate redirect url?
+ * 7216cb0: [Validator] fix showing wrong max file size for upload errors
+ * c423f16: [2.1][TwigBridge] Fixes Issue #7342 in TwigBridge
+ * 7d87ecd: [FrameworkBundle] fixed cahe:clear command's warmup
+ * 5ad4bd1: [TwigBridge] now enter/leave scope on Twig_Node_Module
+ * fe4cc24: [TwigBridge] fixed fixed scope & trans_default_domain node visitor
+ * fc47589: [BrowserKit] added ability to ignored malformed set-cookie header
+ * 602cdee: replace INF to PHP_INT_MAX inside Finder component.
+ * 5bc30bb: [Translation] added xliff loader/dumper with resname support
+ * 663c796: Property accessor custom array object fix
+ * 4f3771d: [2.2][HttpKernel] fixed wrong option name in FragmentHandler::fixOptions
+ * a735cbd: fix xargs pipe to work with spaces in dir names
+ * 15bf033: [FrameworkBundle] fix router debug command
+ * d16d193: [FramworkBundle] removed unused property of trans update command
+ * 523ef29: Fix warning for buildXml method
+ * 7241be9: [Finder] fixed a potential issue on Solaris where INF value is wrong (refs #7269)
+ * 1d3da29: [FrameworkBundle] avoids cache:clear to break if new/old folders already exist
+ * b9cdb9a: [HttpKernel] Fixed possible profiler token collision (closes #7272, closes #7171)
+ * d1f5d25: [FrameworkBundle] Fixes invalid serialized objects in cache
+ * c82c754: RedisProfilerStorage wrong db-number/index-number selected
+ * e86fefa: Unset loading[$id] in ContainerBuilder on exception
+ * 709518b: Default validation message translation fix.
+ * c0687cd: remove() should not use deprecated getParent() so it does not trigger deprecation internally
+ * 708c0d3: adjust routing tests to not use prefix in addCollection
+ * acff735: [Routing] trigger deprecation warning for deprecated features that will be removed in 2.3
+ * 41ad9d8: [Routing] make xml loader more tolerant
+ * 73bead7: [ClassLoader] made DebugClassLoader idempotent
+ * a4ec677: [DomCrawler] Fix relative path handling in links
+ * 6681df0: [Console] fixed StringInput binding
+ * 5bf2f71: [Console] added deprecation annotation
+ * 8d9cd42: Routing issue with installation in a sub-directory ref: https://github.com/symfony/symfony/issues/7129
+ * c97ee8d: [Translator] mention that the message id may also be an object that can be cast to string in TranslatorInterface and fix the IdentityTranslator that did not respect this
+ * 5a36b2d: [Translator] fix MessageCatalogueInterface::getFallbackCatalogue that can return null
+
* 2.2.0 (2013-03-01)
* 5b19c89: [Console] fixed unparsed StringInput tokens
diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php
index 6aadbb7e01..a837723430 100644
--- a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php
@@ -45,8 +45,8 @@ class HttpKernelExtension extends \Twig_Extension
/**
* Renders a fragment.
*
- * @param string $uri A URI
- * @param array $options An array of options
+ * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
+ * @param array $options An array of options
*
* @return string The fragment content
*
@@ -63,9 +63,9 @@ class HttpKernelExtension extends \Twig_Extension
/**
* Renders a fragment.
*
- * @param string $strategy A strategy name
- * @param string $uri A URI
- * @param array $options An array of options
+ * @param string $strategy A strategy name
+ * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
+ * @param array $options An array of options
*
* @return string The fragment content
*
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php
index 1011e1c1b0..37cf41c8eb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php
@@ -84,19 +84,19 @@ abstract class WebTestCase extends \PHPUnit_Framework_TestCase
}
/**
- * Finds the value of configuration flag from cli
+ * Finds the value of the CLI configuration option.
*
* PHPUnit will use the last configuration argument on the command line, so this only returns
- * the last configuration argument
+ * the last configuration argument.
*
- * @return string The value of the phpunit cli configuration option
+ * @return string The value of the PHPUnit cli configuration option
*/
private static function getPhpUnitCliConfigArgument()
{
$dir = null;
$reversedArgs = array_reverse($_SERVER['argv']);
foreach ($reversedArgs as $argIndex => $testArg) {
- if ($testArg === '-c' || $testArg === '--configuration') {
+ if (preg_match('/^-[^ \-]*c$/', $testArg) || $testArg === '--configuration') {
$dir = realpath($reversedArgs[$argIndex - 1]);
break;
} elseif (strpos($testArg, '--configuration=') === 0) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig
index 44a255000c..9c0ea3fb5e 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig
@@ -9,7 +9,7 @@
{{ collector.controller.method }}
{% else %}
- {{ collector.controller }}
+ {{ collector.controller }}
{% endif %}
{% endset %}
{% set request_status_code_color = (400 > collector.statuscode) ? ((200 == collector.statuscode) ? 'green' : 'yellow') : 'red'%}
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index 16f16a33d9..4aec01637f 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -503,20 +503,24 @@ class Application
*/
public function findNamespace($namespace)
{
- $allNamespaces = array();
- foreach ($this->getNamespaces() as $n) {
- $allNamespaces[$n] = explode(':', $n);
- }
-
- $found = array();
+ $allNamespaces = $this->getNamespaces();
+ $found = '';
foreach (explode(':', $namespace) as $i => $part) {
- $abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $allNamespaces)))));
+ // select sub-namespaces matching the current namespace we found
+ $namespaces = array();
+ foreach ($allNamespaces as $n) {
+ if ('' === $found || 0 === strpos($n, $found)) {
+ $namespaces[$n] = explode(':', $n);
+ }
+ }
+
+ $abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $namespaces)))));
if (!isset($abbrevs[$part])) {
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
if (1 <= $i) {
- $part = implode(':', $found).':'.$part;
+ $part = $found.':'.$part;
}
if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) {
@@ -532,14 +536,19 @@ class Application
throw new \InvalidArgumentException($message);
}
+ // there are multiple matches, but $part is an exact match of one of them so we select it
+ if (in_array($part, $abbrevs[$part])) {
+ $abbrevs[$part] = array($part);
+ }
+
if (count($abbrevs[$part]) > 1) {
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part])));
}
- $found[] = $abbrevs[$part][0];
+ $found .= $found ? ':' . $abbrevs[$part][0] : $abbrevs[$part][0];
}
- return implode(':', $found);
+ return $found;
}
/**
@@ -662,21 +671,12 @@ class Application
{
$abbrevs = array();
foreach ($names as $name) {
- for ($len = strlen($name) - 1; $len > 0; --$len) {
+ for ($len = strlen($name); $len > 0; --$len) {
$abbrev = substr($name, 0, $len);
- if (!isset($abbrevs[$abbrev])) {
- $abbrevs[$abbrev] = array($name);
- } else {
- $abbrevs[$abbrev][] = $name;
- }
+ $abbrevs[$abbrev][] = $name;
}
}
- // Non-abbreviations always get entered, even if they aren't unique
- foreach ($names as $name) {
- $abbrevs[$name] = array($name);
- }
-
return $abbrevs;
}
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index 9494211135..9650969592 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -351,6 +351,16 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
}
}
+ public function testFindNamespaceDoesNotFailOnDeepSimilarNamespaces()
+ {
+ $application = $this->getMock('Symfony\Component\Console\Application', array('getNamespaces'));
+ $application->expects($this->once())
+ ->method('getNamespaces')
+ ->will($this->returnValue(array('foo:sublong', 'bar:sub')));
+
+ $this->assertEquals('foo:sublong', $application->findNamespace('f:sub'));
+ }
+
public function testSetCatchExceptions()
{
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php
index b0843c1b01..facb7c8fe3 100644
--- a/src/Symfony/Component/Debug/ErrorHandler.php
+++ b/src/Symfony/Component/Debug/ErrorHandler.php
@@ -87,7 +87,17 @@ class ErrorHandler
if ($level & (E_USER_DEPRECATED | E_DEPRECATED)) {
if (null !== self::$logger) {
- $stack = version_compare(PHP_VERSION, '5.4', '<') ? array_slice(debug_backtrace(false), 0, 10) : debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
+ if (version_compare(PHP_VERSION, '5.4', '<')) {
+ $stack = array_map(
+ function ($row) {
+ unset($row['args']);
+ return $row;
+ },
+ array_slice(debug_backtrace(false), 0, 10)
+ );
+ } else {
+ $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
+ }
self::$logger->warning($message, array('type' => self::TYPE_DEPRECATION, 'stack' => $stack));
}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
index 2f1a4222e7..e9d0257152 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
@@ -31,7 +31,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
/**
* Constructor.
*
- * @param string $storageKey The key used to store flashes in the session.
+ * @param string $storageKey The key used to store attributes in the session.
*/
public function __construct($storageKey = '_sf2_attributes')
{
diff --git a/src/Symfony/Component/HttpKernel/Config/FileLocator.php b/src/Symfony/Component/HttpKernel/Config/FileLocator.php
index d241b9da19..47b543c15e 100644
--- a/src/Symfony/Component/HttpKernel/Config/FileLocator.php
+++ b/src/Symfony/Component/HttpKernel/Config/FileLocator.php
@@ -28,14 +28,16 @@ class FileLocator extends BaseFileLocator
* Constructor.
*
* @param KernelInterface $kernel A KernelInterface instance
- * @param string $path The path the global resource directory
- * @param string|array $paths A path or an array of paths where to look for resources
+ * @param null|string $path The path the global resource directory
+ * @param array $paths An array of paths where to look for resources
*/
public function __construct(KernelInterface $kernel, $path = null, array $paths = array())
{
$this->kernel = $kernel;
- $this->path = $path;
- $paths[] = $path;
+ if (null !== $path) {
+ $this->path = $path;
+ $paths[] = $path;
+ }
parent::__construct($paths);
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php b/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php
new file mode 100755
index 0000000000..be59486269
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\Config;
+
+use Symfony\Component\HttpKernel\Config\FileLocator;
+
+class FileLocatorTest extends \PHPUnit_Framework_TestCase
+{
+ public function testLocate()
+ {
+ $kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
+ $kernel
+ ->expects($this->atLeastOnce())
+ ->method('locateResource')
+ ->with('@BundleName/some/path', null, true)
+ ->will($this->returnValue('/bundle-name/some/path'));
+ $locator = new FileLocator($kernel);
+ $this->assertEquals('/bundle-name/some/path', $locator->locate('@BundleName/some/path'));
+
+ $kernel
+ ->expects($this->never())
+ ->method('locateResource');
+ $this->setExpectedException('LogicException');
+ $locator->locate('/some/path');
+ }
+
+ public function testLocateWithGlobalResourcePath()
+ {
+ $kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
+ $kernel
+ ->expects($this->atLeastOnce())
+ ->method('locateResource')
+ ->with('@BundleName/some/path', '/global/resource/path', false);
+
+ $locator = new FileLocator($kernel, '/global/resource/path');
+ $locator->locate('@BundleName/some/path', null, false);
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php
index 9ca64321b2..e5e4e3a286 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php
@@ -68,6 +68,17 @@ class LocaleListenerTest extends \PHPUnit_Framework_TestCase
$listener->onKernelRequest($this->getEvent($request));
}
+ public function testRequestLocaleIsNotOverridden()
+ {
+ $request = Request::create('/');
+ $request->setLocale('de');
+ $listener = new LocaleListener('fr');
+ $event = $this->getEvent($request);
+
+ $listener->onKernelRequest($event);
+ $this->assertEquals('de', $request->getLocale());
+ }
+
private function getEvent(Request $request)
{
return new GetResponseEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, HttpKernelInterface::MASTER_REQUEST);
diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php
index e60373d57b..0cfd371f6e 100644
--- a/src/Symfony/Component/Process/Process.php
+++ b/src/Symfony/Component/Process/Process.php
@@ -35,10 +35,14 @@ class Process
const STDOUT = 1;
const STDERR = 2;
+ // Timeout Precision in seconds.
+ const TIMEOUT_PRECISION = 0.2;
+
private $commandline;
private $cwd;
private $env;
private $stdin;
+ private $starttime;
private $timeout;
private $options;
private $exitcode;
@@ -228,6 +232,7 @@ class Process
throw new RuntimeException('Process is already running');
}
+ $this->starttime = microtime(true);
$this->stdout = '';
$this->stderr = '';
$this->incrementalOutputOffset = 0;
@@ -304,7 +309,7 @@ class Process
$w = $writePipes;
$e = null;
- $n = @stream_select($r, $w, $e, $this->timeout);
+ $n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6));
if (false === $n) {
break;
@@ -337,6 +342,8 @@ class Process
unset($this->pipes[$type]);
}
}
+
+ $this->checkTimeout();
}
$this->updateStatus();
@@ -360,7 +367,7 @@ class Process
public function restart($callback = null)
{
if ($this->isRunning()) {
- throw new \RuntimeException('Process is already running');
+ throw new RuntimeException('Process is already running');
}
$process = clone $this;
@@ -391,13 +398,15 @@ class Process
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
$this->processFileHandles($callback, !$this->pipes);
}
+ $this->checkTimeout();
if ($this->pipes) {
$r = $this->pipes;
$w = null;
$e = null;
- if (false === $n = @stream_select($r, $w, $e, $this->timeout)) {
+ // let's have a look if something changed in streams
+ if (false === $n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6))) {
$lastError = error_get_last();
// stream_select returns false when the `select` system call is interrupted by an incoming signal
@@ -407,10 +416,10 @@ class Process
continue;
}
- if (0 === $n) {
- proc_terminate($this->process);
- throw new RuntimeException('The process timed out.');
+ // nothing has changed
+ if (0 === $n) {
+ continue;
}
foreach ($r as $pipe) {
@@ -712,7 +721,7 @@ class Process
*/
public function stop($timeout = 10)
{
- $timeoutMicro = (int) $timeout*10E6;
+ $timeoutMicro = (int) $timeout*1E6;
if ($this->isRunning()) {
proc_terminate($this->process);
$time = 0;
@@ -721,6 +730,10 @@ class Process
usleep(1000);
}
+ if (!defined('PHP_WINDOWS_VERSION_BUILD') && $this->isRunning()) {
+ proc_terminate($this->process, SIGKILL);
+ }
+
foreach ($this->pipes as $pipe) {
fclose($pipe);
}
@@ -800,7 +813,7 @@ class Process
*
* To disable the timeout, set this value to null.
*
- * @param integer|null $timeout The timeout in seconds
+ * @param float|null $timeout The timeout in seconds
*
* @return self The current Process instance
*
@@ -814,10 +827,10 @@ class Process
return $this;
}
- $timeout = (integer) $timeout;
+ $timeout = (float) $timeout;
if ($timeout < 0) {
- throw new InvalidArgumentException('The timeout value must be a valid positive integer.');
+ throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}
$this->timeout = $timeout;
@@ -982,6 +995,24 @@ class Process
return $this;
}
+ /**
+ * Performs a check between the timeout definition and the time the process
+ * started
+ *
+ * In case you run a background process (with the start method), you should
+ * trigger this method regularly to ensure the process timeout
+ *
+ * @throws RuntimeException In case the timeout was reached
+ */
+ public function checkTimeout()
+ {
+ if (0 < $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
+ $this->stop(0);
+
+ throw new RuntimeException('The process timed-out.');
+ }
+ }
+
/**
* Builds up the callback used by wait().
*
diff --git a/src/Symfony/Component/Process/ProcessBuilder.php b/src/Symfony/Component/Process/ProcessBuilder.php
index 1a95bd0df4..c4ef31d311 100644
--- a/src/Symfony/Component/Process/ProcessBuilder.php
+++ b/src/Symfony/Component/Process/ProcessBuilder.php
@@ -103,7 +103,7 @@ class ProcessBuilder
*
* To disable the timeout, set this value to null.
*
- * @param integer|null
+ * @param float|null
*
* @return ProcessBuilder
*
@@ -117,10 +117,10 @@ class ProcessBuilder
return $this;
}
- $timeout = (integer) $timeout;
+ $timeout = (float) $timeout;
if ($timeout < 0) {
- throw new InvalidArgumentException('The timeout value must be a valid positive integer.');
+ throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}
$this->timeout = $timeout;
diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php
index 14433deeb6..ec63a39856 100644
--- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php
+++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Process\Tests;
use Symfony\Component\Process\Process;
+use Symfony\Component\Process\Exception\RuntimeException;
/**
* @author Robert Schönthal
@@ -44,6 +45,31 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
$this->assertNull($p->getTimeout());
}
+ public function testStopWithTimeoutIsActuallyWorking()
+ {
+ if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+ $this->markTestSkipped('Stop with timeout does not work on windows, it requires posix signals');
+ }
+ if (!function_exists('pcntl_signal')) {
+ $this->markTestSkipped('This test require pcntl_signal function');
+ }
+
+ // exec is mandatory here since we send a signal to the process
+ // see https://github.com/symfony/symfony/issues/5030 about prepending
+ // command with exec
+ $p = $this->getProcess('exec php '.__DIR__.'/NonStopableProcess.php 3');
+ $p->start();
+ usleep(100000);
+ $start = microtime(true);
+ $p->stop(1.1);
+ while ($p->isRunning()) {
+ usleep(1000);
+ }
+ $duration = microtime(true) - $start;
+
+ $this->assertLessThan(1.3, $duration);
+ }
+
/**
* tests results from sub processes
*
@@ -320,6 +346,47 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
// PHP will deadlock when it tries to cleanup $process
}
+ public function testRunProcessWithTimeout()
+ {
+ $timeout = 0.5;
+ $process = $this->getProcess('sleep 3');
+ $process->setTimeout($timeout);
+ $start = microtime(true);
+ try {
+ $process->run();
+ $this->fail('A RuntimeException should have been raised');
+ } catch (RuntimeException $e) {
+
+ }
+ $duration = microtime(true) - $start;
+
+ $this->assertLessThan($timeout + Process::TIMEOUT_PRECISION, $duration);
+ }
+
+ public function testCheckTimeoutOnStartedProcess()
+ {
+ $timeout = 0.5;
+ $precision = 100000;
+ $process = $this->getProcess('sleep 3');
+ $process->setTimeout($timeout);
+ $start = microtime(true);
+
+ $process->start();
+
+ try {
+ while ($process->isRunning()) {
+ $process->checkTimeout();
+ usleep($precision);
+ }
+ $this->fail('A RuntimeException should have been raised');
+ } catch (RuntimeException $e) {
+
+ }
+ $duration = microtime(true) - $start;
+
+ $this->assertLessThan($timeout + $precision, $duration);
+ }
+
public function responsesCodeProvider()
{
return array(
diff --git a/src/Symfony/Component/Process/Tests/NonStopableProcess.php b/src/Symfony/Component/Process/Tests/NonStopableProcess.php
new file mode 100644
index 0000000000..a4db838256
--- /dev/null
+++ b/src/Symfony/Component/Process/Tests/NonStopableProcess.php
@@ -0,0 +1,37 @@
+ (microtime(true) - $start)) {
+ usleep(1000);
+}
diff --git a/src/Symfony/Component/Security/Acl/Dbal/AclProvider.php b/src/Symfony/Component/Security/Acl/Dbal/AclProvider.php
index 6f47231ed9..822a16017c 100644
--- a/src/Symfony/Component/Security/Acl/Dbal/AclProvider.php
+++ b/src/Symfony/Component/Security/Acl/Dbal/AclProvider.php
@@ -263,7 +263,11 @@ SELECTCLAUSE;
for ($i = 0; $i < $count; $i++) {
if (!isset($types[$batch[$i]->getType()])) {
$types[$batch[$i]->getType()] = true;
- if ($count > 1) {
+
+ // if there is more than one type we can safely break out of the
+ // loop, because it is the differentiator factor on whether to
+ // query for only one or more class types
+ if (count($types) > 1) {
break;
}
}
diff --git a/src/Symfony/Component/Security/Tests/Acl/Dbal/AclProviderTest.php b/src/Symfony/Component/Security/Tests/Acl/Dbal/AclProviderTest.php
index 83771eef21..ad58d72ab2 100644
--- a/src/Symfony/Component/Security/Tests/Acl/Dbal/AclProviderTest.php
+++ b/src/Symfony/Component/Security/Tests/Acl/Dbal/AclProviderTest.php
@@ -72,6 +72,23 @@ class AclProviderTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($oids[1]->equals($acl1->getObjectIdentity()));
}
+ public function testFindAclsWithDifferentTypes()
+ {
+ $oids = array();
+ $oids[] = new ObjectIdentity('123', 'Bundle\SomeVendor\MyBundle\Entity\SomeEntity');
+ $oids[] = new ObjectIdentity('123', 'Bundle\MyBundle\Entity\AnotherEntity');
+
+ $provider = $this->getProvider();
+
+ $acls = $provider->findAcls($oids);
+ $this->assertInstanceOf('SplObjectStorage', $acls);
+ $this->assertCount(2, $acls);
+ $this->assertInstanceOf('Symfony\Component\Security\Acl\Domain\Acl', $acl0 = $acls->offsetGet($oids[0]));
+ $this->assertInstanceOf('Symfony\Component\Security\Acl\Domain\Acl', $acl1 = $acls->offsetGet($oids[1]));
+ $this->assertTrue($oids[0]->equals($acl0->getObjectIdentity()));
+ $this->assertTrue($oids[1]->equals($acl1->getObjectIdentity()));
+ }
+
public function testFindAclCachesAclInMemory()
{
$oid = new ObjectIdentity('1', 'foo');