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

Skip to content

Commit a29789e

Browse files
committed
Add tags support
1 parent e6bd47e commit a29789e

File tree

6 files changed

+190
-4
lines changed

6 files changed

+190
-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: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
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;
1617

1718
/**
@@ -26,6 +27,7 @@ class Inline
2627
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
2728

2829
public static $parsedLineNumber;
30+
public static $tagResolver;
2931

3032
private static $exceptionOnInvalidType = false;
3133
private static $objectSupport = false;
@@ -659,9 +661,22 @@ private static function evaluateScalar($scalar, $flags, $references = array())
659661

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

667682
/**

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;
@@ -386,6 +406,7 @@ private function parseBlock($offset, $yaml, $flags)
386406

387407
$parser = new self($offset, $this->totalNumberOfLines, $skippedLineNumbers);
388408
$parser->refs = &$this->refs;
409+
$parser->tagResolver = $this->tagResolver;
389410

390411
return $parser->parse($yaml, $flags);
391412
}
@@ -599,8 +620,18 @@ private function parseValue($value, $flags, $context)
599620

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

602-
if (isset($matches['tag']) && '!!binary' === $matches['tag']) {
603-
return Inline::evaluateBinaryScalar($data);
623+
if (isset($matches['tag'])) {
624+
if ('!!binary' === $matches['tag']) {
625+
return Inline::evaluateBinaryScalar($data);
626+
}
627+
628+
$tag = substr($matches['tag'], 1);
629+
630+
try {
631+
return $this->tagResolver->resolve($data, $tag);
632+
} catch (UnsupportedTagException $e) {
633+
// ignored for bc
634+
}
604635
}
605636

606637
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
{
@@ -1491,9 +1492,35 @@ public function testParseMultiLineMappingValue()
14911492

14921493
$this->assertEquals($expected, $this->parser->parse($yaml));
14931494
}
1495+
1496+
public function testCustomTagSupport()
1497+
{
1498+
$this->parser->addTag(new FooTag());
1499+
1500+
$this->assertSame('bar', $this->parser->parse('!foo'));
1501+
}
14941502
}
14951503

14961504
class B
14971505
{
14981506
public $b = 'foo';
14991507
}
1508+
1509+
class FooTag implements TagInterface
1510+
{
1511+
/**
1512+
* {@inheritdoc}
1513+
*/
1514+
public function construct($value, $tag)
1515+
{
1516+
return 'bar';
1517+
}
1518+
1519+
/**
1520+
* {@inheritdoc}
1521+
*/
1522+
public function supports($value, $tag)
1523+
{
1524+
return 'foo' === $tag;
1525+
}
1526+
}

0 commit comments

Comments
 (0)
0