Template::expand()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
/**
4
 * League.Uri (https://uri.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
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
declare(strict_types=1);
13
14
namespace League\Uri\UriTemplate;
15
16
use League\Uri\Exceptions\SyntaxError;
17
use League\Uri\Exceptions\TemplateCanNotBeExpanded;
18
use function array_merge;
19
use function array_unique;
20
use function gettype;
21
use function is_object;
22
use function is_string;
23
use function method_exists;
24
use function preg_match_all;
25
use function preg_replace;
26
use function sprintf;
27
use function strpos;
28
use const PREG_SET_ORDER;
29
30
final class Template
31
{
32
    /**
33
     * Expression regular expression pattern.
34
     */
35
    private const REGEXP_EXPRESSION_DETECTOR = '/\{[^\}]*\}/x';
36
37
    /**
38
     * @var string
39
     */
40
    private $template;
41
42
    /**
43
     * @var array<string, Expression>
44
     */
45
    private $expressions = [];
46
47
    /**
48
     * @var array<string>
49
     */
50
    private $variableNames;
51
52 18
    private function __construct(string $template, Expression ...$expressions)
53
    {
54 18
        $this->template = $template;
55 18
        $variableNames = [];
56 18
        foreach ($expressions as $expression) {
57 14
            $this->expressions[$expression->toString()] = $expression;
58 14
            $variableNames[] = $expression->variableNames();
59
        }
60 18
        $this->variableNames = array_unique(array_merge([], ...$variableNames));
61 18
    }
62
63
    /**
64
     * {@inheritDoc}
65
     */
66 2
    public static function __set_state(array $properties): self
67
    {
68 2
        return new self($properties['template'], ...array_values($properties['expressions']));
69
    }
70
71
    /**
72
     * @param object|string $template a string or an object with the __toString method
73
     *
74
     * @throws \TypeError  if the template is not a string or an object with the __toString method
75
     * @throws SyntaxError if the template contains invalid expressions
76
     * @throws SyntaxError if the template contains invalid variable specification
77
     */
78 34
    public static function createFromString($template): self
79
    {
80 34
        if (is_object($template) && method_exists($template, '__toString')) {
81
            $template = (string) $template;
82
        }
83
84 34
        if (!is_string($template)) {
85 2
            throw new \TypeError(sprintf('The template must be a string or a stringable object %s given.', gettype($template)));
86
        }
87
88
        /** @var string $remainder */
89 32
        $remainder = preg_replace(self::REGEXP_EXPRESSION_DETECTOR, '', $template);
90 32
        if (false !== strpos($remainder, '{') || false !== strpos($remainder, '}')) {
91 12
            throw new SyntaxError('The template "'.$template.'" contains invalid expressions.');
92
        }
93
94 20
        $names = [];
95 20
        preg_match_all(self::REGEXP_EXPRESSION_DETECTOR, $template, $findings, PREG_SET_ORDER);
96 20
        $arguments = [];
97 20
        foreach ($findings as $finding) {
98 16
            if (!isset($names[$finding[0]])) {
99 16
                $arguments[] = Expression::createFromString($finding[0]);
100 14
                $names[$finding[0]] = 1;
101
            }
102
        }
103
104 18
        return new self($template, ...$arguments);
105
    }
106
107 4
    public function toString(): string
108
    {
109 4
        return $this->template;
110
    }
111
112
    /**
113
     * @return array<string>
114
     */
115 18
    public function variableNames(): array
116
    {
117 18
        return $this->variableNames;
118
    }
119
120
    /**
121
     * @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
122
     * @throws TemplateCanNotBeExpanded if the variables contains nested array values
123
     */
124 12
    public function expand(VariableBag $variables): string
125
    {
126 12
        $uriString = $this->template;
127
        /** @var Expression $expression */
128 12
        foreach ($this->expressions as $pattern => $expression) {
129 10
            $uriString = str_replace($pattern, $expression->expand($variables), $uriString);
130
        }
131
132 12
        return $uriString;
133
    }
134
}
135