wiki.techinc.nl/includes/Settings/Source/Format/YamlFormat.php
Umherirrender 6dd8a2bb32 phan: Disable scalar_implicit_cast setting
Make phan stricter about scalar types by setting scalar_implicit_cast to
false (the default in mediawiki-phan-config)

Bug: T242536
Bug: T301991
Change-Id: Ia2fe30b17804186571722e728578121c8b75d455
2022-03-18 18:52:24 +00:00

120 lines
2.9 KiB
PHP

<?php
namespace MediaWiki\Settings\Source\Format;
use LogicException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
use UnexpectedValueException;
use Wikimedia\AtEase\AtEase;
class YamlFormat implements SettingsFormat {
public const PARSER_PHP_YAML = 'php-yaml';
public const PARSER_SYMFONY = 'symfony';
/** @var string[] */
private $useParsers;
/**
* @param string[] $useParsers which parsers to try in order.
*/
public function __construct( array $useParsers = [ self::PARSER_PHP_YAML, self::PARSER_SYMFONY ] ) {
$this->useParsers = $useParsers;
}
public function decode( string $data ): array {
foreach ( $this->useParsers as $parser ) {
if ( self::isParserAvailable( $parser ) ) {
return $this->parseWith( $parser, $data );
}
}
throw new LogicException( 'No parser available' );
}
/**
* Check whether a specific YAML parser is available.
*
* @param string $parser one of the PARSER_* constants.
* @return bool
*/
public static function isParserAvailable( string $parser ): bool {
switch ( $parser ) {
case self::PARSER_PHP_YAML:
return function_exists( 'yaml_parse' );
case self::PARSER_SYMFONY:
return true;
default:
throw new LogicException( 'Unknown parser: ' . $parser );
}
}
/**
* @param string $parser
* @param string $data
* @return array
*/
private function parseWith( string $parser, string $data ): array {
switch ( $parser ) {
case self::PARSER_PHP_YAML:
return $this->parseWithPhp( $data );
case self::PARSER_SYMFONY:
return $this->parseWithSymfony( $data );
default:
throw new LogicException( 'Unknown parser: ' . $parser );
}
}
private function parseWithPhp( string $data ): array {
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
$previousValue = ini_set( 'yaml.decode_php', false );
try {
$ndocs = 0;
$result = AtEase::quietCall(
'yaml_parse',
$data,
0,
$ndocs,
[
/**
* Crash if provided YAML has PHP constants in it.
* We do not want to support that.
*
* @return never
*/
'!php/const' => static function () {
throw new UnexpectedValueException(
'PHP constants are not supported'
);
},
]
);
if ( $result === false ) {
throw new UnexpectedValueException( 'Failed to parse YAML' );
}
return $result;
} finally {
ini_set( 'yaml.decode_php', $previousValue );
}
}
private function parseWithSymfony( string $data ): array {
try {
return Yaml::parse( $data, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE );
} catch ( ParseException $e ) {
throw new UnexpectedValueException(
'Failed to parse YAML ' . $e->getMessage()
);
}
}
public static function supportsFileExtension( string $ext ): bool {
$ext = strtolower( $ext );
return $ext === 'yml' || $ext === 'yaml';
}
public function __toString() {
return 'YAML';
}
}