Merge branch '2.2'
* 2.2: Fix finding ACLs from ObjectIdentity's with different types [HttpKernel] tweaked previous merge #7531: [HttpKernel][Config] FileLocator adds NULL as global resource path Fix autocompletion of command names when namespaces conflict Fix timeout in Process::stop method fixed CS Round stream_select fifth argument up. Fix Process timeout [HttpKernel] Remove args from 5.3 stack traces to avoid filling log files, fixes #7259 bumped Symfony version to 2.2.2-DEV updated VERSION for 2.2.1 updated CHANGELOG for 2.2.1 Fixed phpdoc blocks to show that $uri can be passed as a string or ControllerReference (rather than just as a string) [HttpFoundation] Fixed copy pasted comment from FlashBag in AttributeBag [FrameworkBundle] fixed the discovery of the PHPUnit configuration file when using aggregate options like in -vc app/ (closes #7562) [WebProfilerBundle] removed next pointer class in a template fix overwriting of request's locale if attribute _locale is missing Conflicts: src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php src/Symfony/Component/HttpKernel/Kernel.php
This commit is contained in:
commit
83e078a035
@ -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 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
|
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)
|
* 2.2.0 (2013-03-01)
|
||||||
|
|
||||||
* 5b19c89: [Console] fixed unparsed StringInput tokens
|
* 5b19c89: [Console] fixed unparsed StringInput tokens
|
||||||
|
@ -45,8 +45,8 @@ class HttpKernelExtension extends \Twig_Extension
|
|||||||
/**
|
/**
|
||||||
* Renders a fragment.
|
* Renders a fragment.
|
||||||
*
|
*
|
||||||
* @param string $uri A URI
|
* @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
|
||||||
* @param array $options An array of options
|
* @param array $options An array of options
|
||||||
*
|
*
|
||||||
* @return string The fragment content
|
* @return string The fragment content
|
||||||
*
|
*
|
||||||
@ -63,9 +63,9 @@ class HttpKernelExtension extends \Twig_Extension
|
|||||||
/**
|
/**
|
||||||
* Renders a fragment.
|
* Renders a fragment.
|
||||||
*
|
*
|
||||||
* @param string $strategy A strategy name
|
* @param string $strategy A strategy name
|
||||||
* @param string $uri A URI
|
* @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
|
||||||
* @param array $options An array of options
|
* @param array $options An array of options
|
||||||
*
|
*
|
||||||
* @return string The fragment content
|
* @return string The fragment content
|
||||||
*
|
*
|
||||||
|
@ -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
|
* 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()
|
private static function getPhpUnitCliConfigArgument()
|
||||||
{
|
{
|
||||||
$dir = null;
|
$dir = null;
|
||||||
$reversedArgs = array_reverse($_SERVER['argv']);
|
$reversedArgs = array_reverse($_SERVER['argv']);
|
||||||
foreach ($reversedArgs as $argIndex => $testArg) {
|
foreach ($reversedArgs as $argIndex => $testArg) {
|
||||||
if ($testArg === '-c' || $testArg === '--configuration') {
|
if (preg_match('/^-[^ \-]*c$/', $testArg) || $testArg === '--configuration') {
|
||||||
$dir = realpath($reversedArgs[$argIndex - 1]);
|
$dir = realpath($reversedArgs[$argIndex - 1]);
|
||||||
break;
|
break;
|
||||||
} elseif (strpos($testArg, '--configuration=') === 0) {
|
} elseif (strpos($testArg, '--configuration=') === 0) {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
{{ collector.controller.method }}
|
{{ collector.controller.method }}
|
||||||
</span>
|
</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="sf-toolbar-info-class sf-toolbar-info-with-next-pointer">{{ collector.controller }}</span>
|
<span class="sf-toolbar-info-class">{{ collector.controller }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endset %}
|
{% endset %}
|
||||||
{% set request_status_code_color = (400 > collector.statuscode) ? ((200 == collector.statuscode) ? 'green' : 'yellow') : 'red'%}
|
{% set request_status_code_color = (400 > collector.statuscode) ? ((200 == collector.statuscode) ? 'green' : 'yellow') : 'red'%}
|
||||||
|
@ -503,20 +503,24 @@ class Application
|
|||||||
*/
|
*/
|
||||||
public function findNamespace($namespace)
|
public function findNamespace($namespace)
|
||||||
{
|
{
|
||||||
$allNamespaces = array();
|
$allNamespaces = $this->getNamespaces();
|
||||||
foreach ($this->getNamespaces() as $n) {
|
$found = '';
|
||||||
$allNamespaces[$n] = explode(':', $n);
|
|
||||||
}
|
|
||||||
|
|
||||||
$found = array();
|
|
||||||
foreach (explode(':', $namespace) as $i => $part) {
|
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])) {
|
if (!isset($abbrevs[$part])) {
|
||||||
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
|
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
|
||||||
|
|
||||||
if (1 <= $i) {
|
if (1 <= $i) {
|
||||||
$part = implode(':', $found).':'.$part;
|
$part = $found.':'.$part;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) {
|
if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) {
|
||||||
@ -532,14 +536,19 @@ class Application
|
|||||||
throw new \InvalidArgumentException($message);
|
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) {
|
if (count($abbrevs[$part]) > 1) {
|
||||||
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part])));
|
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();
|
$abbrevs = array();
|
||||||
foreach ($names as $name) {
|
foreach ($names as $name) {
|
||||||
for ($len = strlen($name) - 1; $len > 0; --$len) {
|
for ($len = strlen($name); $len > 0; --$len) {
|
||||||
$abbrev = substr($name, 0, $len);
|
$abbrev = substr($name, 0, $len);
|
||||||
if (!isset($abbrevs[$abbrev])) {
|
$abbrevs[$abbrev][] = $name;
|
||||||
$abbrevs[$abbrev] = array($name);
|
|
||||||
} else {
|
|
||||||
$abbrevs[$abbrev][] = $name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-abbreviations always get entered, even if they aren't unique
|
|
||||||
foreach ($names as $name) {
|
|
||||||
$abbrevs[$name] = array($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $abbrevs;
|
return $abbrevs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
public function testSetCatchExceptions()
|
||||||
{
|
{
|
||||||
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
|
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
|
||||||
|
@ -87,7 +87,17 @@ class ErrorHandler
|
|||||||
|
|
||||||
if ($level & (E_USER_DEPRECATED | E_DEPRECATED)) {
|
if ($level & (E_USER_DEPRECATED | E_DEPRECATED)) {
|
||||||
if (null !== self::$logger) {
|
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));
|
self::$logger->warning($message, array('type' => self::TYPE_DEPRECATION, 'stack' => $stack));
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* 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')
|
public function __construct($storageKey = '_sf2_attributes')
|
||||||
{
|
{
|
||||||
|
@ -28,14 +28,16 @@ class FileLocator extends BaseFileLocator
|
|||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param KernelInterface $kernel A KernelInterface instance
|
* @param KernelInterface $kernel A KernelInterface instance
|
||||||
* @param string $path The path the global resource directory
|
* @param null|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 array $paths An array of paths where to look for resources
|
||||||
*/
|
*/
|
||||||
public function __construct(KernelInterface $kernel, $path = null, array $paths = array())
|
public function __construct(KernelInterface $kernel, $path = null, array $paths = array())
|
||||||
{
|
{
|
||||||
$this->kernel = $kernel;
|
$this->kernel = $kernel;
|
||||||
$this->path = $path;
|
if (null !== $path) {
|
||||||
$paths[] = $path;
|
$this->path = $path;
|
||||||
|
$paths[] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
parent::__construct($paths);
|
parent::__construct($paths);
|
||||||
}
|
}
|
||||||
|
47
src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php
Executable file
47
src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
@ -68,6 +68,17 @@ class LocaleListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$listener->onKernelRequest($this->getEvent($request));
|
$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)
|
private function getEvent(Request $request)
|
||||||
{
|
{
|
||||||
return new GetResponseEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, HttpKernelInterface::MASTER_REQUEST);
|
return new GetResponseEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, HttpKernelInterface::MASTER_REQUEST);
|
||||||
|
@ -35,10 +35,14 @@ class Process
|
|||||||
const STDOUT = 1;
|
const STDOUT = 1;
|
||||||
const STDERR = 2;
|
const STDERR = 2;
|
||||||
|
|
||||||
|
// Timeout Precision in seconds.
|
||||||
|
const TIMEOUT_PRECISION = 0.2;
|
||||||
|
|
||||||
private $commandline;
|
private $commandline;
|
||||||
private $cwd;
|
private $cwd;
|
||||||
private $env;
|
private $env;
|
||||||
private $stdin;
|
private $stdin;
|
||||||
|
private $starttime;
|
||||||
private $timeout;
|
private $timeout;
|
||||||
private $options;
|
private $options;
|
||||||
private $exitcode;
|
private $exitcode;
|
||||||
@ -228,6 +232,7 @@ class Process
|
|||||||
throw new RuntimeException('Process is already running');
|
throw new RuntimeException('Process is already running');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->starttime = microtime(true);
|
||||||
$this->stdout = '';
|
$this->stdout = '';
|
||||||
$this->stderr = '';
|
$this->stderr = '';
|
||||||
$this->incrementalOutputOffset = 0;
|
$this->incrementalOutputOffset = 0;
|
||||||
@ -304,7 +309,7 @@ class Process
|
|||||||
$w = $writePipes;
|
$w = $writePipes;
|
||||||
$e = null;
|
$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) {
|
if (false === $n) {
|
||||||
break;
|
break;
|
||||||
@ -337,6 +342,8 @@ class Process
|
|||||||
unset($this->pipes[$type]);
|
unset($this->pipes[$type]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->checkTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->updateStatus();
|
$this->updateStatus();
|
||||||
@ -360,7 +367,7 @@ class Process
|
|||||||
public function restart($callback = null)
|
public function restart($callback = null)
|
||||||
{
|
{
|
||||||
if ($this->isRunning()) {
|
if ($this->isRunning()) {
|
||||||
throw new \RuntimeException('Process is already running');
|
throw new RuntimeException('Process is already running');
|
||||||
}
|
}
|
||||||
|
|
||||||
$process = clone $this;
|
$process = clone $this;
|
||||||
@ -391,13 +398,15 @@ class Process
|
|||||||
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
|
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
|
||||||
$this->processFileHandles($callback, !$this->pipes);
|
$this->processFileHandles($callback, !$this->pipes);
|
||||||
}
|
}
|
||||||
|
$this->checkTimeout();
|
||||||
|
|
||||||
if ($this->pipes) {
|
if ($this->pipes) {
|
||||||
$r = $this->pipes;
|
$r = $this->pipes;
|
||||||
$w = null;
|
$w = null;
|
||||||
$e = 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();
|
$lastError = error_get_last();
|
||||||
|
|
||||||
// stream_select returns false when the `select` system call is interrupted by an incoming signal
|
// stream_select returns false when the `select` system call is interrupted by an incoming signal
|
||||||
@ -407,10 +416,10 @@ class Process
|
|||||||
|
|
||||||
continue;
|
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) {
|
foreach ($r as $pipe) {
|
||||||
@ -712,7 +721,7 @@ class Process
|
|||||||
*/
|
*/
|
||||||
public function stop($timeout = 10)
|
public function stop($timeout = 10)
|
||||||
{
|
{
|
||||||
$timeoutMicro = (int) $timeout*10E6;
|
$timeoutMicro = (int) $timeout*1E6;
|
||||||
if ($this->isRunning()) {
|
if ($this->isRunning()) {
|
||||||
proc_terminate($this->process);
|
proc_terminate($this->process);
|
||||||
$time = 0;
|
$time = 0;
|
||||||
@ -721,6 +730,10 @@ class Process
|
|||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defined('PHP_WINDOWS_VERSION_BUILD') && $this->isRunning()) {
|
||||||
|
proc_terminate($this->process, SIGKILL);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->pipes as $pipe) {
|
foreach ($this->pipes as $pipe) {
|
||||||
fclose($pipe);
|
fclose($pipe);
|
||||||
}
|
}
|
||||||
@ -800,7 +813,7 @@ class Process
|
|||||||
*
|
*
|
||||||
* To disable the timeout, set this value to null.
|
* 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
|
* @return self The current Process instance
|
||||||
*
|
*
|
||||||
@ -814,10 +827,10 @@ class Process
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeout = (integer) $timeout;
|
$timeout = (float) $timeout;
|
||||||
|
|
||||||
if ($timeout < 0) {
|
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;
|
$this->timeout = $timeout;
|
||||||
@ -982,6 +995,24 @@ class Process
|
|||||||
return $this;
|
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().
|
* Builds up the callback used by wait().
|
||||||
*
|
*
|
||||||
|
@ -103,7 +103,7 @@ class ProcessBuilder
|
|||||||
*
|
*
|
||||||
* To disable the timeout, set this value to null.
|
* To disable the timeout, set this value to null.
|
||||||
*
|
*
|
||||||
* @param integer|null
|
* @param float|null
|
||||||
*
|
*
|
||||||
* @return ProcessBuilder
|
* @return ProcessBuilder
|
||||||
*
|
*
|
||||||
@ -117,10 +117,10 @@ class ProcessBuilder
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeout = (integer) $timeout;
|
$timeout = (float) $timeout;
|
||||||
|
|
||||||
if ($timeout < 0) {
|
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;
|
$this->timeout = $timeout;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\Process\Tests;
|
namespace Symfony\Component\Process\Tests;
|
||||||
|
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
|
use Symfony\Component\Process\Exception\RuntimeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||||
@ -44,6 +45,31 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertNull($p->getTimeout());
|
$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
|
* 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
|
// 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()
|
public function responsesCodeProvider()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
|
37
src/Symfony/Component/Process/Tests/NonStopableProcess.php
Normal file
37
src/Symfony/Component/Process/Tests/NonStopableProcess.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a PHP script that can be stopped only with a SIGKILL (9) signal for 3 seconds
|
||||||
|
*
|
||||||
|
* @args duration Run this script with a custom duration
|
||||||
|
*
|
||||||
|
* @example `php NonStopableProcess.php 42` will run the script for 42 seconds
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handleSignal($signal)
|
||||||
|
{
|
||||||
|
switch ($signal) {
|
||||||
|
case SIGTERM:
|
||||||
|
$name = 'SIGTERM';
|
||||||
|
break;
|
||||||
|
case SIGINT:
|
||||||
|
$name = 'SIGINT';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$name = $signal . ' (unknown)';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "received signal $name\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
declare(ticks=1);
|
||||||
|
pcntl_signal(SIGTERM, 'handleSignal');
|
||||||
|
pcntl_signal(SIGINT, 'handleSignal');
|
||||||
|
|
||||||
|
$duration = isset($argv[1]) ? (int) $argv[1] : 3;
|
||||||
|
$start = microtime(true);
|
||||||
|
|
||||||
|
while ($duration > (microtime(true) - $start)) {
|
||||||
|
usleep(1000);
|
||||||
|
}
|
@ -263,7 +263,11 @@ SELECTCLAUSE;
|
|||||||
for ($i = 0; $i < $count; $i++) {
|
for ($i = 0; $i < $count; $i++) {
|
||||||
if (!isset($types[$batch[$i]->getType()])) {
|
if (!isset($types[$batch[$i]->getType()])) {
|
||||||
$types[$batch[$i]->getType()] = true;
|
$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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,23 @@ class AclProviderTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertTrue($oids[1]->equals($acl1->getObjectIdentity()));
|
$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()
|
public function testFindAclCachesAclInMemory()
|
||||||
{
|
{
|
||||||
$oid = new ObjectIdentity('1', 'foo');
|
$oid = new ObjectIdentity('1', 'foo');
|
||||||
|
Reference in New Issue
Block a user