10000 Add tags support · symfony/symfony@5951921 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5951921

Browse files
committed
Add tags support
1 parent 7bc268e commit 5951921

File tree

6 files changed

+191 8000
-4
lines changed

6 files changed

+191
-4
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Yaml\Exception;
13+
14+
/**
15+
* @author Guilhem N. <egetick@gmail.com>
16+
*
17+
* @internal
18+
*/
19+
class UnsupportedTagException extends ParseException
20+
{
21+
}

src/Symfony/Component/Yaml/Inline.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
namespace Symfony\Component\Yaml;
1313

1414
use Symfony\Component\Yaml\Exception\ParseException;
15+
use Symfony\Component\Yaml\Exception\UnsupportedTagException;
1516
use Symfony\Component\Yaml\Exception\DumpException;
17+
use Symfony\Component\Yaml\Tag\TagResolver;
1618

1719
/**
1820
* Inline implements a YAML parser/dumper for the YAML inline syntax.
@@ -26,6 +28,7 @@ class Inline
2628
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
2729

2830
public static $parsedLineNumber;
31+
public static $tagResolver;
2932

3033
private static $exceptionOnInvalidType = false;
3134
private static $objectSupport = false;
@@ -659,9 +662,22 @@ private static function evaluateScalar($scalar, $flags, $references = array())
659662

660663
return $time;
661664
}
662-
default:
663-
return (string) $scalar;
664665
}
666+
667+
if (null !== self::$tagResolver && $scalar && '!' === $scalar[0]) {
668+
$tagLength = strcspn($scalar, " \t", 1);
669+
$tag = substr($scalar, 1, $tagLength);
670+
$i = 0;
671+
$scalar = self::parseScalar(ltrim(substr($scalar, $tagLength)), $flags, null, array('"', "'"), $i, false, $references);
672+
673+
try {
674+
return self::$tagResolver->resolve($scalar, $tag);
675+
} catch (UnsupportedTagException $e) {
676+
// Ignored for bc
677+
}
678+
}
679+
680+
return (string) $scalar;
665681
}
666682

667683
/**

src/Symfony/Component/Yaml/Parser.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
namespace Symfony\Component\Yaml;
1313

1414
use Symfony\Component\Yaml\Exception\ParseException;
15+
use Symfony\Component\Yaml\Exception\UnsupportedTagException;
16+
use Symfony\Component\Yaml\Tag\TagInterface;
17+
use Symfony\Component\Yaml\Tag\TagResolver;
1518

1619
/**
1720
* Parser parses YAML strings to convert them to PHP arrays.
@@ -31,6 +34,7 @@ class Parser
3134
private $refs = array();
3235
private $skippedLineNumbers = array();
3336
private $locallySkippedLineNumbers = array();
37+
private $tagResolver;
3438

3539
/**
3640
* Constructor.
@@ -44,6 +48,12 @@ public function __construct($offset = 0, $totalNumberOfLines = null, array $skip
4448
$this->offset = $offset;
4549
$this->totalNumberOfLines = $totalNumberOfLines;
4650
$this->skippedLineNumbers = $skippedLineNumbers;
51+
$this->tagResolver = new TagResolver();
52+
}
53+
54+
public function addTag(TagInterface $tag, $priority = 0)
55+
{
56+
$this->tagResolver->addTag($tag);
4757
}
4858

4959
/**
@@ -101,6 +111,16 @@ public function parse($value, $flags = 0)
101111
mb_internal_encoding('UTF-8');
102112
}
103113

114+
Inline::$tagResolver = $this->tagResolver;
115+
try {
116+
return $this->doParse($value, $flags);
117+
} finally {
118+
Inline::$tagResolver = null;
119+
}
120+
}
121+
122+
private function doParse($value, $flags)
123+
{
104124
$data = array();
105125
$context = null;
106126
$allowOverwrite = false;
@@ -350,6 +370,7 @@ private function parseBlock($offset, $yaml, $flags)
350370

351371
$parser = new self($offset, $this->totalNumberOfLines, $skippedLineNumbers);
352372
$parser->refs = &$this->refs;
373+
$parser->tagResolver = $this->tagResolver;
353374

354375
return $parser->parse($yaml, $flags);
355376
}
@@ -563,8 +584,18 @@ private function parseValue($value, $flags, $context)
563584

564585
$data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
565586

566-
if (isset($matches['tag']) && '!!binary' === $matches['tag']) {
567-
return Inline::evaluateBinaryScalar($data);
587+
if (isset($matches['tag'])) {
588+
if ('!!binary' === $matches['tag']) {
589+
return Inline::evaluateBinaryScalar($data);
590+
}
591+
592+
$tag = substr($matches['tag'], 1);
593+
594+
try {
595+
return $this->tagResolver->resolve($data, $tag);
596+
} catch (UnsupportedTagException $e) {
597+
// ignored for bc
598+
}
568599
}
569600

570601
return $data;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Yaml\Tag;
13+
14+
/**
15+
* @author Guilhem N. <egetick@gmail.com>
16+
*/
17+
interface TagInterface
18+
{
19+
/**
20+
* @param mixed $value
21+
* @param string $tag
22+
*
23+
* @return mixed
24+
*/
25+
public function construct($value, $tag);
26+
27+
/**
28+
* @param mixed $value
29+
* @param string $tag
30+
*
31+
* @return bool
32+
*/
33+
public function supports($value, $tag);
34+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Yaml\Tag;
13+
14+
use Symfony\Component\Yaml\Yaml;
15+
use Symfony\Component\Yaml\Exception\UnsupportedTagException;
16+
17+
/**
18+
* @author Guilhem N. <egetick@gmail.com>
19+
*
20+
* @internal
21+
*/
22+
final class TagResolver
23+
{
24+
private $tags = array();
25+
26+
public function addTag(TagInterface $tag, $priority = 0)
27+
{
28+
if (!isset($this->tags[$priority])) {
29+
$this->tags[$priority] = array();
30+
krsort($this->tags);
31+
}
32+
33+
$this->tags[$priority][] = $tag;
34+
}
35+
36+
public function resolve($value, $tag)
37+
{
38+
$tag = $this->prefixTag($tag);
39+
foreach ($this->tags as $registeredTags) {
40+
foreach ($registeredTags as $registeredTag) {
41+
if ($registeredTag->supports($value, $tag)) {
42+
return $registeredTag->construct($value, $tag);
43+
}
44+
}
45+
}
46+
47+
throw new UnsupportedTagException(sprintf('Tag "%s" used with value "%s" is not supported', $tag, $value));
48+
}
49+
50+
private function prefixTag($tag)
51+
{
52+
if ($tag && '!' === $tag[0]) {
53+
$tag = 'tag:yaml.org,2002:'.substr($tag, 1);
54+
}
55+
56+
return $tag;
57+
}
58+
}

src/Symfony/Component/Yaml/Tests/ParserTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Yaml\Yaml;
1515
use Symfony\Component\Yaml\Parser;
16+
use Symfony\Component\Yaml\Tag\TagInterface;
1617

1718
class ParserTest extends \PHPUnit_Framework_TestCase
1819
{
@@ -1449,9 +1450,35 @@ public function testParseMultiLineUnquotedString()
14491450

14501451
$this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml));
14511452
}
1453+
1454+
public function testCustomTagSupport()
1455+
{
1456+
$this->parser->addTag(new FooTag());
1457+
1458+
$this->assertSame('bar', $this->parser->parse('!foo'));
1459+
}
14521460
}
14531461

14541462
class B
14551463
{
14561464
public $b = 'foo';
14571465
}
1466+
1467+
class FooTag implements TagInterface
1468+
{
1469+
/**
1470+
* {@inheritdoc}
1471+
*/
1472+
public function construct($value, $tag)
1473+
{
1474+
return 'bar';
1475+
}
1476+
1477+
/**
1478+
* {@inheritdoc}
1479+
*/
1480+
public function supports($value, $tag)
1481+
{
1482+
return 'foo' === $tag;
1483+
}
1484+
}

0 commit comments

Comments
 (0)
0