cambios en el composer con mejores versiones

This commit is contained in:
German Correa 2021-08-11 10:38:08 -03:00
parent 4f03e3b727
commit 6efadee8a8
91 changed files with 3775 additions and 10285 deletions

View File

@ -35,7 +35,7 @@
"process-timeout" : 0
},
"scripts": {
"start": "php -S localhost:8080 -t public index.php",
"start": "php -S localhost:8080 -t public",
"test": "phpunit"
}

View File

@ -37,11 +37,13 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
private $vendorDir;
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
@ -57,10 +59,17 @@ class ClassLoader
private $missingClasses = array();
private $apcuPrefix;
private static $registeredLoaders = array();
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
@ -300,6 +309,17 @@ class ClassLoader
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
@ -308,13 +328,17 @@ class ClassLoader
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
@ -323,6 +347,8 @@ class ClassLoader
return true;
}
return null;
}
/**
@ -367,6 +393,16 @@ class ClassLoader
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup

View File

@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'File_Iterator' => $vendorDir . '/phpunit/php-file-iterator/src/Iterator.php',
'File_Iterator_Facade' => $vendorDir . '/phpunit/php-file-iterator/src/Facade.php',
'File_Iterator_Factory' => $vendorDir . '/phpunit/php-file-iterator/src/Factory.php',

View File

@ -7,7 +7,7 @@ $baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
);

View File

@ -13,19 +13,24 @@ class ComposerAutoloaderInit0dd15d1e9d08041097652a874300c62a
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit0dd15d1e9d08041097652a874300c62a', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit0dd15d1e9d08041097652a874300c62a', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit0dd15d1e9d08041097652a874300c62a::getInitializer($loader));
} else {

View File

@ -8,9 +8,9 @@ class ComposerStaticInit0dd15d1e9d08041097652a874300c62a
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'6124b4c8570aa390c21fafd04a26c69f' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
'6124b4c8570aa390c21fafd04a26c69f' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
);
public static $prefixLengthsPsr4 = array (
@ -200,6 +200,7 @@ class ComposerStaticInit0dd15d1e9d08041097652a874300c62a
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'File_Iterator' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Iterator.php',
'File_Iterator_Facade' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Facade.php',
'File_Iterator_Factory' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Factory.php',

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,15 @@
namespace Doctrine\Instantiator;
use ArrayIterator;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use ReflectionClass;
use ReflectionException;
use Serializable;
use function class_exists;
use function is_subclass_of;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
@ -94,7 +97,7 @@ final class Instantiator implements InstantiatorInterface
$serializedString = sprintf(
'%s:%d:"%s":0:{}',
self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER,
is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER,
strlen($className),
$className
);
@ -107,12 +110,10 @@ final class Instantiator implements InstantiatorInterface
}
/**
* @param string $className
*
* @throws InvalidArgumentException
* @throws ReflectionException
*/
private function getReflectionClass($className) : ReflectionClass
private function getReflectionClass(string $className) : ReflectionClass
{
if (! class_exists($className)) {
throw InvalidArgumentException::fromNonExistingClass($className);
@ -132,7 +133,7 @@ final class Instantiator implements InstantiatorInterface
*/
private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString) : void
{
set_error_handler(static function ($code, $message, $file, $line) use ($reflectionClass, & $error) : void {
set_error_handler(static function (int $code, string $message, string $file, int $line) use ($reflectionClass, &$error) : bool {
$error = UnexpectedValueException::fromUncleanUnSerialization(
$reflectionClass,
$message,
@ -140,6 +141,8 @@ final class Instantiator implements InstantiatorInterface
$file,
$line
);
return true;
});
try {
@ -193,6 +196,8 @@ final class Instantiator implements InstantiatorInterface
*/
private function isSafeToClone(ReflectionClass $reflection) : bool
{
return $reflection->isCloneable() && ! $reflection->hasMethod('__clone');
return $reflection->isCloneable()
&& ! $reflection->hasMethod('__clone')
&& ! $reflection->isSubclassOf(ArrayIterator::class);
}
}

View File

@ -1,3 +1,12 @@
### 1.25.2 (2019-11-13)
* Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable
* Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler and SamplingHandler
* Fixed BrowserConsoleHandler formatting when using multiple styles
* Fixed normalization of exception codes to be always integers even for PDOException which have them as numeric strings
* Fixed normalization of SoapFault objects containing non-strings as "detail"
* Fixed json encoding across all handlers to always attempt recovery of non-UTF-8 strings instead of failing the whole encoding
### 1.25.1 (2019-09-06)
* Fixed forward-compatible interfaces to be compatible with Monolog 1.x too.

View File

@ -11,6 +11,8 @@
namespace Monolog\Formatter;
use Monolog\Utils;
/**
* Class FluentdFormatter
*
@ -71,7 +73,7 @@ class FluentdFormatter implements FormatterInterface
$message['level_name'] = $record['level_name'];
}
return json_encode(array($tag, $record['datetime']->getTimestamp(), $message));
return Utils::jsonEncode(array($tag, $record['datetime']->getTimestamp(), $message));
}
public function formatBatch(array $records)

View File

@ -11,6 +11,7 @@
namespace Monolog\Formatter;
use Monolog\Logger;
use Monolog\Utils;
/**
* Formats incoming records into an HTML table
@ -133,9 +134,9 @@ class HtmlFormatter extends NormalizerFormatter
$data = $this->normalize($data);
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return Utils::jsonEncode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, true);
}
return str_replace('\\/', '/', json_encode($data));
return str_replace('\\/', '/', Utils::jsonEncode($data, null, true));
}
}

View File

@ -145,7 +145,7 @@ class JsonFormatter extends NormalizerFormatter
return 'Over 9 levels deep, aborting normalization';
}
if (is_array($data) || $data instanceof \Traversable) {
if (is_array($data)) {
$normalized = array();
$count = 1;
@ -186,7 +186,7 @@ class JsonFormatter extends NormalizerFormatter
$data = array(
'class' => Utils::getClass($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'code' => (int) $e->getCode(),
'file' => $e->getFile().':'.$e->getLine(),
);

View File

@ -163,7 +163,7 @@ class LineFormatter extends NormalizerFormatter
return $this->toJson($data, true);
}
return str_replace('\\/', '/', @json_encode($data));
return str_replace('\\/', '/', $this->toJson($data, true));
}
protected function replaceNewlines($str)

View File

@ -87,7 +87,7 @@ class MongoDBFormatter implements FormatterInterface
$formattedException = array(
'class' => Utils::getClass($exception),
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'code' => (int) $exception->getCode(),
'file' => $exception->getFile() . ':' . $exception->getLine(),
);

View File

@ -129,7 +129,7 @@ class NormalizerFormatter implements FormatterInterface
$data = array(
'class' => Utils::getClass($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'code' => (int) $e->getCode(),
'file' => $e->getFile().':'.$e->getLine(),
);
@ -142,8 +142,8 @@ class NormalizerFormatter implements FormatterInterface
$data['faultactor'] = $e->faultactor;
}
if (isset($e->detail)) {
$data['detail'] = $e->detail;
if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) {
$data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail);
}
}
@ -171,127 +171,6 @@ class NormalizerFormatter implements FormatterInterface
*/
protected function toJson($data, $ignoreErrors = false)
{
// suppress json_encode errors since it's twitchy with some inputs
if ($ignoreErrors) {
return @$this->jsonEncode($data);
}
$json = $this->jsonEncode($data);
if ($json === false) {
$json = $this->handleJsonError(json_last_error(), $data);
}
return $json;
}
/**
* @param mixed $data
* @return string JSON encoded data or null on failure
*/
private function jsonEncode($data)
{
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
return json_encode($data);
}
/**
* Handle a json_encode failure.
*
* If the failure is due to invalid string encoding, try to clean the
* input and encode again. If the second encoding attempt fails, the
* inital error is not encoding related or the input can't be cleaned then
* raise a descriptive exception.
*
* @param int $code return code of json_last_error function
* @param mixed $data data that was meant to be encoded
* @throws \RuntimeException if failure can't be corrected
* @return string JSON encoded data after error correction
*/
private function handleJsonError($code, $data)
{
if ($code !== JSON_ERROR_UTF8) {
$this->throwEncodeError($code, $data);
}
if (is_string($data)) {
$this->detectAndCleanUtf8($data);
} elseif (is_array($data)) {
array_walk_recursive($data, array($this, 'detectAndCleanUtf8'));
} else {
$this->throwEncodeError($code, $data);
}
$json = $this->jsonEncode($data);
if ($json === false) {
$this->throwEncodeError(json_last_error(), $data);
}
return $json;
}
/**
* Throws an exception according to a given code with a customized message
*
* @param int $code return code of json_last_error function
* @param mixed $data data that was meant to be encoded
* @throws \RuntimeException
*/
private function throwEncodeError($code, $data)
{
switch ($code) {
case JSON_ERROR_DEPTH:
$msg = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Unexpected control character found';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = 'Unknown error';
}
throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
}
/**
* Detect invalid UTF-8 string characters and convert to valid UTF-8.
*
* Valid UTF-8 input will be left unmodified, but strings containing
* invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed
* original encoding of ISO-8859-15. This conversion may result in
* incorrect output if the actual encoding was not ISO-8859-15, but it
* will be clean UTF-8 output and will not rely on expensive and fragile
* detection algorithms.
*
* Function converts the input in place in the passed variable so that it
* can be used as a callback for array_walk_recursive.
*
* @param mixed &$data Input to check and convert if needed
* @private
*/
public function detectAndCleanUtf8(&$data)
{
if (is_string($data) && !preg_match('//u', $data)) {
$data = preg_replace_callback(
'/[\x80-\xFF]+/',
function ($m) { return utf8_encode($m[0]); },
$data
);
$data = str_replace(
array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
$data
);
}
return Utils::jsonEncode($data, null, $ignoreErrors);
}
}

View File

@ -164,21 +164,22 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
private static function handleStyles($formatted)
{
$args = array(static::quote('font-weight: normal'));
$args = array();
$format = '%c' . $formatted;
preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
foreach (array_reverse($matches) as $match) {
$args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
$args[] = '"font-weight: normal"';
$args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
$pos = $match[0][1];
$format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
}
array_unshift($args, static::quote($format));
$args[] = static::quote('font-weight: normal');
$args[] = static::quote($format);
return $args;
return array_reverse($args);
}
private static function handleCustomStyles($style, $string)

View File

@ -13,6 +13,7 @@ namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\ResettableInterface;
use Monolog\Formatter\FormatterInterface;
/**
* Buffers all records until closing the handler and then pass them as batch.
@ -126,4 +127,22 @@ class BufferHandler extends AbstractHandler
$this->handler->reset();
}
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
$this->handler->setFormatter($formatter);
return $this;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
return $this->handler->getFormatter();
}
}

View File

@ -13,6 +13,7 @@ namespace Monolog\Handler;
use Monolog\Formatter\ChromePHPFormatter;
use Monolog\Logger;
use Monolog\Utils;
/**
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
@ -134,7 +135,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
}
$json = @json_encode(self::$json);
$json = Utils::jsonEncode(self::$json, null, true);
$data = base64_encode(utf8_encode($json));
if (strlen($data) > 3 * 1024) {
self::$overflowed = true;
@ -149,7 +150,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
'extra' => array(),
);
self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
$json = @json_encode(self::$json);
$json = Utils::jsonEncode(self::$json, null, true);
$data = base64_encode(utf8_encode($json));
}

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Utils;
/**
* Logs to Cube.
@ -119,9 +120,9 @@ class CubeHandler extends AbstractProcessingHandler
$data['data']['level'] = $record['level'];
if ($this->scheme === 'http') {
$this->writeHttp(json_encode($data));
$this->writeHttp(Utils::jsonEncode($data));
} else {
$this->writeUdp(json_encode($data));
$this->writeUdp(Utils::jsonEncode($data));
}
}

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\FormatterInterface;
/**
* Simple handler wrapper that filters records based on a list of levels
@ -45,7 +46,7 @@ class FilterHandler extends AbstractHandler
protected $bubble;
/**
* @param callable|HandlerInterface $handler Handler or factory callable($record, $this).
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler).
* @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
* @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
@ -104,21 +105,13 @@ class FilterHandler extends AbstractHandler
return false;
}
// The same logic as in FingersCrossedHandler
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
$this->handler->handle($record);
$this->getHandler($record)->handle($record);
return false === $this->bubble;
}
@ -135,6 +128,43 @@ class FilterHandler extends AbstractHandler
}
}
$this->handler->handleBatch($filtered);
$this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered);
}
/**
* Return the nested handler
*
* If the handler was provided as a factory callable, this will trigger the handler's instantiation.
*
* @return HandlerInterface
*/
public function getHandler(array $record = null)
{
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
return $this->handler;
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
$this->getHandler()->setFormatter($formatter);
return $this;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
return $this->getHandler()->getFormatter();
}
}

View File

@ -15,6 +15,7 @@ use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
use Monolog\Logger;
use Monolog\ResettableInterface;
use Monolog\Formatter\FormatterInterface;
/**
* Buffers all records until a certain level is reached
@ -39,7 +40,7 @@ class FingersCrossedHandler extends AbstractHandler
protected $passthruLevel;
/**
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler).
* @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
* @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
@ -88,15 +89,7 @@ class FingersCrossedHandler extends AbstractHandler
if ($this->stopBuffering) {
$this->buffering = false;
}
if (!$this->handler instanceof HandlerInterface) {
$record = end($this->buffer) ?: null;
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
$this->handler->handleBatch($this->buffer);
$this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
$this->buffer = array();
}
@ -120,7 +113,7 @@ class FingersCrossedHandler extends AbstractHandler
$this->activate();
}
} else {
$this->handler->handle($record);
$this->getHandler($record)->handle($record);
}
return false === $this->bubble;
@ -140,8 +133,8 @@ class FingersCrossedHandler extends AbstractHandler
parent::reset();
if ($this->handler instanceof ResettableInterface) {
$this->handler->reset();
if ($this->getHandler() instanceof ResettableInterface) {
$this->getHandler()->reset();
}
}
@ -167,11 +160,48 @@ class FingersCrossedHandler extends AbstractHandler
return $record['level'] >= $level;
});
if (count($this->buffer) > 0) {
$this->handler->handleBatch($this->buffer);
$this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
}
}
$this->buffer = array();
$this->buffering = true;
}
/**
* Return the nested handler
*
* If the handler was provided as a factory callable, this will trigger the handler's instantiation.
*
* @return HandlerInterface
*/
public function getHandler(array $record = null)
{
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
return $this->handler;
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
$this->getHandler()->setFormatter($formatter);
return $this;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
return $this->getHandler()->getFormatter();
}
}

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Utils;
use Monolog\Formatter\FlowdockFormatter;
use Monolog\Formatter\FormatterInterface;
@ -105,7 +106,7 @@ class FlowdockHandler extends SocketHandler
*/
private function buildContent($record)
{
return json_encode($record['formatted']['flowdock']);
return Utils::jsonEncode($record['formatted']['flowdock']);
}
/**

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Utils;
/**
* IFTTTHandler uses cURL to trigger IFTTT Maker actions
@ -53,7 +54,7 @@ class IFTTTHandler extends AbstractProcessingHandler
"value2" => $record["level_name"],
"value3" => $record["message"],
);
$postString = json_encode($postData);
$postString = Utils::jsonEncode($postData);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey);

View File

@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Utils;
use Monolog\Formatter\NormalizerFormatter;
/**
@ -190,7 +191,7 @@ class NewRelicHandler extends AbstractProcessingHandler
if (null === $value || is_scalar($value)) {
newrelic_add_custom_parameter($key, $value);
} else {
newrelic_add_custom_parameter($key, @json_encode($value));
newrelic_add_custom_parameter($key, Utils::jsonEncode($value, null, true));
}
}

View File

@ -14,6 +14,7 @@ namespace Monolog\Handler;
use Exception;
use Monolog\Formatter\LineFormatter;
use Monolog\Logger;
use Monolog\Utils;
use PhpConsole\Connector;
use PhpConsole\Handler;
use PhpConsole\Helper;
@ -188,7 +189,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler
$tags = $this->getRecordTags($record);
$message = $record['message'];
if ($record['context']) {
$message .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context'])));
$message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true);
}
$this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
}

View File

@ -11,6 +11,8 @@
namespace Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
/**
* Sampling handler
*
@ -38,7 +40,7 @@ class SamplingHandler extends AbstractHandler
protected $factor;
/**
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
* @param int $factor Sample factor
*/
public function __construct($handler, $factor)
@ -54,29 +56,58 @@ class SamplingHandler extends AbstractHandler
public function isHandling(array $record)
{
return $this->handler->isHandling($record);
return $this->getHandler($record)->isHandling($record);
}
public function handle(array $record)
{
if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
// The same logic as in FingersCrossedHandler
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
$this->handler->handle($record);
$this->getHandler($record)->handle($record);
}
return false === $this->bubble;
}
/**
* Return the nested handler
*
* If the handler was provided as a factory callable, this will trigger the handler's instantiation.
*
* @return HandlerInterface
*/
public function getHandler(array $record = null)
{
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
return $this->handler;
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
$this->getHandler()->setFormatter($formatter);
return $this;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
return $this->getHandler()->getFormatter();
}
}

9
vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php vendored Executable file → Normal file
View File

@ -12,6 +12,7 @@
namespace Monolog\Handler\Slack;
use Monolog\Logger;
use Monolog\Utils;
use Monolog\Formatter\NormalizerFormatter;
use Monolog\Formatter\FormatterInterface;
@ -207,13 +208,17 @@ class SlackRecord
{
$normalized = $this->normalizerFormatter->format($fields);
$prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128;
$flags = 0;
if (PHP_VERSION_ID >= 50400) {
$flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
}
$hasSecondDimension = count(array_filter($normalized, 'is_array'));
$hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric'));
return $hasSecondDimension || $hasNonNumericKeys
? json_encode($normalized, $prettyPrintFlag)
: json_encode($normalized);
? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags)
: Utils::jsonEncode($normalized, $flags);
}
/**

View File

@ -13,6 +13,7 @@ namespace Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
use Monolog\Logger;
use Monolog\Utils;
use Monolog\Handler\Slack\SlackRecord;
/**
@ -118,7 +119,7 @@ class SlackHandler extends SocketHandler
$dataArray['token'] = $this->token;
if (!empty($dataArray['attachments'])) {
$dataArray['attachments'] = json_encode($dataArray['attachments']);
$dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']);
}
return $dataArray;

View File

@ -13,6 +13,7 @@ namespace Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
use Monolog\Logger;
use Monolog\Utils;
use Monolog\Handler\Slack\SlackRecord;
/**
@ -83,7 +84,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler
protected function write(array $record)
{
$postData = $this->slackRecord->getSlackData($record);
$postString = json_encode($postData);
$postString = Utils::jsonEncode($postData);
$ch = curl_init();
$options = array(

View File

@ -22,4 +22,138 @@ class Utils
return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
}
/**
* Return the JSON representation of a value
*
* @param mixed $data
* @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
* @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null
* @throws \RuntimeException if encoding fails and errors are not ignored
* @return string
*/
public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = false)
{
if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
$encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
}
if ($ignoreErrors) {
$json = @json_encode($data, $encodeFlags);
if (false === $json) {
return 'null';
}
return $json;
}
$json = json_encode($data, $encodeFlags);
if (false === $json) {
$json = self::handleJsonError(json_last_error(), $data);
}
return $json;
}
/**
* Handle a json_encode failure.
*
* If the failure is due to invalid string encoding, try to clean the
* input and encode again. If the second encoding attempt fails, the
* inital error is not encoding related or the input can't be cleaned then
* raise a descriptive exception.
*
* @param int $code return code of json_last_error function
* @param mixed $data data that was meant to be encoded
* @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
* @throws \RuntimeException if failure can't be corrected
* @return string JSON encoded data after error correction
*/
public static function handleJsonError($code, $data, $encodeFlags = null)
{
if ($code !== JSON_ERROR_UTF8) {
self::throwEncodeError($code, $data);
}
if (is_string($data)) {
self::detectAndCleanUtf8($data);
} elseif (is_array($data)) {
array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8'));
} else {
self::throwEncodeError($code, $data);
}
if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
$encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
}
$json = json_encode($data, $encodeFlags);
if ($json === false) {
self::throwEncodeError(json_last_error(), $data);
}
return $json;
}
/**
* Throws an exception according to a given code with a customized message
*
* @param int $code return code of json_last_error function
* @param mixed $data data that was meant to be encoded
* @throws \RuntimeException
*/
private static function throwEncodeError($code, $data)
{
switch ($code) {
case JSON_ERROR_DEPTH:
$msg = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Unexpected control character found';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = 'Unknown error';
}
throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
}
/**
* Detect invalid UTF-8 string characters and convert to valid UTF-8.
*
* Valid UTF-8 input will be left unmodified, but strings containing
* invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed
* original encoding of ISO-8859-15. This conversion may result in
* incorrect output if the actual encoding was not ISO-8859-15, but it
* will be clean UTF-8 output and will not rely on expensive and fragile
* detection algorithms.
*
* Function converts the input in place in the passed variable so that it
* can be used as a callback for array_walk_recursive.
*
* @param mixed &$data Input to check and convert if needed
* @private
*/
public static function detectAndCleanUtf8(&$data)
{
if (is_string($data) && !preg_match('//u', $data)) {
$data = preg_replace_callback(
'/[\x80-\xFF]+/',
function ($m) { return utf8_encode($m[0]); },
$data
);
$data = str_replace(
array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
$data
);
}
}
}

View File

@ -6,11 +6,11 @@ Build status: [![Build Status](https://travis-ci.org/PHPMailer/PHPMailer.svg)](h
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/badges/quality-score.png?s=3758e21d279becdf847a557a56a3ed16dfec9d5d)](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/)
[![Code Coverage](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/badges/coverage.png?s=3fe6ca5fe8cd2cdf96285756e42932f7ca256962)](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/)
[![Latest Stable Version](https://poser.pugx.org/phpmailer/phpmailer/v/stable.svg)](https://packagist.org/packages/phpmailer/phpmailer) [![Total Downloads](https://poser.pugx.org/phpmailer/phpmailer/downloads)](https://packagist.org/packages/phpmailer/phpmailer) [![Latest Unstable Version](https://poser.pugx.org/phpmailer/phpmailer/v/unstable.svg)](https://packagist.org/packages/phpmailer/phpmailer) [![License](https://poser.pugx.org/phpmailer/phpmailer/license.svg)](https://packagist.org/packages/phpmailer/phpmailer)
[![Latest Stable Version](https://poser.pugx.org/phpmailer/phpmailer/v/stable.svg)](https://packagist.org/packages/phpmailer/phpmailer) [![Total Downloads](https://poser.pugx.org/phpmailer/phpmailer/downloads)](https://packagist.org/packages/phpmailer/phpmailer) [![Latest Unstable Version](https://poser.pugx.org/phpmailer/phpmailer/v/unstable.svg)](https://packagist.org/packages/phpmailer/phpmailer) [![License](https://poser.pugx.org/phpmailer/phpmailer/license.svg)](https://packagist.org/packages/phpmailer/phpmailer) [![API Docs](https://github.com/phpmailer/phpmailer/workflows/Docs/badge.svg)](http://phpmailer.github.io/PHPMailer/)
## Class Features
- Probably the world's most popular code for sending email from PHP!
- Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla!, and many more
- Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more
- Integrated SMTP support - send without a local mail server
- Send emails with multiple To, CC, BCC and Reply-to addresses
- Multipart/alternative emails for mail clients that do not read HTML email

View File

@ -1 +1 @@
6.1.1
6.1.3

View File

@ -26,12 +26,8 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.2",
"phpdocumentor/phpdocumentor": "2.*",
"phpunit/phpunit": "^4.8 || ^5.7",
"zendframework/zend-serializer": "2.7.*",
"doctrine/annotations": "1.2.*",
"zendframework/zend-eventmanager": "3.0.*",
"zendframework/zend-i18n": "2.7.3"
"doctrine/annotations": "^1.2"
},
"suggest": {
"psr/log": "For optional PSR-3 debug logging",

View File

@ -123,7 +123,7 @@ class OAuth
public function getOauth64()
{
// Get a new token if it's not available or has expired
if (null === $this->oauthToken or $this->oauthToken->hasExpired()) {
if (null === $this->oauthToken || $this->oauthToken->hasExpired()) {
$this->oauthToken = $this->getToken();
}

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,7 @@ class POP3
*
* @var string
*/
const VERSION = '6.1.1';
const VERSION = '6.1.3';
/**
* Default POP3 port number.
@ -364,7 +364,7 @@ class POP3
*/
protected function checkResponse($string)
{
if (substr($string, 0, 3) !== '+OK') {
if (strpos($string, '+OK') !== 0) {
$this->setError("Server reported an error: $string");
return false;

View File

@ -34,7 +34,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.1.1';
const VERSION = '6.1.3';
/**
* SMTP line break constant.
@ -51,12 +51,25 @@ class SMTP
const DEFAULT_PORT = 25;
/**
* The maximum line length allowed by RFC 2822 section 2.1.1.
* The maximum line length allowed by RFC 5321 section 4.5.3.1.6,
* *excluding* a trailing CRLF break.
*
* @see https://tools.ietf.org/html/rfc5321#section-4.5.3.1.6
*
* @var int
*/
const MAX_LINE_LENGTH = 998;
/**
* The maximum line length allowed for replies in RFC 5321 section 4.5.3.1.5,
* *including* a trailing CRLF line break.
*
* @see https://tools.ietf.org/html/rfc5321#section-4.5.3.1.5
*
* @var int
*/
const MAX_REPLY_LENGTH = 512;
/**
* Debug level for no output.
*
@ -207,7 +220,7 @@ class SMTP
*
* @var string|null
*/
protected $helo_rply = null;
protected $helo_rply;
/**
* The set of SMTP extensions sent in reply to EHLO command.
@ -219,7 +232,7 @@ class SMTP
*
* @var array|null
*/
protected $server_caps = null;
protected $server_caps;
/**
* The most recent reply received from the server.
@ -249,7 +262,7 @@ class SMTP
return;
}
//Avoid clash with built-in function names
if (!in_array($this->Debugoutput, ['error_log', 'html', 'echo']) and is_callable($this->Debugoutput)) {
if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) {
call_user_func($this->Debugoutput, $str, $level);
return;
@ -270,12 +283,12 @@ class SMTP
case 'echo':
default:
//Normalize line breaks
$str = preg_replace('/\r\n|\r/ms', "\n", $str);
$str = preg_replace('/\r\n|\r/m', "\n", $str);
echo gmdate('Y-m-d H:i:s'),
"\t",
//Trim trailing space
trim(
//Indent for readability, except for trailing break
//Indent for readability, except for trailing break
str_replace(
"\n",
"\n \t ",
@ -358,7 +371,7 @@ class SMTP
'Failed to connect to server',
'',
(string) $errno,
(string) $errstr
$errstr
);
$this->edebug(
'SMTP ERROR: ' . $this->error['error']
@ -371,10 +384,10 @@ class SMTP
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
if (substr(PHP_OS, 0, 3) != 'WIN') {
$max = ini_get('max_execution_time');
if (strpos(PHP_OS, 'WIN') !== 0) {
$max = (int) ini_get('max_execution_time');
// Don't bother if unlimited
if (0 != $max and $timeout > $max) {
if (0 !== $max && $timeout > $max) {
@set_time_limit($timeout);
}
stream_set_timeout($this->smtp_conn, $timeout, 0);
@ -454,14 +467,14 @@ class SMTP
return false;
}
$this->edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNSPECIFIED'), self::DEBUG_LOWLEVEL);
$this->edebug('Auth method requested: ' . ($authtype ?: 'UNSPECIFIED'), self::DEBUG_LOWLEVEL);
$this->edebug(
'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
self::DEBUG_LOWLEVEL
);
//If we have requested a specific auth type, check the server supports it before trying others
if (null !== $authtype and !in_array($authtype, $this->server_caps['AUTH'])) {
if (null !== $authtype && !in_array($authtype, $this->server_caps['AUTH'], true)) {
$this->edebug('Requested auth method not available: ' . $authtype, self::DEBUG_LOWLEVEL);
$authtype = null;
}
@ -470,7 +483,7 @@ class SMTP
//If no auth mechanism is specified, attempt to use these, in this order
//Try CRAM-MD5 first as it's more secure than the others
foreach (['CRAM-MD5', 'LOGIN', 'PLAIN', 'XOAUTH2'] as $method) {
if (in_array($method, $this->server_caps['AUTH'])) {
if (in_array($method, $this->server_caps['AUTH'], true)) {
$authtype = $method;
break;
}
@ -480,10 +493,10 @@ class SMTP
return false;
}
self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL);
$this->edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL);
}
if (!in_array($authtype, $this->server_caps['AUTH'])) {
if (!in_array($authtype, $this->server_caps['AUTH'], true)) {
$this->setError("The requested authentication method \"$authtype\" is not supported by the server");
return false;
@ -673,13 +686,13 @@ class SMTP
$field = substr($lines[0], 0, strpos($lines[0], ':'));
$in_headers = false;
if (!empty($field) and strpos($field, ' ') === false) {
if (!empty($field) && strpos($field, ' ') === false) {
$in_headers = true;
}
foreach ($lines as $line) {
$lines_out = [];
if ($in_headers and $line == '') {
if ($in_headers && $line === '') {
$in_headers = false;
}
//Break this line up into several smaller lines if it's too long
@ -710,7 +723,7 @@ class SMTP
//Send the lines to the server
foreach ($lines_out as $line_out) {
//RFC2821 section 4.5.2
if (!empty($line_out) and $line_out[0] == '.') {
if (!empty($line_out) && $line_out[0] === '.') {
$line_out = '.' . $line_out;
}
$this->client_send($line_out . static::LE, 'DATA');
@ -720,7 +733,7 @@ class SMTP
//Message data has been sent, complete the command
//Increase timelimit for end of DATA command
$savetimelimit = $this->Timelimit;
$this->Timelimit = $this->Timelimit * 2;
$this->Timelimit *= 2;
$result = $this->sendCommand('DATA END', '.', 250);
$this->recordLastTransactionID();
//Restore timelimit
@ -848,7 +861,7 @@ class SMTP
{
$noerror = $this->sendCommand('QUIT', 'QUIT', 221);
$err = $this->error; //Save any error
if ($noerror or $close_on_error) {
if ($noerror || $close_on_error) {
$this->close();
$this->error = $err; //Restore any error from the quit command
}
@ -925,7 +938,7 @@ class SMTP
return false;
}
//Reject line breaks in all commands
if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) {
if ((strpos($commandstring, "\n") !== false) || (strpos($commandstring, "\r") !== false)) {
$this->setError("Command '$command' contained line breaks");
return false;
@ -935,8 +948,8 @@ class SMTP
$this->last_reply = $this->get_lines();
// Fetch SMTP code and possible error code explanation
$matches = [];
if (preg_match('/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]{1,2}) )?/', $this->last_reply, $matches)) {
$code = $matches[1];
if (preg_match('/^([\d]{3})[ -](?:([\d]\\.[\d]\\.[\d]{1,2}) )?/', $this->last_reply, $matches)) {
$code = (int) $matches[1];
$code_ex = (count($matches) > 2 ? $matches[2] : null);
// Cut off error code from each response line
$detail = preg_replace(
@ -947,14 +960,14 @@ class SMTP
);
} else {
// Fall back to simple parsing if regex fails
$code = substr($this->last_reply, 0, 3);
$code = (int) substr($this->last_reply, 0, 3);
$code_ex = null;
$detail = substr($this->last_reply, 4);
}
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
if (!in_array($code, (array) $expect)) {
if (!in_array($code, (array) $expect, true)) {
$this->setError(
"$command command failed",
$detail,
@ -1045,9 +1058,9 @@ class SMTP
{
//If SMTP transcripts are left enabled, or debug output is posted online
//it can leak credentials, so hide credentials in all but lowest level
if (self::DEBUG_LOWLEVEL > $this->do_debug and
if (self::DEBUG_LOWLEVEL > $this->do_debug &&
in_array($command, ['User & Password', 'Username', 'Password'], true)) {
$this->edebug('CLIENT -> SERVER: <credentials hidden>', self::DEBUG_CLIENT);
$this->edebug('CLIENT -> SERVER: [credentials hidden]', self::DEBUG_CLIENT);
} else {
$this->edebug('CLIENT -> SERVER: ' . $data, self::DEBUG_CLIENT);
}
@ -1093,7 +1106,7 @@ class SMTP
*
* @param string $name Name of SMTP extension or 'HELO'|'EHLO'
*
* @return mixed
* @return string|bool|null
*/
public function getServerExt($name)
{
@ -1104,10 +1117,10 @@ class SMTP
}
if (!array_key_exists($name, $this->server_caps)) {
if ('HELO' == $name) {
if ('HELO' === $name) {
return $this->server_caps['EHLO'];
}
if ('EHLO' == $name || array_key_exists('EHLO', $this->server_caps)) {
if ('EHLO' === $name || array_key_exists('EHLO', $this->server_caps)) {
return false;
}
$this->setError('HELO handshake was used; No information about server extensions available');
@ -1151,7 +1164,7 @@ class SMTP
}
$selR = [$this->smtp_conn];
$selW = null;
while (is_resource($this->smtp_conn) and !feof($this->smtp_conn)) {
while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
//Must pass vars in here as params are by reference
if (!stream_select($selR, $selW, $selW, $this->Timelimit)) {
$this->edebug(
@ -1161,13 +1174,13 @@ class SMTP
break;
}
//Deliberate noise suppression - errors are handled afterwards
$str = @fgets($this->smtp_conn, 515);
$str = @fgets($this->smtp_conn, self::MAX_REPLY_LENGTH);
$this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL);
$data .= $str;
// If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
// or 4th character is a space, we are done reading, break the loop,
// string array access is a micro-optimisation over strlen
if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) {
// or 4th character is a space or a line break char, we are done reading, break the loop.
// String array access is a significant micro-optimisation over strlen
if (!isset($str[3]) || $str[3] === ' ' || $str[3] === "\r" || $str[3] === "\n") {
break;
}
// Timed-out? Log and break
@ -1180,7 +1193,7 @@ class SMTP
break;
}
// Now check if reads took too long
if ($endtime and time() > $endtime) {
if ($endtime && time() > $endtime) {
$this->edebug(
'SMTP -> get_lines(): timelimit reached (' .
$this->Timelimit . ' sec)',

View File

@ -118,6 +118,8 @@ interface LoggerInterface
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array());
}

View File

@ -135,6 +135,8 @@ trait LoggerTrait
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
abstract public function log($level, $message, array $context = array());
}

View File

@ -20,6 +20,8 @@ class NullLogger extends AbstractLogger
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array())
{

View File

@ -4,6 +4,7 @@ namespace Psr\Log\Test;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use PHPUnit\Framework\TestCase;
/**
* Provides a base test class for ensuring compliance with the LoggerInterface.
@ -11,7 +12,7 @@ use Psr\Log\LogLevel;
* Implementors can extend the class and implement abstract methods to run this
* as part of their test suite.
*/
abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
abstract class LoggerInterfaceTest extends TestCase
{
/**
* @return LoggerInterface
@ -140,5 +141,6 @@ class DummyTest
{
public function __toString()
{
return 'DummyTest';
}
}

View File

@ -142,5 +142,6 @@ class TestLogger extends AbstractLogger
public function reset()
{
$this->records = [];
$this->recordsByLevel = [];
}
}

View File

@ -38,6 +38,12 @@ class Foo
if ($this->logger) {
$this->logger->info('Doing work');
}
try {
$this->doSomethingElse();
} catch (Exception $exception) {
$this->logger->error('Oh no!', array('exception' => $exception));
}
// do something useful
}

View File

@ -20,7 +20,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
}
}

View File

@ -1,3 +0,0 @@
vendor/
composer.lock
phpunit.xml

View File

@ -1,6 +1,13 @@
CHANGELOG
=========
4.4.0
-----
* Added support for parsing the inline notation spanning multiple lines.
* Added support to dump `null` as `~` by using the `Yaml::DUMP_NULL_AS_TILDE` flag.
* deprecated accepting STDIN implicitly when using the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit.
4.3.0
-----

View File

@ -54,7 +54,7 @@ class LintCommand extends Command
{
$this
->setDescription('Lints a file and outputs encountered errors')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file or a directory or STDIN')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
->addOption('parse-tags', null, InputOption::VALUE_NONE, 'Parse custom tags')
->setHelp(<<<EOF
@ -63,7 +63,7 @@ the first encountered syntax error.
You can validates YAML contents passed from STDIN:
<info>cat filename | php %command.full_name%</info>
<info>cat filename | php %command.full_name% -</info>
You can also validate the syntax of a file:
@ -87,12 +87,19 @@ EOF
$this->displayCorrectFiles = $output->isVerbose();
$flags = $input->getOption('parse-tags') ? Yaml::PARSE_CUSTOM_TAGS : 0;
if (0 === \count($filenames)) {
if (!$stdin = $this->getStdin()) {
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
if (['-'] === $filenames) {
return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
}
// @deprecated to be removed in 5.0
if (!$filenames) {
if (0 === ftell(STDIN)) {
@trigger_error('Piping content from STDIN to the "lint:yaml" command without passing the dash symbol "-" as argument is deprecated since Symfony 4.4.', E_USER_DEPRECATED);
return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
}
return $this->display($io, [$this->validate($stdin, $flags)]);
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
$filesInfo = [];
@ -109,7 +116,7 @@ EOF
return $this->display($io, $filesInfo);
}
private function validate($content, $flags, $file = null)
private function validate(string $content, int $flags, string $file = null)
{
$prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
if (E_USER_DEPRECATED === $level) {
@ -130,7 +137,7 @@ EOF
return ['file' => $file, 'valid' => true];
}
private function display(SymfonyStyle $io, array $files)
private function display(SymfonyStyle $io, array $files): int
{
switch ($this->format) {
case 'txt':
@ -142,10 +149,11 @@ EOF
}
}
private function displayTxt(SymfonyStyle $io, array $filesInfo)
private function displayTxt(SymfonyStyle $io, array $filesInfo): int
{
$countFiles = \count($filesInfo);
$erroredFiles = 0;
$suggestTagOption = false;
foreach ($filesInfo as $info) {
if ($info['valid'] && $this->displayCorrectFiles) {
@ -154,19 +162,23 @@ EOF
++$erroredFiles;
$io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
$io->text(sprintf('<error> >> %s</error>', $info['message']));
if (false !== strpos($info['message'], 'PARSE_CUSTOM_TAGS')) {
$suggestTagOption = true;
}
}
}
if (0 === $erroredFiles) {
$io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
} else {
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles));
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.%s', $countFiles - $erroredFiles, $erroredFiles, $suggestTagOption ? ' Use the --parse-tags option if you want parse custom tags.' : ''));
}
return min($erroredFiles, 1);
}
private function displayJson(SymfonyStyle $io, array $filesInfo)
private function displayJson(SymfonyStyle $io, array $filesInfo): int
{
$errors = 0;
@ -175,6 +187,10 @@ EOF
if (!$v['valid']) {
++$errors;
}
if (isset($v['message']) && false !== strpos($v['message'], 'PARSE_CUSTOM_TAGS')) {
$v['message'] .= ' Use the --parse-tags option if you want parse custom tags.';
}
});
$io->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
@ -182,7 +198,7 @@ EOF
return min($errors, 1);
}
private function getFiles($fileOrDirectory)
private function getFiles(string $fileOrDirectory): iterable
{
if (is_file($fileOrDirectory)) {
yield new \SplFileInfo($fileOrDirectory);
@ -199,24 +215,7 @@ EOF
}
}
/**
* @return string|null
*/
private function getStdin()
{
if (0 !== ftell(STDIN)) {
return null;
}
$inputs = '';
while (!feof(STDIN)) {
$inputs .= fread(STDIN, 1024);
}
return $inputs;
}
private function getParser()
private function getParser(): Parser
{
if (!$this->parser) {
$this->parser = new Parser();
@ -225,7 +224,7 @@ EOF
return $this->parser;
}
private function getDirectoryIterator($directory)
private function getDirectoryIterator(string $directory): iterable
{
$default = function ($directory) {
return new \RecursiveIteratorIterator(
@ -241,7 +240,7 @@ EOF
return $default($directory);
}
private function isReadable($fileOrDirectory)
private function isReadable(string $fileOrDirectory): bool
{
$default = function ($fileOrDirectory) {
return is_readable($fileOrDirectory);

View File

@ -30,7 +30,7 @@ class ParseException extends RuntimeException
* @param string|null $parsedFile The file name where the error occurred
* @param \Exception|null $previous The previous exception
*/
public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Exception $previous = null)
public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;

View File

@ -34,12 +34,7 @@ class Inline
private static $objectForMap = false;
private static $constantSupport = false;
/**
* @param int $flags
* @param int|null $parsedLineNumber
* @param string|null $parsedFilename
*/
public static function initialize($flags, $parsedLineNumber = null, $parsedFilename = null)
public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null)
{
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
@ -94,15 +89,15 @@ class Inline
$result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
}
if (null !== $tag && '' !== $tag) {
return new TaggedValue($tag, $result);
}
// 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)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
if (null !== $tag && '' !== $tag) {
return new TaggedValue($tag, $result);
}
return $result;
} finally {
if (isset($mbEncoding)) {
@ -129,7 +124,7 @@ class Inline
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
}
return 'null';
return self::dumpNull($flags);
case $value instanceof \DateTimeInterface:
return $value->format('c');
case \is_object($value):
@ -155,11 +150,11 @@ class Inline
throw new DumpException('Object support when dumping a YAML file has been disabled.');
}
return 'null';
return self::dumpNull($flags);
case \is_array($value):
return self::dumpArray($value, $flags);
case null === $value:
return 'null';
return self::dumpNull($flags);
case true === $value:
return 'true';
case false === $value:
@ -256,6 +251,15 @@ class Inline
return sprintf('{ %s }', implode(', ', $output));
}
private static function dumpNull(int $flags): string
{
if (Yaml::DUMP_NULL_AS_TILDE & $flags) {
return '~';
}
return 'null';
}
/**
* Parses a YAML scalar.
*
@ -270,7 +274,7 @@ class Inline
$output = self::parseQuotedScalar($scalar, $i);
if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
$tmp = ltrim(substr($scalar, $i), " \n");
if ('' === $tmp) {
throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
@ -415,6 +419,7 @@ class Inline
switch ($mapping[$i]) {
case ' ':
case ',':
case "\n":
++$i;
continue 2;
case '}':
@ -446,7 +451,7 @@ class Inline
}
}
if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}'], true))) {
if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], true))) {
throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
}
@ -455,7 +460,7 @@ class Inline
}
while ($i < $len) {
if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) {
++$i;
continue;
@ -504,7 +509,7 @@ class Inline
}
break;
default:
$value = self::parseScalar($mapping, $flags, [',', '}'], $i, null === $tag, $references);
$value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.

View File

@ -85,7 +85,6 @@ class Parser
$this->refs = [];
$mbEncoding = null;
$data = null;
if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
@ -108,14 +107,6 @@ class Parser
return $data;
}
/**
* @internal
*/
public function getLastLineNumberBeforeDeprecation(): int
{
return $this->getRealCurrentLineNb();
}
private function doParse(string $value, int $flags)
{
$this->currentLineNb = -1;
@ -353,6 +344,61 @@ class Parser
$this->refs[$isRef] = $data[$key];
array_pop($this->refsBeingParsed);
}
} elseif ('"' === $this->currentLine[0] || "'" === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
try {
return Inline::parse($this->parseQuotedString($this->currentLine), $flags, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
} elseif ('{' === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
try {
$parsedMapping = Inline::parse($this->lexInlineMapping($this->currentLine), $flags, $this->refs);
while ($this->moveToNextLine()) {
if (!$this->isCurrentLineEmpty()) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}
return $parsedMapping;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
} elseif ('[' === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
try {
$parsedSequence = Inline::parse($this->lexInlineSequence($this->currentLine), $flags, $this->refs);
while ($this->moveToNextLine()) {
if (!$this->isCurrentLineEmpty()) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}
return $parsedSequence;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
} else {
// multiple documents are not supported
if ('---' === $this->currentLine) {
@ -678,6 +724,12 @@ class Parser
}
try {
if ('' !== $value && '{' === $value[0]) {
return Inline::parse($this->lexInlineMapping($value), $flags, $this->refs);
} elseif ('' !== $value && '[' === $value[0]) {
return Inline::parse($this->lexInlineSequence($value), $flags, $this->refs);
}
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
// do not take following lines into account when the current line is a quoted single line value
@ -1072,4 +1124,122 @@ class Parser
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);
}
private function parseQuotedString(string $yaml): ?string
{
if ('' === $yaml || ('"' !== $yaml[0] && "'" !== $yaml[0])) {
throw new \InvalidArgumentException(sprintf('"%s" is not a quoted string.', $yaml));
}
$lines = [$yaml];
while ($this->moveToNextLine()) {
$lines[] = $this->currentLine;
if (!$this->isCurrentLineEmpty() && $yaml[0] === $this->currentLine[-1]) {
break;
}
}
$value = '';
for ($i = 0, $linesCount = \count($lines), $previousLineWasNewline = false, $previousLineWasTerminatedWithBackslash = false; $i < $linesCount; ++$i) {
if ('' === trim($lines[$i])) {
$value .= "\n";
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
$value .= ' ';
}
if ('' !== trim($lines[$i]) && '\\' === substr($lines[$i], -1)) {
$value .= ltrim(substr($lines[$i], 0, -1));
} elseif ('' !== trim($lines[$i])) {
$value .= trim($lines[$i]);
}
if ('' === trim($lines[$i])) {
$previousLineWasNewline = true;
$previousLineWasTerminatedWithBackslash = false;
} elseif ('\\' === substr($lines[$i], -1)) {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = true;
} else {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = false;
}
}
return $value;
for ($i = 1; isset($yaml[$i]) && $quotation !== $yaml[$i]; ++$i) {
}
// quoted single line string
if (isset($yaml[$i]) && $quotation === $yaml[$i]) {
return $yaml;
}
$lines = [$yaml];
while ($this->moveToNextLine()) {
for ($i = 1; isset($this->currentLine[$i]) && $quotation !== $this->currentLine[$i]; ++$i) {
}
$lines[] = trim($this->currentLine);
if (isset($this->currentLine[$i]) && $quotation === $this->currentLine[$i]) {
break;
}
}
}
private function lexInlineMapping(string $yaml): string
{
if ('' === $yaml || '{' !== $yaml[0]) {
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
}
for ($i = 1; isset($yaml[$i]) && '}' !== $yaml[$i]; ++$i) {
}
if (isset($yaml[$i]) && '}' === $yaml[$i]) {
return $yaml;
}
$lines = [$yaml];
while ($this->moveToNextLine()) {
$lines[] = $this->currentLine;
}
return implode("\n", $lines);
}
private function lexInlineSequence(string $yaml): string
{
if ('' === $yaml || '[' !== $yaml[0]) {
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
}
for ($i = 1; isset($yaml[$i]) && ']' !== $yaml[$i]; ++$i) {
}
if (isset($yaml[$i]) && ']' === $yaml[$i]) {
return $yaml;
}
$value = $yaml;
while ($this->moveToNextLine()) {
for ($i = 1; isset($this->currentLine[$i]) && ']' !== $this->currentLine[$i]; ++$i) {
}
$value .= trim($this->currentLine);
if (isset($this->currentLine[$i]) && ']' === $this->currentLine[$i]) {
break;
}
}
return $value;
}
}

View File

@ -1,149 +0,0 @@
<?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\Yaml\Tests\Command;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Yaml\Command\LintCommand;
/**
* Tests the YamlLintCommand.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class LintCommandTest extends TestCase
{
private $files;
public function testLintCorrectFile()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('foo: bar');
$ret = $tester->execute(['filename' => $filename], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]);
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
$this->assertRegExp('/^\/\/ OK in /', trim($tester->getDisplay()));
}
public function testLintCorrectFiles()
{
$tester = $this->createCommandTester();
$filename1 = $this->createFile('foo: bar');
$filename2 = $this->createFile('bar: baz');
$ret = $tester->execute(['filename' => [$filename1, $filename2]], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]);
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
$this->assertRegExp('/^\/\/ OK in /', trim($tester->getDisplay()));
}
public function testLintIncorrectFile()
{
$incorrectContent = '
foo:
bar';
$tester = $this->createCommandTester();
$filename = $this->createFile($incorrectContent);
$ret = $tester->execute(['filename' => $filename], ['decorated' => false]);
$this->assertEquals(1, $ret, 'Returns 1 in case of error');
$this->assertStringContainsString('Unable to parse at line 3 (near "bar").', trim($tester->getDisplay()));
}
public function testConstantAsKey()
{
$yaml = <<<YAML
!php/const 'Symfony\Component\Yaml\Tests\Command\Foo::TEST': bar
YAML;
$ret = $this->createCommandTester()->execute(['filename' => $this->createFile($yaml)], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]);
$this->assertSame(0, $ret, 'lint:yaml exits with code 0 in case of success');
}
public function testCustomTags()
{
$yaml = <<<YAML
foo: !my_tag {foo: bar}
YAML;
$ret = $this->createCommandTester()->execute(['filename' => $this->createFile($yaml), '--parse-tags' => true], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]);
$this->assertSame(0, $ret, 'lint:yaml exits with code 0 in case of success');
}
public function testCustomTagsError()
{
$yaml = <<<YAML
foo: !my_tag {foo: bar}
YAML;
$ret = $this->createCommandTester()->execute(['filename' => $this->createFile($yaml)], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]);
$this->assertSame(1, $ret, 'lint:yaml exits with code 1 in case of error');
}
public function testLintFileNotReadable()
{
$this->expectException('RuntimeException');
$tester = $this->createCommandTester();
$filename = $this->createFile('');
unlink($filename);
$ret = $tester->execute(['filename' => $filename], ['decorated' => false]);
}
/**
* @return string Path to the new file
*/
private function createFile($content)
{
$filename = tempnam(sys_get_temp_dir().'/framework-yml-lint-test', 'sf-');
file_put_contents($filename, $content);
$this->files[] = $filename;
return $filename;
}
/**
* @return CommandTester
*/
protected function createCommandTester()
{
$application = new Application();
$application->add(new LintCommand());
$command = $application->find('lint:yaml');
return new CommandTester($command);
}
protected function setUp(): void
{
$this->files = [];
@mkdir(sys_get_temp_dir().'/framework-yml-lint-test');
}
protected function tearDown(): void
{
foreach ($this->files as $file) {
if (file_exists($file)) {
unlink($file);
}
}
rmdir(sys_get_temp_dir().'/framework-yml-lint-test');
}
}
class Foo
{
const TEST = 'foo';
}

View File

@ -1,540 +0,0 @@
<?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\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Dumper;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Tag\TaggedValue;
use Symfony\Component\Yaml\Yaml;
class DumperTest extends TestCase
{
protected $parser;
protected $dumper;
protected $path;
protected $array = [
'' => 'bar',
'foo' => '#bar',
'foo\'bar' => [],
'bar' => [1, 'foo'],
'foobar' => [
'foo' => 'bar',
'bar' => [1, 'foo'],
'foobar' => [
'foo' => 'bar',
'bar' => [1, 'foo'],
],
],
];
protected function setUp(): void
{
$this->parser = new Parser();
$this->dumper = new Dumper();
$this->path = __DIR__.'/Fixtures';
}
protected function tearDown(): void
{
$this->parser = null;
$this->dumper = null;
$this->path = null;
$this->array = null;
}
public function testIndentationInConstructor()
{
$dumper = new Dumper(7);
$expected = <<<'EOF'
'': bar
foo: '#bar'
'foo''bar': { }
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
EOF;
$this->assertEquals($expected, $dumper->dump($this->array, 4, 0));
}
public function testSpecifications()
{
$files = $this->parser->parse(file_get_contents($this->path.'/index.yml'));
foreach ($files as $file) {
$yamls = file_get_contents($this->path.'/'.$file.'.yml');
// split YAMLs documents
foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) {
if (!$yaml) {
continue;
}
$test = $this->parser->parse($yaml);
if (isset($test['dump_skip']) && $test['dump_skip']) {
continue;
} elseif (isset($test['todo']) && $test['todo']) {
// TODO
} else {
eval('$expected = '.trim($test['php']).';');
$this->assertSame($expected, $this->parser->parse($this->dumper->dump($expected, 10)), $test['test']);
}
}
}
}
public function testInlineLevel()
{
$expected = <<<'EOF'
{ '': bar, foo: '#bar', 'foo''bar': { }, bar: [1, foo], foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } }
EOF;
$this->assertEquals($expected, $this->dumper->dump($this->array, -10), '->dump() takes an inline level argument');
$this->assertEquals($expected, $this->dumper->dump($this->array, 0), '->dump() takes an inline level argument');
$expected = <<<'EOF'
'': bar
foo: '#bar'
'foo''bar': { }
bar: [1, foo]
foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } }
EOF;
$this->assertEquals($expected, $this->dumper->dump($this->array, 1), '->dump() takes an inline level argument');
$expected = <<<'EOF'
'': bar
foo: '#bar'
'foo''bar': { }
bar:
- 1
- foo
foobar:
foo: bar
bar: [1, foo]
foobar: { foo: bar, bar: [1, foo] }
EOF;
$this->assertEquals($expected, $this->dumper->dump($this->array, 2), '->dump() takes an inline level argument');
$expected = <<<'EOF'
'': bar
foo: '#bar'
'foo''bar': { }
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
foobar:
foo: bar
bar: [1, foo]
EOF;
$this->assertEquals($expected, $this->dumper->dump($this->array, 3), '->dump() takes an inline level argument');
$expected = <<<'EOF'
'': bar
foo: '#bar'
'foo''bar': { }
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
EOF;
$this->assertEquals($expected, $this->dumper->dump($this->array, 4), '->dump() takes an inline level argument');
$this->assertEquals($expected, $this->dumper->dump($this->array, 10), '->dump() takes an inline level argument');
}
public function testObjectSupportEnabled()
{
$dump = $this->dumper->dump(['foo' => new A(), 'bar' => 1], 0, 0, Yaml::DUMP_OBJECT);
$this->assertEquals('{ foo: !php/object \'O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}\', bar: 1 }', $dump, '->dump() is able to dump objects');
}
public function testObjectSupportDisabledButNoExceptions()
{
$dump = $this->dumper->dump(['foo' => new A(), 'bar' => 1]);
$this->assertEquals('{ foo: null, bar: 1 }', $dump, '->dump() does not dump objects when disabled');
}
public function testObjectSupportDisabledWithExceptions()
{
$this->expectException('Symfony\Component\Yaml\Exception\DumpException');
$this->dumper->dump(['foo' => new A(), 'bar' => 1], 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE);
}
/**
* @dataProvider getEscapeSequences
*/
public function testEscapedEscapeSequencesInQuotedScalar($input, $expected)
{
$this->assertEquals($expected, $this->dumper->dump($input));
}
public function getEscapeSequences()
{
return [
'empty string' => ['', "''"],
'null' => ["\x0", '"\\0"'],
'bell' => ["\x7", '"\\a"'],
'backspace' => ["\x8", '"\\b"'],
'horizontal-tab' => ["\t", '"\\t"'],
'line-feed' => ["\n", '"\\n"'],
'vertical-tab' => ["\v", '"\\v"'],
'form-feed' => ["\xC", '"\\f"'],
'carriage-return' => ["\r", '"\\r"'],
'escape' => ["\x1B", '"\\e"'],
'space' => [' ', "' '"],
'double-quote' => ['"', "'\"'"],
'slash' => ['/', '/'],
'backslash' => ['\\', '\\'],
'next-line' => ["\xC2\x85", '"\\N"'],
'non-breaking-space' => ["\xc2\xa0", '"\\_"'],
'line-separator' => ["\xE2\x80\xA8", '"\\L"'],
'paragraph-separator' => ["\xE2\x80\xA9", '"\\P"'],
'colon' => [':', "':'"],
];
}
public function testBinaryDataIsDumpedBase64Encoded()
{
$binaryData = file_get_contents(__DIR__.'/Fixtures/arrow.gif');
$expected = '{ data: !!binary '.base64_encode($binaryData).' }';
$this->assertSame($expected, $this->dumper->dump(['data' => $binaryData]));
}
public function testNonUtf8DataIsDumpedBase64Encoded()
{
// "für" (ISO-8859-1 encoded)
$this->assertSame('!!binary ZsM/cg==', $this->dumper->dump("f\xc3\x3fr"));
}
/**
* @dataProvider objectAsMapProvider
*/
public function testDumpObjectAsMap($object, $expected)
{
$yaml = $this->dumper->dump($object, 0, 0, Yaml::DUMP_OBJECT_AS_MAP);
$this->assertEquals($expected, Yaml::parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
}
public function objectAsMapProvider()
{
$tests = [];
$bar = new \stdClass();
$bar->class = 'classBar';
$bar->args = ['bar'];
$zar = new \stdClass();
$foo = new \stdClass();
$foo->bar = $bar;
$foo->zar = $zar;
$object = new \stdClass();
$object->foo = $foo;
$tests['stdClass'] = [$object, $object];
$arrayObject = new \ArrayObject();
$arrayObject['foo'] = 'bar';
$arrayObject['baz'] = 'foobar';
$parsedArrayObject = new \stdClass();
$parsedArrayObject->foo = 'bar';
$parsedArrayObject->baz = 'foobar';
$tests['ArrayObject'] = [$arrayObject, $parsedArrayObject];
$a = new A();
$tests['arbitrary-object'] = [$a, null];
return $tests;
}
public function testDumpingArrayObjectInstancesRespectsInlineLevel()
{
$deep = new \ArrayObject(['deep1' => 'd', 'deep2' => 'e']);
$inner = new \ArrayObject(['inner1' => 'b', 'inner2' => 'c', 'inner3' => $deep]);
$outer = new \ArrayObject(['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(['d', 'e']);
$inner = new \ArrayObject(['b', 'c', $deep]);
$outer = new \ArrayObject(['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(['d', 'e']);
$inner = new \ArrayObject(['b', 'c', $deep]);
$outer = new \ArrayObject(['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 testDumpingTaggedValueSequenceRespectsInlineLevel()
{
$data = [
new TaggedValue('user', [
'username' => 'jane',
]),
new TaggedValue('user', [
'username' => 'john',
]),
];
$yaml = $this->dumper->dump($data, 2);
$expected = <<<YAML
- !user
username: jane
- !user
username: john
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingTaggedValueSequenceWithInlinedTagValues()
{
$data = [
new TaggedValue('user', [
'username' => 'jane',
]),
new TaggedValue('user', [
'username' => 'john',
]),
];
$yaml = $this->dumper->dump($data, 1);
$expected = <<<YAML
- !user { username: jane }
- !user { username: john }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingTaggedValueMapRespectsInlineLevel()
{
$data = [
'user1' => new TaggedValue('user', [
'username' => 'jane',
]),
'user2' => new TaggedValue('user', [
'username' => 'john',
]),
];
$yaml = $this->dumper->dump($data, 2);
$expected = <<<YAML
user1: !user
username: jane
user2: !user
username: john
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingTaggedValueMapWithInlinedTagValues()
{
$data = [
'user1' => new TaggedValue('user', [
'username' => 'jane',
]),
'user2' => new TaggedValue('user', [
'username' => 'john',
]),
];
$yaml = $this->dumper->dump($data, 1);
$expected = <<<YAML
user1: !user { username: jane }
user2: !user { username: john }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingNotInlinedScalarTaggedValue()
{
$data = [
'user1' => new TaggedValue('user', 'jane'),
'user2' => new TaggedValue('user', 'john'),
];
$expected = <<<YAML
user1: !user jane
user2: !user john
YAML;
$this->assertSame($expected, $this->dumper->dump($data, 2));
}
public function testDumpingNotInlinedNullTaggedValue()
{
$data = [
'foo' => new TaggedValue('bar', null),
];
$expected = <<<YAML
foo: !bar null
YAML;
$this->assertSame($expected, $this->dumper->dump($data, 2));
}
public function testDumpMultiLineStringAsScalarBlock()
{
$data = [
'data' => [
'single_line' => 'foo bar baz',
'multi_line' => "foo\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz",
'multi_line_with_carriage_return' => "foo\nbar\r\nbaz",
'nested_inlined_multi_line_string' => [
'inlined_multi_line' => "foo\nbar\r\nempty line:\n\nbaz",
],
],
];
$this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
}
public function testDumpMultiLineStringAsScalarBlockWhenFirstLineHasLeadingSpace()
{
$data = [
'data' => [
'multi_line' => " the first line has leading spaces\nThe second line does not.",
],
];
$this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block_leading_space_in_first_line.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
}
public function testCarriageReturnIsMaintainedWhenDumpingAsMultiLineLiteralBlock()
{
$this->assertSame("- \"a\\r\\nb\\nc\"\n", $this->dumper->dump(["a\r\nb\nc"], 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
}
public function testZeroIndentationThrowsException()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The indentation must be greater than zero');
new Dumper(0);
}
public function testNegativeIndentationThrowsException()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The indentation must be greater than zero');
new Dumper(-4);
}
}
class A
{
public $a = 'foo';
}

View File

@ -1,31 +0,0 @@
--- %YAML:1.0
test: Simple Alias Example
brief: >
If you need to refer to the same item of data twice,
you can give that item an alias. The alias is a plain
string, starting with an ampersand. The item may then
be referred to by the alias throughout your document
by using an asterisk before the name of the alias.
This is called an anchor.
yaml: |
- &showell Steve
- Clark
- Brian
- Oren
- *showell
php: |
['Steve', 'Clark', 'Brian', 'Oren', 'Steve']
---
test: Alias of a Mapping
brief: >
An alias can be used on any item of data, including
sequences, mappings, and other complex data types.
yaml: |
- &hello
Meat: pork
Starch: potato
- banana
- *hello
php: |
[['Meat'=>'pork', 'Starch'=>'potato'], 'banana', ['Meat'=>'pork', 'Starch'=>'potato']]

View File

@ -1,202 +0,0 @@
--- %YAML:1.0
test: Simple Sequence
brief: |
You can specify a list in YAML by placing each
member of the list on a new line with an opening
dash. These lists are called sequences.
yaml: |
- apple
- banana
- carrot
php: |
['apple', 'banana', 'carrot']
---
test: Sequence With Item Being Null In The Middle
brief: |
You can specify a list in YAML by placing each
member of the list on a new line with an opening
dash. These lists are called sequences.
yaml: |
- apple
-
- carrot
php: |
['apple', null, 'carrot']
---
test: Sequence With Last Item Being Null
brief: |
You can specify a list in YAML by placing each
member of the list on a new line with an opening
dash. These lists are called sequences.
yaml: |
- apple
- banana
-
php: |
['apple', 'banana', null]
---
test: Nested Sequences
brief: |
You can include a sequence within another
sequence by giving the sequence an empty
dash, followed by an indented list.
yaml: |
-
- foo
- bar
- baz
php: |
[['foo', 'bar', 'baz']]
---
test: Mixed Sequences
brief: |
Sequences can contain any YAML data,
including strings and other sequences.
yaml: |
- apple
-
- foo
- bar
- x123
- banana
- carrot
php: |
['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
---
test: Deeply Nested Sequences
brief: |
Sequences can be nested even deeper, with each
level of indentation representing a level of
depth.
yaml: |
-
-
- uno
- dos
php: |
[[['uno', 'dos']]]
---
test: Simple Mapping
brief: |
You can add a keyed list (also known as a dictionary or
hash) to your document by placing each member of the
list on a new line, with a colon separating the key
from its value. In YAML, this type of list is called
a mapping.
yaml: |
foo: whatever
bar: stuff
php: |
['foo' => 'whatever', 'bar' => 'stuff']
---
test: Sequence in a Mapping
brief: |
A value in a mapping can be a sequence.
yaml: |
foo: whatever
bar:
- uno
- dos
php: |
['foo' => 'whatever', 'bar' => ['uno', 'dos']]
---
test: Nested Mappings
brief: |
A value in a mapping can be another mapping.
yaml: |
foo: whatever
bar:
fruit: apple
name: steve
sport: baseball
php: |
[
'foo' => 'whatever',
'bar' => [
'fruit' => 'apple',
'name' => 'steve',
'sport' => 'baseball'
]
]
---
test: Mixed Mapping
brief: |
A mapping can contain any assortment
of mappings and sequences as values.
yaml: |
foo: whatever
bar:
-
fruit: apple
name: steve
sport: baseball
- more
-
python: rocks
perl: papers
ruby: scissorses
php: |
[
'foo' => 'whatever',
'bar' => [
[
'fruit' => 'apple',
'name' => 'steve',
'sport' => 'baseball'
],
'more',
[
'python' => 'rocks',
'perl' => 'papers',
'ruby' => 'scissorses'
]
]
]
---
test: Mapping-in-Sequence Shortcut
todo: true
brief: |
If you are adding a mapping to a sequence, you
can place the mapping on the same line as the
dash as a shortcut.
yaml: |
- work on YAML.py:
- work on Store
php: |
[['work on YAML.py' => ['work on Store']]]
---
test: Sequence-in-Mapping Shortcut
todo: true
brief: |
The dash in a sequence counts as indentation, so
you can add a sequence inside of a mapping without
needing spaces as indentation.
yaml: |
allow:
- 'localhost'
- '%.sourceforge.net'
- '%.freepan.org'
php: |
['allow' => ['localhost', '%.sourceforge.net', '%.freepan.org']]
---
todo: true
test: Merge key
brief: |
A merge key ('<<') can be used in a mapping to insert other mappings. If
the value associated with the merge key is a mapping, each of its key/value
pairs is inserted into the current mapping.
yaml: |
mapping:
name: Joe
job: Accountant
<<:
age: 38
php: |
[
'mapping' =>
[
'name' => 'Joe',
'job' => 'Accountant',
'age' => 38
]
]

View File

@ -1,51 +0,0 @@
---
test: One Element Mapping
brief: |
A mapping with one key/value pair
yaml: |
foo: bar
php: |
['foo' => 'bar']
---
test: Multi Element Mapping
brief: |
More than one key/value pair
yaml: |
red: baron
white: walls
blue: berries
php: |
[
'red' => 'baron',
'white' => 'walls',
'blue' => 'berries',
]
---
test: Values aligned
brief: |
Often times human editors of documents will align the values even
though YAML emitters generally don't.
yaml: |
red: baron
white: walls
blue: berries
php: |
[
'red' => 'baron',
'white' => 'walls',
'blue' => 'berries',
]
---
test: Colons aligned
brief: |
Spaces can come before the ': ' key/value separator.
yaml: |
red : baron
white : walls
blue : berries
php: |
[
'red' => 'baron',
'white' => 'walls',
'blue' => 'berries',
]

View File

@ -1,85 +0,0 @@
--- %YAML:1.0
test: Trailing Document Separator
todo: true
brief: >
You can separate YAML documents
with a string of three dashes.
yaml: |
- foo: 1
bar: 2
---
more: stuff
python: |
[
[ { 'foo': 1, 'bar': 2 } ],
{ 'more': 'stuff' }
]
ruby: |
[ { 'foo' => 1, 'bar' => 2 } ]
---
test: Leading Document Separator
todo: true
brief: >
You can explicitly give an opening
document separator to your YAML stream.
yaml: |
---
- foo: 1
bar: 2
---
more: stuff
python: |
[
[ {'foo': 1, 'bar': 2}],
{'more': 'stuff'}
]
ruby: |
[ { 'foo' => 1, 'bar' => 2 } ]
---
test: YAML Header
todo: true
brief: >
The opening separator can contain directives
to the YAML parser, such as the version
number.
yaml: |
--- %YAML:1.0
foo: 1
bar: 2
php: |
['foo' => 1, 'bar' => 2]
documents: 1
---
test: Red Herring Document Separator
brief: >
Separators included in blocks or strings
are treated as blocks or strings, as the
document separator should have no indentation
preceding it.
yaml: |
foo: |
---
php: |
['foo' => "---\n"]
---
test: Multiple Document Separators in Block
brief: >
This technique allows you to embed other YAML
documents within literal blocks.
yaml: |
foo: |
---
foo: bar
---
yo: baz
bar: |
fooness
php: |
[
'foo' => "---\nfoo: bar\n---\nyo: baz\n",
'bar' => "fooness\n"
]

View File

@ -1,25 +0,0 @@
---
test: Missing value for hash item
todo: true
brief: |
Third item in this hash doesn't have a value
yaml: |
okay: value
also okay: ~
causes error because no value specified
last key: value okay here too
python-error: causes error because no value specified
---
test: Not indenting enough
brief: |
There was a bug in PyYaml where it was off by one
in the indentation check. It was allowing the YAML
below.
# This is actually valid YAML now. Someone should tell showell.
yaml: |
foo:
firstline: 1
secondline: 2
php: |
['foo' => null, 'firstline' => 1, 'secondline' => 2]

View File

@ -1,60 +0,0 @@
---
test: Simple Inline Array
brief: >
Sequences can be contained on a
single line, using the inline syntax.
Separate each entry with commas and
enclose in square brackets.
yaml: |
seq: [ a, b, c ]
php: |
['seq' => ['a', 'b', 'c']]
---
test: Simple Inline Hash
brief: >
Mapping can also be contained on
a single line, using the inline
syntax. Each key-value pair is
separated by a colon, with a comma
between each entry in the mapping.
Enclose with curly braces.
yaml: |
hash: { name: Steve, foo: bar }
php: |
['hash' => ['name' => 'Steve', 'foo' => 'bar']]
---
test: Multi-line Inline Collections
todo: true
brief: >
Both inline sequences and inline mappings
can span multiple lines, provided that you
indent the additional lines.
yaml: |
languages: [ Ruby,
Perl,
Python ]
websites: { YAML: yaml.org,
Ruby: ruby-lang.org,
Python: python.org,
Perl: use.perl.org }
php: |
[
'languages' => ['Ruby', 'Perl', 'Python'],
'websites' => [
'YAML' => 'yaml.org',
'Ruby' => 'ruby-lang.org',
'Python' => 'python.org',
'Perl' => 'use.perl.org'
]
]
---
test: Commas in Values (not in the spec!)
todo: true
brief: >
List items in collections are delimited by commas, but
there must be a space after each comma. This allows you
to add numbers without quoting.
yaml: |
attendances: [ 45,123, 70,000, 17,222 ]
php: |
['attendances' => [45123, 70000, 17222]]

View File

@ -1,176 +0,0 @@
--- %YAML:1.0
test: Single ending newline
brief: >
A pipe character, followed by an indented
block of text is treated as a literal
block, in which newlines are preserved
throughout the block, including the final
newline.
yaml: |
---
this: |
Foo
Bar
php: |
['this' => "Foo\nBar\n"]
---
test: The '+' indicator
brief: >
The '+' indicator says to keep newlines at the end of text
blocks.
yaml: |
normal: |
extra new lines not kept
preserving: |+
extra new lines are kept
dummy: value
php: |
[
'normal' => "extra new lines not kept\n",
'preserving' => "extra new lines are kept\n\n\n",
'dummy' => 'value'
]
---
test: Three trailing newlines in literals
brief: >
To give you more control over how space
is preserved in text blocks, YAML has
the keep '+' and chomp '-' indicators.
The keep indicator will preserve all
ending newlines, while the chomp indicator
will strip all ending newlines.
yaml: |
clipped: |
This has one newline.
same as "clipped" above: "This has one newline.\n"
stripped: |-
This has no newline.
same as "stripped" above: "This has no newline."
kept: |+
This has four newlines.
same as "kept" above: "This has four newlines.\n\n\n\n"
php: |
[
'clipped' => "This has one newline.\n",
'same as "clipped" above' => "This has one newline.\n",
'stripped' => 'This has no newline.',
'same as "stripped" above' => 'This has no newline.',
'kept' => "This has four newlines.\n\n\n\n",
'same as "kept" above' => "This has four newlines.\n\n\n\n"
]
---
test: Extra trailing newlines with spaces
todo: true
brief: >
Normally, only a single newline is kept
from the end of a literal block, unless the
keep '+' character is used in combination
with the pipe. The following example
will preserve all ending whitespace
since the last line of both literal blocks
contains spaces which extend past the indentation
level.
yaml: |
---
this: |
Foo
kept: |+
Foo
php: |
['this' => "Foo\n\n \n",
'kept' => "Foo\n\n \n"]
---
test: Folded Block in a Sequence
brief: >
A greater-then character, followed by an indented
block of text is treated as a folded block, in
which lines of text separated by a single newline
are concatenated as a single line.
yaml: |
---
- apple
- banana
- >
can't you see
the beauty of yaml?
hmm
- dog
php: |
[
'apple',
'banana',
"can't you see the beauty of yaml? hmm\n",
'dog'
]
---
test: Folded Block as a Mapping Value
brief: >
Both literal and folded blocks can be
used in collections, as values in a
sequence or a mapping.
yaml: |
---
quote: >
Mark McGwire's
year was crippled
by a knee injury.
source: espn
php: |
[
'quote' => "Mark McGwire's year was crippled by a knee injury.\n",
'source' => 'espn'
]
---
test: Three trailing newlines in folded blocks
brief: >
The keep and chomp indicators can also
be applied to folded blocks.
yaml: |
clipped: >
This has one newline.
same as "clipped" above: "This has one newline.\n"
stripped: >-
This has no newline.
same as "stripped" above: "This has no newline."
kept: >+
This has four newlines.
same as "kept" above: "This has four newlines.\n\n\n\n"
php: |
[
'clipped' => "This has one newline.\n",
'same as "clipped" above' => "This has one newline.\n",
'stripped' => 'This has no newline.',
'same as "stripped" above' => 'This has no newline.',
'kept' => "This has four newlines.\n\n\n\n",
'same as "kept" above' => "This has four newlines.\n\n\n\n"
]

View File

@ -1,45 +0,0 @@
--- %YAML:1.0
test: Empty Sequence
brief: >
You can represent the empty sequence
with an empty inline sequence.
yaml: |
empty: []
php: |
['empty' => []]
---
test: Empty Mapping
brief: >
You can represent the empty mapping
with an empty inline mapping.
yaml: |
empty: {}
php: |
['empty' => []]
---
test: Empty Sequence as Entire Document
yaml: |
[]
php: |
[]
---
test: Empty Mapping as Entire Document
yaml: |
{}
php: |
[]
---
test: Null as Document
yaml: |
~
php: |
null
---
test: Empty String
brief: >
You can represent an empty string
with a pair of quotes.
yaml: |
''
php: |
''

File diff suppressed because it is too large Load Diff

View File

@ -1,224 +0,0 @@
--- %YAML:1.0
test: Strings
brief: >
Any group of characters beginning with an
alphabetic or numeric character is a string,
unless it belongs to one of the groups below
(such as an Integer or Time).
yaml: |
String
php: |
'String'
---
test: String characters
brief: >
A string can contain any alphabetic or
numeric character, along with many
punctuation characters, including the
period, dash, space, quotes, exclamation, and
question mark.
yaml: |
- What's Yaml?
- It's for writing data structures in plain text.
- And?
- And what? That's not good enough for you?
- No, I mean, "And what about Yaml?"
- Oh, oh yeah. Uh.. Yaml for Ruby.
php: |
[
"What's Yaml?",
"It's for writing data structures in plain text.",
"And?",
"And what? That's not good enough for you?",
"No, I mean, \"And what about Yaml?\"",
"Oh, oh yeah. Uh.. Yaml for Ruby."
]
---
test: Indicators in Strings
brief: >
Be careful using indicators in strings. In particular,
the comma, colon, and pound sign must be used carefully.
yaml: |
the colon followed by space is an indicator: but is a string:right here
same for the pound sign: here we have it#in a string
the comma can, honestly, be used in most cases: [ but not in, inline collections ]
php: |
[
'the colon followed by space is an indicator' => 'but is a string:right here',
'same for the pound sign' => 'here we have it#in a string',
'the comma can, honestly, be used in most cases' => ['but not in', 'inline collections']
]
---
test: Forcing Strings
brief: >
Any YAML type can be forced into a string using the
explicit !!str method.
yaml: |
date string: !!str 2001-08-01
number string: !!str 192
php: |
[
'date string' => '2001-08-01',
'number string' => '192'
]
---
test: Single-quoted Strings
brief: >
You can also enclose your strings within single quotes,
which allows use of slashes, colons, and other indicators
freely. Inside single quotes, you can represent a single
quote in your string by using two single quotes next to
each other.
yaml: |
all my favorite symbols: '#:!/%.)'
a few i hate: '&(*'
why do i hate them?: 'it''s very hard to explain'
entities: '&pound; me'
php: |
[
'all my favorite symbols' => '#:!/%.)',
'a few i hate' => '&(*',
'why do i hate them?' => 'it\'s very hard to explain',
'entities' => '&pound; me'
]
---
test: Double-quoted Strings
brief: >
Enclosing strings in double quotes allows you
to use escapings to represent ASCII and
Unicode characters.
yaml: |
i know where i want my line breaks: "one here\nand another here\n"
php: |
[
'i know where i want my line breaks' => "one here\nand another here\n"
]
---
test: Multi-line Quoted Strings
todo: true
brief: >
Both single- and double-quoted strings may be
carried on to new lines in your YAML document.
They must be indented a step and indentation
is interpreted as a single space.
yaml: |
i want a long string: "so i'm going to
let it go on and on to other lines
until i end it with a quote."
php: |
['i want a long string' => "so i'm going to ".
"let it go on and on to other lines ".
"until i end it with a quote."
]
---
test: Plain scalars
todo: true
brief: >
Unquoted strings may also span multiple lines, if they
are free of YAML space indicators and indented.
yaml: |
- My little toe is broken in two places;
- I'm crazy to have skied this way;
- I'm not the craziest he's seen, since there was always the German guy
who skied for 3 hours on a broken shin bone (just below the kneecap);
- Nevertheless, second place is respectable, and he doesn't
recommend going for the record;
- He's going to put my foot in plaster for a month;
- This would impair my skiing ability somewhat for the
duration, as can be imagined.
php: |
[
"My little toe is broken in two places;",
"I'm crazy to have skied this way;",
"I'm not the craziest he's seen, since there was always ".
"the German guy who skied for 3 hours on a broken shin ".
"bone (just below the kneecap);",
"Nevertheless, second place is respectable, and he doesn't ".
"recommend going for the record;",
"He's going to put my foot in plaster for a month;",
"This would impair my skiing ability somewhat for the duration, ".
"as can be imagined."
]
---
test: 'Null'
brief: >
You can use the tilde '~' character for a null value.
yaml: |
name: Mr. Show
hosted by: Bob and David
date of next season: ~
php: |
[
'name' => 'Mr. Show',
'hosted by' => 'Bob and David',
'date of next season' => null
]
---
test: Boolean
brief: >
You can use 'true' and 'false' for Boolean values.
yaml: |
Is Gus a Liar?: true
Do I rely on Gus for Sustenance?: false
php: |
[
'Is Gus a Liar?' => true,
'Do I rely on Gus for Sustenance?' => false
]
---
test: Integers
dump_skip: true
brief: >
An integer is a series of numbers, optionally
starting with a positive or negative sign. Integers
may also contain commas for readability.
yaml: |
zero: 0
simple: 12
php: |
[
'zero' => 0,
'simple' => 12,
]
---
test: Floats
dump_skip: true
brief: >
Floats are represented by numbers with decimals,
allowing for scientific notation, as well as
positive and negative infinity and "not a number."
yaml: |
a simple float: 2.00
scientific notation: 1.00009e+3
php: |
[
'a simple float' => 2.0,
'scientific notation' => 1000.09
]
---
test: Time
todo: true
brief: >
You can represent timestamps by using
ISO8601 format, or a variation which
allows spaces between the date, time and
time zone.
yaml: |
iso8601: 2001-12-14t21:59:43.10-05:00
space separated: 2001-12-14 21:59:43.10 -05:00
php: |
[
'iso8601' => mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ),
'space separated' => mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" )
]
---
test: Date
todo: true
brief: >
A date can be represented by its year,
month and day in ISO8601 order.
yaml: |
1976-07-31
php: |
date( 1976, 7, 31 )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

View File

@ -1,11 +0,0 @@
--- %YAML:1.0
test: Miscellaneous
spec: 2.21
yaml: |
true: true
false: false
php: |
[
'true' => true,
'false' => false,
]

View File

@ -1 +0,0 @@
value: <?php echo 1 + 2 + 3 ?>

View File

@ -1,155 +0,0 @@
test: outside double quotes
yaml: |
\0 \ \a \b \n
php: |
"\\0 \\ \\a \\b \\n"
---
test: 'null'
yaml: |
"\0"
php: |
"\x00"
---
test: bell
yaml: |
"\a"
php: |
"\x07"
---
test: backspace
yaml: |
"\b"
php: |
"\x08"
---
test: horizontal tab (1)
yaml: |
"\t"
php: |
"\x09"
---
test: horizontal tab (2)
yaml: |
"\ "
php: |
"\x09"
---
test: line feed
yaml: |
"\n"
php: |
"\x0a"
---
test: vertical tab
yaml: |
"\v"
php: |
"\x0b"
---
test: form feed
yaml: |
"\f"
php: |
"\x0c"
---
test: carriage return
yaml: |
"\r"
php: |
"\x0d"
---
test: escape
yaml: |
"\e"
php: |
"\x1b"
---
test: space
yaml: |
"\ "
php: |
"\x20"
---
test: slash
yaml: |
"\/"
php: |
"\x2f"
---
test: backslash
yaml: |
"\\"
php: |
"\\"
---
test: Unicode next line
yaml: |
"\N"
php: |
"\xc2\x85"
---
test: Unicode non-breaking space
yaml: |
"\_"
php: |
"\xc2\xa0"
---
test: Unicode line separator
yaml: |
"\L"
php: |
"\xe2\x80\xa8"
---
test: Unicode paragraph separator
yaml: |
"\P"
php: |
"\xe2\x80\xa9"
---
test: Escaped 8-bit Unicode
yaml: |
"\x42"
php: |
"B"
---
test: Escaped 16-bit Unicode
yaml: |
"\u20ac"
php: |
"\xe2\x82\xac"
---
test: Escaped 32-bit Unicode
yaml: |
"\U00000043"
php: |
"C"
---
test: Example 5.13 Escaped Characters
note: |
Currently throws an error parsing first line. Maybe Symfony Yaml doesn't support
continuation of string across multiple lines? Keeping test here but disabled.
todo: true
yaml: |
"Fun with \\
\" \a \b \e \f \
\n \r \t \v \0 \
\ \_ \N \L \P \
\x41 \u0041 \U00000041"
php: |
"Fun with \x5C\n\x22 \x07 \x08 \x1B \x0C\n\x0A \x0D \x09 \x0B \x00\n\x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9\nA A A"
---
test: Double quotes with a line feed
yaml: |
{ double: "some value\n \"some quoted string\" and 'some single quotes one'" }
php: |
[
'double' => "some value\n \"some quoted string\" and 'some single quotes one'"
]
---
test: Backslashes
yaml: |
{ single: 'foo\Var', no-quotes: foo\Var, double: "foo\\Var" }
php: |
[
'single' => 'foo\Var', 'no-quotes' => 'foo\Var', 'double' => 'foo\Var'
]

View File

@ -1,18 +0,0 @@
- escapedCharacters
- sfComments
- sfCompact
- sfTests
- sfObjects
- sfMergeKey
- sfQuotes
- YtsAnchorAlias
- YtsBasicTests
- YtsBlockMapping
- YtsDocumentSeparator
- YtsErrorTests
- YtsFlowCollections
- YtsFoldedScalars
- YtsNullsAndEmpties
- YtsSpecificationExamples
- YtsTypeTransfers
- unindentedCollections

View File

@ -1,14 +0,0 @@
data:
single_line: 'foo bar baz'
multi_line: |
foo
line with trailing spaces:
bar
integer like line:
123456789
empty line:
baz
multi_line_with_carriage_return: "foo\nbar\r\nbaz"
nested_inlined_multi_line_string: { inlined_multi_line: "foo\nbar\r\nempty line:\n\nbaz" }

View File

@ -1,4 +0,0 @@
data:
multi_line: |4
the first line has leading spaces
The second line does not.

View File

@ -1,3 +0,0 @@
- booleanMappingKeys
- numericMappingKeys
- nullMappingKey

View File

@ -1,18 +0,0 @@
- escapedCharacters
- sfComments
- sfCompact
- sfTests
- sfObjects
- sfMergeKey
- sfQuotes
- YtsAnchorAlias
- YtsBasicTests
- YtsBlockMapping
- YtsDocumentSeparator
- YtsErrorTests
- YtsFlowCollections
- YtsFoldedScalars
- YtsNullsAndEmpties
- YtsSpecificationExamples
- YtsTypeTransfers
- unindentedCollections

View File

@ -1,9 +0,0 @@
--- %YAML:1.0
test: Miscellaneous
spec: 2.21
yaml: |
null: ~
php: |
[
'null' => null,
]

View File

@ -1,23 +0,0 @@
--- %YAML:1.0
test: A sequence with an unordered array
brief: >
A sequence with an unordered array
yaml: |
1: foo
0: bar
php: |
[1 => 'foo', 0 => 'bar']
---
test: Integers as Map Keys
brief: >
An integer can be used as dictionary key.
yaml: |
1: one
2: two
3: three
php: |
[
1 => 'one',
2 => 'two',
3 => 'three'
]

View File

@ -1,76 +0,0 @@
--- %YAML:1.0
test: Comments at the end of a line
brief: >
Comments at the end of a line
yaml: |
ex1: "foo # bar"
ex2: "foo # bar" # comment
ex3: 'foo # bar' # comment
ex4: foo # comment
ex5: foo # comment with tab before
ex6: foo#foo # comment here
ex7: foo # ignore me # and me
php: |
['ex1' => 'foo # bar', 'ex2' => 'foo # bar', 'ex3' => 'foo # bar', 'ex4' => 'foo', 'ex5' => 'foo', 'ex6' => 'foo#foo', 'ex7' => 'foo']
---
test: Comments in the middle
brief: >
Comments in the middle
yaml: |
foo:
# some comment
# some comment
bar: foo
# some comment
# some comment
php: |
['foo' => ['bar' => 'foo']]
---
test: Comments on a hash line
brief: >
Comments on a hash line
yaml: |
foo: # a comment
foo: bar # a comment
php: |
['foo' => ['foo' => 'bar']]
---
test: 'Value starting with a #'
brief: >
'Value starting with a #'
yaml: |
foo: '#bar'
php: |
['foo' => '#bar']
---
test: Document starting with a comment and a separator
brief: >
Commenting before document start is allowed
yaml: |
# document comment
---
foo: bar # a comment
php: |
['foo' => 'bar']
---
test: Comment containing a colon on a hash line
brief: >
Comment containing a colon on a scalar line
yaml: 'foo # comment: this is also part of the comment'
php: |
'foo'
---
test: 'Hash key containing a #'
brief: >
'Hash key containing a #'
yaml: 'foo#bar: baz'
php: |
['foo#bar' => 'baz']
---
test: 'Hash key ending with a space and a #'
brief: >
'Hash key ending with a space and a #'
yaml: |
'foo #': baz
php: |
['foo #' => 'baz']

View File

@ -1,159 +0,0 @@
--- %YAML:1.0
test: Compact notation
brief: |
Compact notation for sets of mappings with single element
yaml: |
---
# products purchased
- item : Super Hoop
- item : Basketball
quantity: 1
- item:
name: Big Shoes
nick: Biggies
quantity: 1
php: |
[
[
'item' => 'Super Hoop',
],
[
'item' => 'Basketball',
'quantity' => 1,
],
[
'item' => [
'name' => 'Big Shoes',
'nick' => 'Biggies'
],
'quantity' => 1
]
]
---
test: Compact notation combined with inline notation
brief: |
Combinations of compact and inline notation are allowed
yaml: |
---
items:
- { item: Super Hoop, quantity: 1 }
- [ Basketball, Big Shoes ]
php: |
[
'items' => [
[
'item' => 'Super Hoop',
'quantity' => 1,
],
[
'Basketball',
'Big Shoes'
]
]
]
--- %YAML:1.0
test: Compact notation
brief: |
Compact notation for sets of mappings with single element
yaml: |
---
# products purchased
- item : Super Hoop
- item : Basketball
quantity: 1
- item:
name: Big Shoes
nick: Biggies
quantity: 1
php: |
[
[
'item' => 'Super Hoop',
],
[
'item' => 'Basketball',
'quantity' => 1,
],
[
'item' => [
'name' => 'Big Shoes',
'nick' => 'Biggies'
],
'quantity' => 1
]
]
---
test: Compact notation combined with inline notation
brief: |
Combinations of compact and inline notation are allowed
yaml: |
---
items:
- { item: Super Hoop, quantity: 1 }
- [ Basketball, Big Shoes ]
php: |
[
'items' => [
[
'item' => 'Super Hoop',
'quantity' => 1,
],
[
'Basketball',
'Big Shoes'
]
]
]
--- %YAML:1.0
test: Compact notation
brief: |
Compact notation for sets of mappings with single element
yaml: |
---
# products purchased
- item : Super Hoop
- item : Basketball
quantity: 1
- item:
name: Big Shoes
nick: Biggies
quantity: 1
php: |
[
[
'item' => 'Super Hoop',
],
[
'item' => 'Basketball',
'quantity' => 1,
],
[
'item' => [
'name' => 'Big Shoes',
'nick' => 'Biggies'
],
'quantity' => 1
]
]
---
test: Compact notation combined with inline notation
brief: |
Combinations of compact and inline notation are allowed
yaml: |
---
items:
- { item: Super Hoop, quantity: 1 }
- [ Basketball, Big Shoes ]
php: |
[
'items' => [
[
'item' => 'Super Hoop',
'quantity' => 1,
],
[
'Basketball',
'Big Shoes'
]
]
]

View File

@ -1,61 +0,0 @@
--- %YAML:1.0
test: Simple In Place Substitution
brief: >
If you want to reuse an entire alias, only overwriting what is different
you can use a << in place substitution. This is not part of the official
YAML spec, but a widely implemented extension. See the following URL for
details: http://yaml.org/type/merge.html
yaml: |
foo: &foo
a: Steve
b: Clark
c: Brian
e: notnull
bar:
a: before
d: other
e: ~
<<: *foo
b: new
x: Oren
c:
foo: bar
bar: foo
bar_inline: {a: before, d: other, <<: *foo, b: new, x: Oren, c: { foo: bar, bar: foo}}
foo2: &foo2
a: Ballmer
ding: &dong [ fi, fei, fo, fam]
check:
<<:
- *foo
- *dong
isit: tested
head:
<<: [ *foo , *dong , *foo2 ]
taz: &taz
a: Steve
w:
p: 1234
nested:
<<: *taz
d: Doug
w: &nestedref
p: 12345
z:
<<: *nestedref
head_inline: &head_inline { <<: [ *foo , *dong , *foo2 ] }
recursive_inline: { <<: *head_inline, c: { <<: *foo2 } }
php: |
[
'foo' => ['a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'],
'bar' => ['a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => ['foo' => 'bar', 'bar' => 'foo'], 'x' => 'Oren'],
'bar_inline' => ['a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => ['foo' => 'bar', 'bar' => 'foo'], 'e' => 'notnull', 'x' => 'Oren'],
'foo2' => ['a' => 'Ballmer'],
'ding' => ['fi', 'fei', 'fo', 'fam'],
'check' => ['a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'],
'head' => ['a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'],
'taz' => ['a' => 'Steve', 'w' => ['p' => 1234]],
'nested' => ['a' => 'Steve', 'w' => ['p' => 12345], 'd' => 'Doug', 'z' => ['p' => 12345]],
'head_inline' => ['a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'],
'recursive_inline' => ['a' => 'Steve', 'b' => 'Clark', 'c' => ['a' => 'Ballmer'], 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'],
]

View File

@ -1,11 +0,0 @@
--- %YAML:1.0
test: Objects
brief: >
Comments at the end of a line
yaml: |
ex1: "foo # bar"
ex2: "foo # bar" # comment
ex3: 'foo # bar' # comment
ex4: foo # comment
php: |
['ex1' => 'foo # bar', 'ex2' => 'foo # bar', 'ex3' => 'foo # bar', 'ex4' => 'foo']

View File

@ -1,33 +0,0 @@
--- %YAML:1.0
test: Some characters at the beginning of a string must be escaped
brief: >
Some characters at the beginning of a string must be escaped
yaml: |
foo: '| bar'
php: |
['foo' => '| bar']
---
test: A key can be a quoted string
brief: >
A key can be a quoted string
yaml: |
"foo1": bar
'foo2': bar
"foo \" bar": bar
'foo '' bar': bar
'foo3: ': bar
"foo4: ": bar
foo5: { "foo \" bar: ": bar, 'foo '' bar: ': bar }
php: |
[
'foo1' => 'bar',
'foo2' => 'bar',
'foo " bar' => 'bar',
'foo \' bar' => 'bar',
'foo3: ' => 'bar',
'foo4: ' => 'bar',
'foo5' => [
'foo " bar: ' => 'bar',
'foo \' bar: ' => 'bar',
],
]

View File

@ -1,140 +0,0 @@
--- %YAML:1.0
test: Multiple quoted string on one line
brief: >
Multiple quoted string on one line
yaml: |
stripped_title: { name: "foo bar", help: "bar foo" }
php: |
['stripped_title' => ['name' => 'foo bar', 'help' => 'bar foo']]
---
test: Empty sequence
yaml: |
foo: [ ]
php: |
['foo' => []]
---
test: Empty value
yaml: |
foo:
php: |
['foo' => null]
---
test: Inline string parsing
brief: >
Inline string parsing
yaml: |
test: ['complex: string', 'another [string]']
php: |
['test' => ['complex: string', 'another [string]']]
---
test: Boolean
brief: >
Boolean
yaml: |
- false
- true
- null
- ~
- 'false'
- 'true'
- 'null'
- '~'
php: |
[
false,
true,
null,
null,
'false',
'true',
'null',
'~',
]
---
test: Empty lines in literal blocks
brief: >
Empty lines in literal blocks
yaml: |
foo:
bar: |
foo
bar
php: |
['foo' => ['bar' => "foo\n\n\n \nbar\n"]]
---
test: Empty lines in folded blocks
brief: >
Empty lines in folded blocks
yaml: |
foo:
bar: >
foo
bar
php: |
['foo' => ['bar' => "\nfoo\n\nbar\n"]]
---
test: IP addresses
brief: >
IP addresses
yaml: |
foo: 10.0.0.2
php: |
['foo' => '10.0.0.2']
---
test: A sequence with an embedded mapping
brief: >
A sequence with an embedded mapping
yaml: |
- foo
- bar: { bar: foo }
php: |
['foo', ['bar' => ['bar' => 'foo']]]
---
test: Octal
brief: as in spec example 2.19, octal value is converted
yaml: |
foo: 0123
php: |
['foo' => 83]
---
test: Octal strings
brief: Octal notation in a string must remain a string
yaml: |
foo: "0123"
php: |
['foo' => '0123']
---
test: Octal strings
brief: Octal notation in a string must remain a string
yaml: |
foo: '0123'
php: |
['foo' => '0123']
---
test: Octal strings
brief: Octal notation in a string must remain a string
yaml: |
foo: |
0123
php: |
['foo' => "0123\n"]
---
test: Document as a simple hash
brief: Document as a simple hash
yaml: |
{ foo: bar }
php: |
['foo' => 'bar']
---
test: Document as a simple array
brief: Document as a simple array
yaml: |
[ foo, bar ]
php: |
['foo', 'bar']

View File

@ -1,82 +0,0 @@
--- %YAML:1.0
test: Unindented collection
brief: >
Unindented collection
yaml: |
collection:
- item1
- item2
- item3
php: |
['collection' => ['item1', 'item2', 'item3']]
---
test: Nested unindented collection (two levels)
brief: >
Nested unindented collection
yaml: |
collection:
key:
- a
- b
- c
php: |
['collection' => ['key' => ['a', 'b', 'c']]]
---
test: Nested unindented collection (three levels)
brief: >
Nested unindented collection
yaml: |
collection:
key:
subkey:
- one
- two
- three
php: |
['collection' => ['key' => ['subkey' => ['one', 'two', 'three']]]]
---
test: Key/value after unindented collection (1)
brief: >
Key/value after unindented collection (1)
yaml: |
collection:
key:
- a
- b
- c
foo: bar
php: |
['collection' => ['key' => ['a', 'b', 'c']], 'foo' => 'bar']
---
test: Key/value after unindented collection (at the same level)
brief: >
Key/value after unindented collection
yaml: |
collection:
key:
- a
- b
- c
foo: bar
php: |
['collection' => ['key' => ['a', 'b', 'c'], 'foo' => 'bar']]
---
test: Shortcut Key after unindented collection
brief: >
Key/value after unindented collection
yaml: |
collection:
- key: foo
foo: bar
php: |
['collection' => [['key' => 'foo', 'foo' => 'bar']]]
---
test: Shortcut Key after unindented collection with custom spaces
brief: >
Key/value after unindented collection
yaml: |
collection:
- key: foo
foo: bar
php: |
['collection' => [['key' => 'foo', 'foo' => 'bar']]]

View File

@ -1,717 +0,0 @@
<?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\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Inline;
use Symfony\Component\Yaml\Tag\TaggedValue;
use Symfony\Component\Yaml\Yaml;
class InlineTest extends TestCase
{
protected function setUp(): void
{
Inline::initialize(0, 0);
}
/**
* @dataProvider getTestsForParse
*/
public function testParse($yaml, $value, $flags = 0)
{
$this->assertSame($value, Inline::parse($yaml, $flags), sprintf('::parse() converts an inline YAML to a PHP structure (%s)', $yaml));
}
/**
* @dataProvider getTestsForParseWithMapObjects
*/
public function testParseWithMapObjects($yaml, $value, $flags = Yaml::PARSE_OBJECT_FOR_MAP)
{
$actual = Inline::parse($yaml, $flags);
$this->assertSame(serialize($value), serialize($actual));
}
/**
* @dataProvider getTestsForParsePhpConstants
*/
public function testParsePhpConstants($yaml, $value)
{
$actual = Inline::parse($yaml, Yaml::PARSE_CONSTANT);
$this->assertSame($value, $actual);
}
public function getTestsForParsePhpConstants()
{
return [
['!php/const Symfony\Component\Yaml\Yaml::PARSE_CONSTANT', Yaml::PARSE_CONSTANT],
['!php/const PHP_INT_MAX', PHP_INT_MAX],
['[!php/const PHP_INT_MAX]', [PHP_INT_MAX]],
['{ foo: !php/const PHP_INT_MAX }', ['foo' => PHP_INT_MAX]],
['!php/const NULL', null],
];
}
public function testParsePhpConstantThrowsExceptionWhenUndefined()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('The constant "WRONG_CONSTANT" is not defined');
Inline::parse('!php/const WRONG_CONSTANT', Yaml::PARSE_CONSTANT);
}
public function testParsePhpConstantThrowsExceptionOnInvalidType()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessageRegExp('#The string "!php/const PHP_INT_MAX" could not be parsed as a constant.*#');
Inline::parse('!php/const PHP_INT_MAX', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
}
/**
* @dataProvider getTestsForDump
*/
public function testDump($yaml, $value, $parseFlags = 0)
{
$this->assertEquals($yaml, Inline::dump($value), sprintf('::dump() converts a PHP structure to an inline YAML (%s)', $yaml));
$this->assertSame($value, Inline::parse(Inline::dump($value), $parseFlags), 'check consistency');
}
public function testDumpNumericValueWithLocale()
{
$locale = setlocale(LC_NUMERIC, 0);
if (false === $locale) {
$this->markTestSkipped('Your platform does not support locales.');
}
try {
$requiredLocales = ['fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252'];
if (false === setlocale(LC_NUMERIC, $requiredLocales)) {
$this->markTestSkipped('Could not set any of required locales: '.implode(', ', $requiredLocales));
}
$this->assertEquals('1.2', Inline::dump(1.2));
$this->assertStringContainsStringIgnoringCase('fr', setlocale(LC_NUMERIC, 0));
} finally {
setlocale(LC_NUMERIC, $locale);
}
}
public function testHashStringsResemblingExponentialNumericsShouldNotBeChangedToINF()
{
$value = '686e444';
$this->assertSame($value, Inline::parse(Inline::dump($value)));
}
public function testParseScalarWithNonEscapedBlackslashShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('Found unknown escape character "\V".');
Inline::parse('"Foo\Var"');
}
public function testParseScalarWithNonEscapedBlackslashAtTheEndShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
Inline::parse('"Foo\\"');
}
public function testParseScalarWithIncorrectlyQuotedStringShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$value = "'don't do somthin' like that'";
Inline::parse($value);
}
public function testParseScalarWithIncorrectlyDoubleQuotedStringShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$value = '"don"t do somthin" like that"';
Inline::parse($value);
}
public function testParseInvalidMappingKeyShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$value = '{ "foo " bar": "bar" }';
Inline::parse($value);
}
public function testParseMappingKeyWithColonNotFollowedBySpace()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}")');
Inline::parse('{foo:""}');
}
public function testParseInvalidMappingShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
Inline::parse('[foo] bar');
}
public function testParseInvalidSequenceShouldThrowException()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
Inline::parse('{ foo: bar } bar');
}
public function testParseScalarWithCorrectlyQuotedStringShouldReturnString()
{
$value = "'don''t do somthin'' like that'";
$expect = "don't do somthin' like that";
$this->assertSame($expect, Inline::parseScalar($value));
}
/**
* @dataProvider getDataForParseReferences
*/
public function testParseReferences($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml, 0, ['var' => 'var-value']));
}
public function getDataForParseReferences()
{
return [
'scalar' => ['*var', 'var-value'],
'list' => ['[ *var ]', ['var-value']],
'list-in-list' => ['[[ *var ]]', [['var-value']]],
'map-in-list' => ['[ { key: *var } ]', [['key' => 'var-value']]],
'embedded-mapping-in-list' => ['[ key: *var ]', [['key' => 'var-value']]],
'map' => ['{ key: *var }', ['key' => 'var-value']],
'list-in-map' => ['{ key: [*var] }', ['key' => ['var-value']]],
'map-in-map' => ['{ foo: { bar: *var } }', ['foo' => ['bar' => 'var-value']]],
];
}
public function testParseMapReferenceInSequence()
{
$foo = [
'a' => 'Steve',
'b' => 'Clark',
'c' => 'Brian',
];
$this->assertSame([$foo], Inline::parse('[*foo]', 0, ['foo' => $foo]));
}
public function testParseUnquotedAsterisk()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('A reference must contain at least one character at line 1.');
Inline::parse('{ foo: * }');
}
public function testParseUnquotedAsteriskFollowedByAComment()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('A reference must contain at least one character at line 1.');
Inline::parse('{ foo: * #foo }');
}
/**
* @dataProvider getReservedIndicators
*/
public function testParseUnquotedScalarStartingWithReservedIndicator($indicator)
{
$this->expectException(ParseException::class);
$this->expectExceptionMessage(sprintf('cannot start a plain scalar; you need to quote the scalar at line 1 (near "%sfoo").', $indicator));
Inline::parse(sprintf('{ foo: %sfoo }', $indicator));
}
public function getReservedIndicators()
{
return [['@'], ['`']];
}
/**
* @dataProvider getScalarIndicators
*/
public function testParseUnquotedScalarStartingWithScalarIndicator($indicator)
{
$this->expectException(ParseException::class);
$this->expectExceptionMessage(sprintf('cannot start a plain scalar; you need to quote the scalar at line 1 (near "%sfoo").', $indicator));
Inline::parse(sprintf('{ foo: %sfoo }', $indicator));
}
public function getScalarIndicators()
{
return [['|'], ['>'], ['%']];
}
/**
* @dataProvider getDataForIsHash
*/
public function testIsHash($array, $expected)
{
$this->assertSame($expected, Inline::isHash($array));
}
public function getDataForIsHash()
{
return [
[[], false],
[[1, 2, 3], false],
[[2 => 1, 1 => 2, 0 => 3], true],
[['foo' => 1, 'bar' => 2], true],
];
}
public function getTestsForParse()
{
return [
['', ''],
['null', null],
['false', false],
['true', true],
['12', 12],
['-12', -12],
['1_2', 12],
['_12', '_12'],
['12_', 12],
['"quoted string"', 'quoted string'],
["'quoted string'", 'quoted string'],
['12.30e+02', 12.30e+02],
['123.45_67', 123.4567],
['0x4D2', 0x4D2],
['0x_4_D_2_', 0x4D2],
['02333', 02333],
['0_2_3_3_3', 02333],
['.Inf', -log(0)],
['-.Inf', log(0)],
["'686e444'", '686e444'],
['686e444', 646e444],
['123456789123456789123456789123456789', '123456789123456789123456789123456789'],
['"foo\r\nbar"', "foo\r\nbar"],
["'foo#bar'", 'foo#bar'],
["'foo # bar'", 'foo # bar'],
["'#cfcfcf'", '#cfcfcf'],
['::form_base.html.twig', '::form_base.html.twig'],
// Pre-YAML-1.2 booleans
["'y'", 'y'],
["'n'", 'n'],
["'yes'", 'yes'],
["'no'", 'no'],
["'on'", 'on'],
["'off'", 'off'],
['2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)],
['2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)],
['2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)],
['1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)],
['1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)],
['"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''],
["'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''],
// sequences
// urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon
['[foo, http://urls.are/no/mappings, false, null, 12]', ['foo', 'http://urls.are/no/mappings', false, null, 12]],
['[ foo , bar , false , null , 12 ]', ['foo', 'bar', false, null, 12]],
['[\'foo,bar\', \'foo bar\']', ['foo,bar', 'foo bar']],
// mappings
['{foo: bar,bar: foo,"false": false, "null": null,integer: 12}', ['foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12]],
['{ foo : bar, bar : foo, "false" : false, "null" : null, integer : 12 }', ['foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12]],
['{foo: \'bar\', bar: \'foo: bar\'}', ['foo' => 'bar', 'bar' => 'foo: bar']],
['{\'foo\': \'bar\', "bar": \'foo: bar\'}', ['foo' => 'bar', 'bar' => 'foo: bar']],
['{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', ['foo\'' => 'bar', 'bar"' => 'foo: bar']],
['{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}', ['foo: ' => 'bar', 'bar: ' => 'foo: bar']],
['{"foo:bar": "baz"}', ['foo:bar' => 'baz']],
['{"foo":"bar"}', ['foo' => 'bar']],
// nested sequences and mappings
['[foo, [bar, foo]]', ['foo', ['bar', 'foo']]],
['[foo, {bar: foo}]', ['foo', ['bar' => 'foo']]],
['{ foo: {bar: foo} }', ['foo' => ['bar' => 'foo']]],
['{ foo: [bar, foo] }', ['foo' => ['bar', 'foo']]],
['{ foo:{bar: foo} }', ['foo' => ['bar' => 'foo']]],
['{ foo:[bar, foo] }', ['foo' => ['bar', 'foo']]],
['[ foo, [ bar, foo ] ]', ['foo', ['bar', 'foo']]],
['[{ foo: {bar: foo} }]', [['foo' => ['bar' => 'foo']]]],
['[foo, [bar, [foo, [bar, foo]], foo]]', ['foo', ['bar', ['foo', ['bar', 'foo']], 'foo']]],
['[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]', ['foo', ['bar' => 'foo', 'foo' => ['foo', ['bar' => 'foo']]], ['foo', ['bar' => 'foo']]]],
['[foo, bar: { foo: bar }]', ['foo', '1' => ['bar' => ['foo' => 'bar']]]],
['[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', ['foo', '@foo.baz', ['%foo%' => 'foo is %foo%', 'bar' => '%foo%'], true, '@service_container']],
];
}
public function getTestsForParseWithMapObjects()
{
return [
['', ''],
['null', null],
['false', false],
['true', true],
['12', 12],
['-12', -12],
['"quoted string"', 'quoted string'],
["'quoted string'", 'quoted string'],
['12.30e+02', 12.30e+02],
['0x4D2', 0x4D2],
['02333', 02333],
['.Inf', -log(0)],
['-.Inf', log(0)],
["'686e444'", '686e444'],
['686e444', 646e444],
['123456789123456789123456789123456789', '123456789123456789123456789123456789'],
['"foo\r\nbar"', "foo\r\nbar"],
["'foo#bar'", 'foo#bar'],
["'foo # bar'", 'foo # bar'],
["'#cfcfcf'", '#cfcfcf'],
['::form_base.html.twig', '::form_base.html.twig'],
['2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)],
['2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)],
['2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)],
['1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)],
['1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)],
['"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''],
["'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''],
// sequences
// urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon
['[foo, http://urls.are/no/mappings, false, null, 12]', ['foo', 'http://urls.are/no/mappings', false, null, 12]],
['[ foo , bar , false , null , 12 ]', ['foo', 'bar', false, null, 12]],
['[\'foo,bar\', \'foo bar\']', ['foo,bar', 'foo bar']],
// mappings
['{foo: bar,bar: foo,"false": false,"null": null,integer: 12}', (object) ['foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12], Yaml::PARSE_OBJECT_FOR_MAP],
['{ foo : bar, bar : foo, "false" : false, "null" : null, integer : 12 }', (object) ['foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12], Yaml::PARSE_OBJECT_FOR_MAP],
['{foo: \'bar\', bar: \'foo: bar\'}', (object) ['foo' => 'bar', 'bar' => 'foo: bar']],
['{\'foo\': \'bar\', "bar": \'foo: bar\'}', (object) ['foo' => 'bar', 'bar' => 'foo: bar']],
['{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', (object) ['foo\'' => 'bar', 'bar"' => 'foo: bar']],
['{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}', (object) ['foo: ' => 'bar', 'bar: ' => 'foo: bar']],
['{"foo:bar": "baz"}', (object) ['foo:bar' => 'baz']],
['{"foo":"bar"}', (object) ['foo' => 'bar']],
// nested sequences and mappings
['[foo, [bar, foo]]', ['foo', ['bar', 'foo']]],
['[foo, {bar: foo}]', ['foo', (object) ['bar' => 'foo']]],
['{ foo: {bar: foo} }', (object) ['foo' => (object) ['bar' => 'foo']]],
['{ foo: [bar, foo] }', (object) ['foo' => ['bar', 'foo']]],
['[ foo, [ bar, foo ] ]', ['foo', ['bar', 'foo']]],
['[{ foo: {bar: foo} }]', [(object) ['foo' => (object) ['bar' => 'foo']]]],
['[foo, [bar, [foo, [bar, foo]], foo]]', ['foo', ['bar', ['foo', ['bar', 'foo']], 'foo']]],
['[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]', ['foo', (object) ['bar' => 'foo', 'foo' => ['foo', (object) ['bar' => 'foo']]], ['foo', (object) ['bar' => 'foo']]]],
['[foo, bar: { foo: bar }]', ['foo', '1' => (object) ['bar' => (object) ['foo' => 'bar']]]],
['[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', ['foo', '@foo.baz', (object) ['%foo%' => 'foo is %foo%', 'bar' => '%foo%'], true, '@service_container']],
['{}', new \stdClass()],
['{ foo : bar, bar : {} }', (object) ['foo' => 'bar', 'bar' => new \stdClass()]],
['{ foo : [], bar : {} }', (object) ['foo' => [], 'bar' => new \stdClass()]],
['{foo: \'bar\', bar: {} }', (object) ['foo' => 'bar', 'bar' => new \stdClass()]],
['{\'foo\': \'bar\', "bar": {}}', (object) ['foo' => 'bar', 'bar' => new \stdClass()]],
['{\'foo\': \'bar\', "bar": \'{}\'}', (object) ['foo' => 'bar', 'bar' => '{}']],
['[foo, [{}, {}]]', ['foo', [new \stdClass(), new \stdClass()]]],
['[foo, [[], {}]]', ['foo', [[], new \stdClass()]]],
['[foo, [[{}, {}], {}]]', ['foo', [[new \stdClass(), new \stdClass()], new \stdClass()]]],
['[foo, {bar: {}}]', ['foo', '1' => (object) ['bar' => new \stdClass()]]],
];
}
public function getTestsForDump()
{
return [
['null', null],
['false', false],
['true', true],
['12', 12],
["'1_2'", '1_2'],
['_12', '_12'],
["'12_'", '12_'],
["'quoted string'", 'quoted string'],
['!!float 1230', 12.30e+02],
['1234', 0x4D2],
['1243', 02333],
["'0x_4_D_2_'", '0x_4_D_2_'],
["'0_2_3_3_3'", '0_2_3_3_3'],
['.Inf', -log(0)],
['-.Inf', log(0)],
["'686e444'", '686e444'],
['"foo\r\nbar"', "foo\r\nbar"],
["'foo#bar'", 'foo#bar'],
["'foo # bar'", 'foo # bar'],
["'#cfcfcf'", '#cfcfcf'],
["'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''],
["'-dash'", '-dash'],
["'-'", '-'],
// Pre-YAML-1.2 booleans
["'y'", 'y'],
["'n'", 'n'],
["'yes'", 'yes'],
["'no'", 'no'],
["'on'", 'on'],
["'off'", 'off'],
// sequences
['[foo, bar, false, null, 12]', ['foo', 'bar', false, null, 12]],
['[\'foo,bar\', \'foo bar\']', ['foo,bar', 'foo bar']],
// mappings
['{ foo: bar, bar: foo, \'false\': false, \'null\': null, integer: 12 }', ['foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12]],
['{ foo: bar, bar: \'foo: bar\' }', ['foo' => 'bar', 'bar' => 'foo: bar']],
// nested sequences and mappings
['[foo, [bar, foo]]', ['foo', ['bar', 'foo']]],
['[foo, [bar, [foo, [bar, foo]], foo]]', ['foo', ['bar', ['foo', ['bar', 'foo']], 'foo']]],
['{ foo: { bar: foo } }', ['foo' => ['bar' => 'foo']]],
['[foo, { bar: foo }]', ['foo', ['bar' => 'foo']]],
['[foo, { bar: foo, foo: [foo, { bar: foo }] }, [foo, { bar: foo }]]', ['foo', ['bar' => 'foo', 'foo' => ['foo', ['bar' => 'foo']]], ['foo', ['bar' => 'foo']]]],
['[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', ['foo', '@foo.baz', ['%foo%' => 'foo is %foo%', 'bar' => '%foo%'], true, '@service_container']],
['{ foo: { bar: { 1: 2, baz: 3 } } }', ['foo' => ['bar' => [1 => 2, 'baz' => 3]]]],
];
}
/**
* @dataProvider getTimestampTests
*/
public function testParseTimestampAsUnixTimestampByDefault($yaml, $year, $month, $day, $hour, $minute, $second)
{
$this->assertSame(gmmktime($hour, $minute, $second, $month, $day, $year), Inline::parse($yaml));
}
/**
* @dataProvider getTimestampTests
*/
public function testParseTimestampAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second, $timezone)
{
$expected = new \DateTime($yaml);
$expected->setTimeZone(new \DateTimeZone('UTC'));
$expected->setDate($year, $month, $day);
$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second));
$date = Inline::parse($yaml, Yaml::PARSE_DATETIME);
$this->assertEquals($expected, $date);
$this->assertSame($timezone, $date->format('O'));
}
public function getTimestampTests()
{
return [
'canonical' => ['2001-12-15T02:59:43.1Z', 2001, 12, 15, 2, 59, 43.1, '+0000'],
'ISO-8601' => ['2001-12-15t21:59:43.10-05:00', 2001, 12, 16, 2, 59, 43.1, '-0500'],
'spaced' => ['2001-12-15 21:59:43.10 -5', 2001, 12, 16, 2, 59, 43.1, '-0500'],
'date' => ['2001-12-15', 2001, 12, 15, 0, 0, 0, '+0000'],
];
}
/**
* @dataProvider getTimestampTests
*/
public function testParseNestedTimestampListAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second)
{
$expected = new \DateTime($yaml);
$expected->setTimeZone(new \DateTimeZone('UTC'));
$expected->setDate($year, $month, $day);
$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second));
$expectedNested = ['nested' => [$expected]];
$yamlNested = "{nested: [$yaml]}";
$this->assertEquals($expectedNested, Inline::parse($yamlNested, Yaml::PARSE_DATETIME));
}
/**
* @dataProvider getDateTimeDumpTests
*/
public function testDumpDateTime($dateTime, $expected)
{
$this->assertSame($expected, Inline::dump($dateTime));
}
public function getDateTimeDumpTests()
{
$tests = [];
$dateTime = new \DateTime('2001-12-15 21:59:43', new \DateTimeZone('UTC'));
$tests['date-time-utc'] = [$dateTime, '2001-12-15T21:59:43+00:00'];
$dateTime = new \DateTimeImmutable('2001-07-15 21:59:43', new \DateTimeZone('Europe/Berlin'));
$tests['immutable-date-time-europe-berlin'] = [$dateTime, '2001-07-15T21:59:43+02:00'];
return $tests;
}
/**
* @dataProvider getBinaryData
*/
public function testParseBinaryData($data)
{
$this->assertSame('Hello world', Inline::parse($data));
}
public function getBinaryData()
{
return [
'enclosed with double quotes' => ['!!binary "SGVsbG8gd29ybGQ="'],
'enclosed with single quotes' => ["!!binary 'SGVsbG8gd29ybGQ='"],
'containing spaces' => ['!!binary "SGVs bG8gd 29ybGQ="'],
];
}
/**
* @dataProvider getInvalidBinaryData
*/
public function testParseInvalidBinaryData($data, $expectedMessage)
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessageRegExp($expectedMessage);
Inline::parse($data);
}
public function getInvalidBinaryData()
{
return [
'length not a multiple of four' => ['!!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'],
'invalid characters' => ['!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'],
'too many equals characters' => ['!!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'],
'misplaced equals character' => ['!!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'],
];
}
public function testNotSupportedMissingValue()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('Malformed inline YAML string: {this, is not, supported} at line 1.');
Inline::parse('{this, is not, supported}');
}
public function testVeryLongQuotedStrings()
{
$longStringWithQuotes = str_repeat("x\r\n\\\"x\"x", 1000);
$yamlString = Inline::dump(['longStringWithQuotes' => $longStringWithQuotes]);
$arrayFromYaml = Inline::parse($yamlString);
$this->assertEquals($longStringWithQuotes, $arrayFromYaml['longStringWithQuotes']);
}
public function testMappingKeysCannotBeOmitted()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('Missing mapping key');
Inline::parse('{: foo}');
}
/**
* @dataProvider getTestsForNullValues
*/
public function testParseMissingMappingValueAsNull($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml));
}
public function getTestsForNullValues()
{
return [
'null before closing curly brace' => ['{foo:}', ['foo' => null]],
'null before comma' => ['{foo:, bar: baz}', ['foo' => null, 'bar' => 'baz']],
];
}
public function testTheEmptyStringIsAValidMappingKey()
{
$this->assertSame(['' => 'foo'], Inline::parse('{ "": foo }'));
}
/**
* @dataProvider getNotPhpCompatibleMappingKeyData
*/
public function testImplicitStringCastingOfMappingKeysIsDeprecated($yaml, $expected)
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead');
$this->assertSame($expected, Inline::parse($yaml));
}
public function getNotPhpCompatibleMappingKeyData()
{
return [
'boolean-true' => ['{true: "foo"}', ['true' => 'foo']],
'boolean-false' => ['{false: "foo"}', ['false' => 'foo']],
'null' => ['{null: "foo"}', ['null' => 'foo']],
'float' => ['{0.25: "foo"}', ['0.25' => 'foo']],
];
}
public function testTagWithoutValueInSequence()
{
$value = Inline::parse('[!foo]', Yaml::PARSE_CUSTOM_TAGS);
$this->assertInstanceOf(TaggedValue::class, $value[0]);
$this->assertSame('foo', $value[0]->getTag());
$this->assertSame('', $value[0]->getValue());
}
public function testTagWithEmptyValueInSequence()
{
$value = Inline::parse('[!foo ""]', Yaml::PARSE_CUSTOM_TAGS);
$this->assertInstanceOf(TaggedValue::class, $value[0]);
$this->assertSame('foo', $value[0]->getTag());
$this->assertSame('', $value[0]->getValue());
}
public function testTagWithoutValueInMapping()
{
$value = Inline::parse('{foo: !bar}', Yaml::PARSE_CUSTOM_TAGS);
$this->assertInstanceOf(TaggedValue::class, $value['foo']);
$this->assertSame('bar', $value['foo']->getTag());
$this->assertSame('', $value['foo']->getValue());
}
public function testTagWithEmptyValueInMapping()
{
$value = Inline::parse('{foo: !bar ""}', Yaml::PARSE_CUSTOM_TAGS);
$this->assertInstanceOf(TaggedValue::class, $value['foo']);
$this->assertSame('bar', $value['foo']->getTag());
$this->assertSame('', $value['foo']->getValue());
}
public function testUnfinishedInlineMap()
{
$this->expectException('Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage('Unexpected end of line, expected one of ",}" at line 1 (near "{abc: \'def\'").');
Inline::parse("{abc: 'def'");
}
}

View File

@ -1,34 +0,0 @@
<?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\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Exception\ParseException;
class ParseExceptionTest extends TestCase
{
public function testGetMessage()
{
$exception = new ParseException('Error message', 42, 'foo: bar', '/var/www/app/config.yml');
$message = 'Error message in "/var/www/app/config.yml" at line 42 (near "foo: bar")';
$this->assertEquals($message, $exception->getMessage());
}
public function testGetMessageWithUnicodeInFilename()
{
$exception = new ParseException('Error message', 42, 'foo: bar', 'äöü.yml');
$message = 'Error message in "äöü.yml" at line 42 (near "foo: bar")';
$this->assertEquals($message, $exception->getMessage());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +0,0 @@
<?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\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;
class YamlTest extends TestCase
{
public function testParseAndDump()
{
$data = ['lorem' => 'ipsum', 'dolor' => 'sit'];
$yml = Yaml::dump($data);
$parsed = Yaml::parse($yml);
$this->assertEquals($data, $parsed);
}
public function testZeroIndentationThrowsException()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The indentation must be greater than zero');
Yaml::dump(['lorem' => 'ipsum', 'dolor' => 'sit'], 2, 0);
}
public function testNegativeIndentationThrowsException()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The indentation must be greater than zero');
Yaml::dump(['lorem' => 'ipsum', 'dolor' => 'sit'], 2, -4);
}
}

View File

@ -33,6 +33,7 @@ class Yaml
const PARSE_CONSTANT = 256;
const PARSE_CUSTOM_TAGS = 512;
const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
const DUMP_NULL_AS_TILDE = 2048;
/**
* Parses a YAML file into a PHP value.

View File

@ -20,7 +20,7 @@
"symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
"symfony/console": "~3.4|~4.0"
"symfony/console": "^3.4|^4.0|^5.0"
},
"conflict": {
"symfony/console": "<3.4"
@ -37,7 +37,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "4.3-dev"
"dev-master": "4.4-dev"
}
}
}

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony Yaml Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -1,3 +1,7 @@
* 2.12.2 (2019-11-11)
* added supported for exponential numbers
* 2.12.1 (2019-10-17)
* added the String extension in the "extra" repositories: "u" filter
@ -284,7 +288,7 @@
* 1.42.4 (2019-XX-XX)
* n/a
* added supported for exponential numbers
* 1.42.3 (2019-08-24)

View File

@ -70,7 +70,7 @@ For large strings manipulation, use the ``apply`` tag:
$ composer req twig/string-extra
Then, use the ``twig/extra-bundle`` on Symfony projects or add the extension
explictly on the Twig environment::
explicitly on the Twig environment::
use Twig\Extra\String\StringExtension;

View File

@ -38,11 +38,11 @@ use Twig\TokenParser\TokenParserInterface;
*/
class Environment
{
const VERSION = '2.12.1';
const VERSION_ID = 21201;
const VERSION = '2.12.2';
const VERSION_ID = 21202;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 12;
const RELEASE_VERSION = 1;
const RELEASE_VERSION = 2;
const EXTRA_VERSION = '';
private $charset;
@ -435,7 +435,7 @@ class Environment
*
* This method should not be used as a generic way to load templates.
*
* @param string $template The template name
* @param string $template The template source
* @param string $name An optional name of the template to be used in error messages
*
* @return TemplateWrapper A template instance representing the given template name

View File

@ -44,7 +44,7 @@ class Lexer
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A';
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';