diff --git a/src/Symfony/Component/Yaml/CHANGELOG.md b/src/Symfony/Component/Yaml/CHANGELOG.md index cdd49352d518..1b07b239cd6e 100644 --- a/src/Symfony/Component/Yaml/CHANGELOG.md +++ b/src/Symfony/Component/Yaml/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 3.4.0 ----- + * added support for parsing YAML files using the `Yaml::parseFile()` or `Parser::parseFile()` method + * the `Dumper`, `Parser`, and `Yaml` classes are marked as final * Deprecated the `!php/object:` tag which will be replaced by the diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 4410d221c7df..b1653137fc13 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -26,7 +26,8 @@ class Inline { const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')'; - public static $parsedLineNumber; + public static $parsedLineNumber = -1; + public static $parsedFilename; private static $exceptionOnInvalidType = false; private static $objectSupport = false; @@ -34,19 +35,18 @@ class Inline private static $constantSupport = false; /** - * @param int $flags - * @param int|null $parsedLineNumber + * @param int $flags + * @param int|null $parsedLineNumber + * @param string|null $parsedFilename */ - public static function initialize($flags, $parsedLineNumber = null) + public static function initialize($flags, $parsedLineNumber = null, $parsedFilename = null) { self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags); self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags); self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags); - - if (null !== $parsedLineNumber) { - self::$parsedLineNumber = $parsedLineNumber; - } + self::$parsedFilename = $parsedFilename; + self::$parsedLineNumber = null !== $parsedLineNumber ? $parsedLineNumber : -1; } /** @@ -128,7 +128,7 @@ public static function parse($value, $flags = 0, $references = array()) // some comments are allowed at the end if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) { - throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i))); + throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber, $value, self::$parsedFilename); } if (isset($mbEncoding)) { @@ -322,7 +322,7 @@ public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i if (null !== $delimiters) { $tmp = ltrim(substr($scalar, $i), ' '); if (!in_array($tmp[0], $delimiters)) { - throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i))); + throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber, $scalar, self::$parsedFilename); } } } else { @@ -339,12 +339,12 @@ public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i $output = $match[1]; $i += strlen($output); } else { - throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar)); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar), self::$parsedLineNumber, null, self::$parsedFilename); } // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >) if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) { - throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0])); + throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber, $output, self::$parsedFilename); } if ($output && '%' === $output[0]) { @@ -372,7 +372,7 @@ public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i private static function parseQuotedScalar($scalar, &$i) { if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { - throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i))); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i)), self::$parsedLineNumber, $scalar, self::$parsedFilename); } $output = substr($match[0], 1, strlen($match[0]) - 2); @@ -455,7 +455,7 @@ private static function parseSequence($sequence, $flags, &$i = 0, $references = ++$i; } - throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence)); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence), self::$parsedLineNumber, null, self::$parsedFilename); } /** @@ -572,7 +572,7 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar } } - throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping)); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping), self::$parsedLineNumber, null, self::$parsedFilename); } /** @@ -600,11 +600,11 @@ private static function evaluateScalar($scalar, $flags, $references = array()) // an unquoted * if (false === $value || '' === $value) { - throw new ParseException('A reference must contain at least one character.'); + throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber, $value, self::$parsedFilename); } if (!array_key_exists($value, $references)) { - throw new ParseException(sprintf('Reference "%s" does not exist.', $value)); + throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber, $value, self::$parsedFilename); } return $references[$value]; @@ -639,7 +639,7 @@ private static function evaluateScalar($scalar, $flags, $references = array()) } if (self::$exceptionOnInvalidType) { - throw new ParseException('Object support when parsing a YAML file has been disabled.'); + throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber, $scalar, self::$parsedFilename); } return; @@ -651,7 +651,7 @@ private static function evaluateScalar($scalar, $flags, $references = array()) } if (self::$exceptionOnInvalidType) { - throw new ParseException('Object support when parsing a YAML file has been disabled.'); + throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber, $scalar, self::$parsedFilename); } return; @@ -661,7 +661,7 @@ private static function evaluateScalar($scalar, $flags, $references = array()) } if (self::$exceptionOnInvalidType) { - throw new ParseException('Object support when parsing a YAML file has been disabled.'); + throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber, $scalar, self::$parsedFilename); } return; @@ -673,10 +673,10 @@ private static function evaluateScalar($scalar, $flags, $references = array()) return constant($const); } - throw new ParseException(sprintf('The constant "%s" is not defined.', $const)); + throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber, $scalar, self::$parsedFilename); } if (self::$exceptionOnInvalidType) { - throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar)); + throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename); } return; @@ -686,10 +686,10 @@ private static function evaluateScalar($scalar, $flags, $references = array()) return constant($const); } - throw new ParseException(sprintf('The constant "%s" is not defined.', $const)); + throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber, $scalar, self::$parsedFilename); } if (self::$exceptionOnInvalidType) { - throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar)); + throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename); } return; @@ -781,7 +781,7 @@ private static function parseTag($value, &$i, $flags) // Built-in tags if ($tag && '!' === $tag[0]) { - throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag)); + throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber, $value, self::$parsedFilename); } if (Yaml::PARSE_CUSTOM_TAGS & $flags) { @@ -790,7 +790,7 @@ private static function parseTag($value, &$i, $flags) return $tag; } - throw new ParseException(sprintf('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!%s".', $tag)); + throw new ParseException(sprintf('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!%s".', $tag), self::$parsedLineNumber, $value, self::$parsedFilename); } /** @@ -805,11 +805,11 @@ public static function evaluateBinaryScalar($scalar) $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar)); if (0 !== (strlen($parsedBinaryData) % 4)) { - throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', strlen($parsedBinaryData))); + throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', strlen($parsedBinaryData)), self::$parsedLineNumber, $scalar, self::$parsedFilename); } if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) { - throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData)); + throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber, $scalar, self::$parsedFilename); } return base64_decode($parsedBinaryData, true); diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 49eae8f0cc63..be1c13cddbf9 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -26,6 +26,7 @@ class Parser const TAG_PATTERN = '(?P![\w!.\/:-]+)'; const BLOCK_SCALAR_HEADER_PATTERN = '(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?'; + private $filename; private $offset = 0; private $totalNumberOfLines; private $lines = array(); @@ -50,6 +51,35 @@ public function __construct() } } + /** + * Parses a YAML file into a PHP value. + * + * @param string $filename The path to the YAML file to be parsed + * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior + * + * @return mixed The YAML converted to a PHP value + * + * @throws ParseException If the file could not be read or the YAML is not valid + */ + public function parseFile($filename, $flags = 0) + { + if (!is_file($filename)) { + throw new ParseException(sprintf('File "%s" does not exist.', $filename)); + } + + if (!is_readable($filename)) { + throw new ParseException(sprintf('File "%s" cannot be read.', $filename)); + } + + $this->filename = $filename; + + try { + return $this->parse(file_get_contents($filename), $flags); + } finally { + $this->filename = null; + } + } + /** * Parses a YAML string to a PHP value. * @@ -93,7 +123,7 @@ public function parse($value, $flags = 0) } if (false === preg_match('//u', $value)) { - throw new ParseException('The YAML value does not appear to be valid UTF-8.'); + throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename); } $this->refs = array(); @@ -168,13 +198,13 @@ private function doParse($value, $flags) // tab? if ("\t" === $this->currentLine[0]) { - throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $isRef = $mergeNode = false; if (self::preg_match('#^\-((?P\s+)(?P.+))?$#u', rtrim($this->currentLine), $values)) { if ($context && 'mapping' == $context) { - throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $context = 'sequence'; @@ -218,11 +248,11 @@ private function doParse($value, $flags) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'"))) ) { if ($context && 'sequence' == $context) { - throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine); + throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine, $this->filename); } $context = 'mapping'; - Inline::initialize($flags, $this->getRealCurrentLineNb()); + Inline::initialize($flags, $this->getRealCurrentLineNb(), $this->filename); try { $i = 0; $evaluateKey = !(Yaml::PARSE_KEYS_AS_STRINGS & $flags); @@ -256,13 +286,13 @@ private function doParse($value, $flags) if (isset($values['value']) && 0 === strpos($values['value'], '*')) { $refName = substr(rtrim($values['value']), 1); if (!array_key_exists($refName, $this->refs)) { - throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $refValue = $this->refs[$refName]; if (!is_array($refValue)) { - throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $data += $refValue; // array union @@ -275,7 +305,7 @@ private function doParse($value, $flags) $parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags); if (!is_array($parsed)) { - throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } if (isset($parsed[0])) { @@ -284,7 +314,7 @@ private function doParse($value, $flags) // in the sequence override keys specified in later mapping nodes. foreach ($parsed as $parsedItem) { if (!is_array($parsedItem)) { - throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem); + throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem, $this->filename); } $data += $parsedItem; // array union @@ -350,7 +380,7 @@ private function doParse($value, $flags) } else { // multiple documents are not supported if ('---' === $this->currentLine) { - throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine); + throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename); } if (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1]) { @@ -412,7 +442,7 @@ private function doParse($value, $flags) } } - throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } while ($this->moveToNextLine()); @@ -515,7 +545,7 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem(); if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) { - throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } else { $newIndent = $indentation; @@ -594,7 +624,7 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) break; } else { - throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } @@ -654,7 +684,7 @@ private function parseValue($value, $flags, $context) } if (!array_key_exists($value, $this->refs)) { - throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine); + throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); } return $this->refs[$value]; @@ -704,7 +734,7 @@ private function parseValue($value, $flags, $context) $parsedValue = Inline::parse($value, $flags, $this->refs); if ('mapping' === $context && is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) { - throw new ParseException('A colon cannot be used in an unquoted mapping value.'); + throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename); } return $parsedValue; @@ -1044,13 +1074,13 @@ private function getLineTag($value, $flags, $nextLineCheck = true) // Built-in tags if ($tag && '!' === $tag[0]) { - throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag)); + throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), $this->getRealCurrentLineNb() + 1, $value, $this->filename); } if (Yaml::PARSE_CUSTOM_TAGS & $flags) { return $tag; } - throw new ParseException(sprintf('Tags support is not enabled. You must use the flag `Yaml::PARSE_CUSTOM_TAGS` to use "%s".', $matches['tag'])); + throw new ParseException(sprintf('Tags support is not enabled. You must use the flag `Yaml::PARSE_CUSTOM_TAGS` to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename); } } diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/not_readable.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/not_readable.yml new file mode 100644 index 000000000000..3216a89ebbc3 --- /dev/null +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/not_readable.yml @@ -0,0 +1,18 @@ +- escapedCharacters +- sfComments +- sfCompact +- sfTests +- sfObjects +- sfMergeKey +- sfQuotes +- YtsAnchorAlias +- YtsBasicTests +- YtsBlockMapping +- YtsDocumentSeparator +- YtsErrorTests +- YtsFlowCollections +- YtsFoldedScalars +- YtsNullsAndEmpties +- YtsSpecificationExamples +- YtsTypeTransfers +- unindentedCollections diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 2933ee67ceea..5fdf2957fb7a 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -18,6 +18,11 @@ class InlineTest extends TestCase { + protected function setUp() + { + Inline::initialize(0); + } + /** * @dataProvider getTestsForParse */ @@ -283,11 +288,16 @@ public function testParseUnquotedAsteriskFollowedByAComment() /** * @dataProvider getReservedIndicators - * @expectedException \Symfony\Component\Yaml\Exception\ParseException - * @expectedExceptionMessage cannot start a plain scalar; you need to quote the scalar. */ public function testParseUnquotedScalarStartingWithReservedIndicator($indicator) { + if (method_exists($this, 'expectExceptionMessage')) { + $this->expectException(ParseException::class); + $this->expectExceptionMessage(sprintf('cannot start a plain scalar; you need to quote the scalar (near "%sfoo ").', $indicator)); + } else { + $this->setExpectedException(ParseException::class, sprintf('cannot start a plain scalar; you need to quote the scalar (near "%sfoo ").', $indicator)); + } + Inline::parse(sprintf('{ foo: %sfoo }', $indicator)); } @@ -298,11 +308,16 @@ public function getReservedIndicators() /** * @dataProvider getScalarIndicators - * @expectedException \Symfony\Component\Yaml\Exception\ParseException - * @expectedExceptionMessage cannot start a plain scalar; you need to quote the scalar. */ public function testParseUnquotedScalarStartingWithScalarIndicator($indicator) { + if (method_exists($this, 'expectExceptionMessage')) { + $this->expectException(ParseException::class); + $this->expectExceptionMessage(sprintf('cannot start a plain scalar; you need to quote the scalar (near "%sfoo ").', $indicator)); + } else { + $this->setExpectedException(ParseException::class, sprintf('cannot start a plain scalar; you need to quote the scalar (near "%sfoo ").', $indicator)); + } + Inline::parse(sprintf('{ foo: %sfoo }', $indicator)); } diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 59e7b4986a30..553b762384c2 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -30,6 +30,8 @@ protected function setUp() protected function tearDown() { $this->parser = null; + + chmod(__DIR__.'/Fixtures/not_readable.yml', 0644); } /** @@ -1696,7 +1698,7 @@ public function testUnsupportedTagWithScalar() /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException - * @expectedExceptionMessage The built-in tag "!!foo" is not implemented. + * @expectedExceptionMessage The built-in tag "!!foo" is not implemented at line 1 (near "!!foo"). */ public function testExceptionWhenUsingUnsuportedBuiltInTags() { @@ -1903,6 +1905,43 @@ public function testPhpConstantTagMappingKeyWithKeysCastToStrings() $this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT | Yaml::PARSE_KEYS_AS_STRINGS)); } + + public function testFilenamesAreParsedAsStringsWithoutFlag() + { + $file = __DIR__.'/Fixtures/index.yml'; + + $this->assertSame($file, $this->parser->parse($file)); + } + + public function testParseFile() + { + $this->assertInternalType('array', $this->parser->parseFile(__DIR__.'/Fixtures/index.yml')); + } + + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessageRegExp #^File ".+/Fixtures/nonexistent.yml" does not exist\.$# + */ + public function testParsingNonExistentFilesThrowsException() + { + $this->parser->parseFile(__DIR__.'/Fixtures/nonexistent.yml'); + } + + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessageRegExp #^File ".+/Fixtures/not_readable.yml" cannot be read\.$# + */ + public function testParsingNotReadableFilesThrowsException() + { + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markTestSkipped('chmod is not supported on Windows'); + } + + $file = __DIR__.'/Fixtures/not_readable.yml'; + chmod($file, 0200); + + $this->parser->parseFile($file); + } } class B diff --git a/src/Symfony/Component/Yaml/Yaml.php b/src/Symfony/Component/Yaml/Yaml.php index 52a064f70b5f..24e3e95cba32 100644 --- a/src/Symfony/Component/Yaml/Yaml.php +++ b/src/Symfony/Component/Yaml/Yaml.php @@ -39,6 +39,29 @@ class Yaml */ const PARSE_KEYS_AS_STRINGS = 2048; + /** + * Parses a YAML file into a PHP value. + * + * Usage: + * + * $array = Yaml::parseFile('config.yml'); + * print_r($array); + * + * + * @param string $filename The path to the YAML file to be parsed + * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior + * + * @return mixed The YAML converted to a PHP value + * + * @throws ParseException If the file could not be read or the YAML is not valid + */ + public static function parseFile($filename, $flags = 0) + { + $yaml = new Parser(); + + return $yaml->parseFile($filename, $flags); + } + /** * Parses YAML into a PHP value. *