Merge branch '3.2'

* 3.2:
  Fix errors not rethrown even if not handled by console.error listeners
  [VarDumper] Fix dumping of non-nested stubs
  [Security] Avoid unnecessary route lookup for empty logout path
  respect inline level when dumping objects as maps
  Test case for not in-lined map-objects
This commit is contained in:
Nicolas Grekas 2017-05-15 14:04:53 +02:00
commit af4ec231b0
9 changed files with 143 additions and 13 deletions

View File

@ -135,7 +135,7 @@ class Application
}
if (null !== $e) {
if (!$this->catchExceptions) {
if (!$this->catchExceptions || !$x instanceof \Exception) {
throw $x;
}

View File

@ -1387,6 +1387,29 @@ class ApplicationTest extends TestCase
return $dispatcher;
}
/**
* @requires PHP 7
*/
public function testErrorIsRethrownIfNotHandledByConsoleErrorEventWithCatchingEnabled()
{
$application = new Application();
$application->setAutoExit(false);
$application->setDispatcher(new EventDispatcher());
$application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) {
new \UnknownClass();
});
$tester = new ApplicationTester($application);
try {
$tester->run(array('command' => 'dym'));
$this->fail('->run() should rethrow PHP errors if not handled via ConsoleErrorEvent.');
} catch (\Error $e) {
$this->assertSame($e->getMessage(), 'Class \'UnknownClass\' not found');
}
}
}
class CustomApplication extends Application

View File

@ -127,6 +127,6 @@ class LogoutListener implements ListenerInterface
*/
protected function requiresLogout(Request $request)
{
return $this->httpUtils->checkRequestPath($request, $this->options['logout_path']);
return isset($this->options['logout_path']) && $this->httpUtils->checkRequestPath($request, $this->options['logout_path']);
}
}

View File

@ -111,6 +111,10 @@ class LogoutUrlGenerator
{
list($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager) = $this->getListener($key);
if (null === $logoutPath) {
throw new \LogicException('Unable to generate the logout URL without a path.');
}
$parameters = null !== $csrfTokenManager ? array($csrfParameter => (string) $csrfTokenManager->getToken($csrfTokenId)) : array();
if ('/' === $logoutPath[0]) {

View File

@ -35,8 +35,10 @@ class StubCaster
$stub->class = Stub::STRING_BINARY;
}
return array();
$a = array();
}
return $a;
}
public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested)

View File

@ -319,7 +319,6 @@ EOTXT
}
};'),
));
$line = __LINE__ - 2;
$ref = (int) $out;
$data = $cloner->cloneVar($out);
@ -353,7 +352,7 @@ stream resource {@{$ref}
: \$this->display(\$context);
: } catch (%s \$e) {
}
%sCliDumperTest.php:{$line}: {
%sCliDumperTest.php:%d: {
%A
}
}

View File

@ -81,15 +81,20 @@ class Dumper
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
$dumpObjectAsInlineMap = true;
if ($inline <= 0 || !is_array($input) || empty($input)) {
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($input instanceof \ArrayObject || $input instanceof \stdClass)) {
$dumpObjectAsInlineMap = empty((array) $input);
}
if ($inline <= 0 || (!is_array($input) && $dumpObjectAsInlineMap) || empty($input)) {
$output .= $prefix.Inline::dump($input, $flags);
} else {
$isAHash = Inline::isHash($input);
$dumpAsMap = Inline::isHash($input);
foreach ($input as $key => $value) {
if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && is_string($value) && false !== strpos($value, "\n")) {
$output .= sprintf("%s%s%s |\n", $prefix, $isAHash ? Inline::dump($key, $flags).':' : '-', '');
$output .= sprintf("%s%s%s |\n", $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '');
foreach (preg_split('/\n|\r\n/', $value) as $row) {
$output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row);
@ -98,11 +103,17 @@ class Dumper
continue;
}
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
$dumpObjectAsInlineMap = true;
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) {
$dumpObjectAsInlineMap = empty((array) $value);
}
$willBeInlined = $inline - 1 <= 0 || !is_array($value) && $dumpObjectAsInlineMap || empty($value);
$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? Inline::dump($key, $flags).':' : '-',
$dumpAsMap ? Inline::dump($key, $flags).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags)
).($willBeInlined ? "\n" : '');

View File

@ -174,7 +174,7 @@ class Inline
}
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
return self::dumpArray((array) $value, $flags & ~Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
return self::dumpArray($value, $flags & ~Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
}
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
@ -234,12 +234,16 @@ class Inline
*
* @internal
*
* @param array $value The PHP array to check
* @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
*
* @return bool true if value is hash array, false otherwise
*/
public static function isHash(array $value)
public static function isHash($value)
{
if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
return true;
}
$expectedKey = 0;
foreach ($value as $key => $val) {

View File

@ -351,6 +351,93 @@ EOF;
return $tests;
}
public function testDumpingArrayObjectInstancesRespectsInlineLevel()
{
$deep = new \ArrayObject(array('deep1' => 'd', 'deep2' => 'e'));
$inner = new \ArrayObject(array('inner1' => 'b', 'inner2' => 'c', 'inner3' => $deep));
$outer = new \ArrayObject(array('outer1' => 'a', 'outer2' => $inner));
$yaml = $this->dumper->dump($outer, 2, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
outer1: a
outer2:
inner1: b
inner2: c
inner3: { deep1: d, deep2: e }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingArrayObjectInstancesWithNumericKeysInlined()
{
$deep = new \ArrayObject(array('d', 'e'));
$inner = new \ArrayObject(array('b', 'c', $deep));
$outer = new \ArrayObject(array('a', $inner));
$yaml = $this->dumper->dump($outer, 0, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
{ 0: a, 1: { 0: b, 1: c, 2: { 0: d, 1: e } } }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingArrayObjectInstancesWithNumericKeysRespectsInlineLevel()
{
$deep = new \ArrayObject(array('d', 'e'));
$inner = new \ArrayObject(array('b', 'c', $deep));
$outer = new \ArrayObject(array('a', $inner));
$yaml = $this->dumper->dump($outer, 2, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
0: a
1:
0: b
1: c
2: { 0: d, 1: e }
YAML;
$this->assertEquals($expected, $yaml);
}
public function testDumpEmptyArrayObjectInstanceAsMap()
{
$this->assertSame('{ }', $this->dumper->dump(new \ArrayObject(), 2, 0, Yaml::DUMP_OBJECT_AS_MAP));
}
public function testDumpEmptyStdClassInstanceAsMap()
{
$this->assertSame('{ }', $this->dumper->dump(new \stdClass(), 2, 0, Yaml::DUMP_OBJECT_AS_MAP));
}
public function testDumpingStdClassInstancesRespectsInlineLevel()
{
$deep = new \stdClass();
$deep->deep1 = 'd';
$deep->deep2 = 'e';
$inner = new \stdClass();
$inner->inner1 = 'b';
$inner->inner2 = 'c';
$inner->inner3 = $deep;
$outer = new \stdClass();
$outer->outer1 = 'a';
$outer->outer2 = $inner;
$yaml = $this->dumper->dump($outer, 2, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
outer1: a
outer2:
inner1: b
inner2: c
inner3: { deep1: d, deep2: e }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpMultiLineStringAsScalarBlock()
{
$data = array(