Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
105 / 105 |
|
89.71% |
61 / 68 |
|
30.00% |
21 / 70 |
|
55.56% |
5 / 9 |
CRAP | |
0.00% |
0 / 1 |
| Placeholders | |
100.00% |
105 / 105 |
|
89.71% |
61 / 68 |
|
30.00% |
21 / 70 |
|
100.00% |
9 / 9 |
257.87 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| compileSql | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| normalizeConfig | |
100.00% |
16 / 16 |
|
100.00% |
12 / 12 |
|
60.00% |
6 / 10 |
|
100.00% |
1 / 1 |
8.30 | |||
| normalizeValues | |
100.00% |
18 / 18 |
|
88.89% |
16 / 18 |
|
20.00% |
4 / 20 |
|
100.00% |
1 / 1 |
24.43 | |||
| substituteFragment | |
100.00% |
22 / 22 |
|
87.50% |
14 / 16 |
|
13.64% |
3 / 22 |
|
100.00% |
1 / 1 |
21.10 | |||
| assertNoMalformedTokens | |
100.00% |
7 / 7 |
|
83.33% |
10 / 12 |
|
20.00% |
2 / 10 |
|
100.00% |
1 / 1 |
7.61 | |||
| unknownPlaceholder | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| malformedPlaceholder | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| location | |
100.00% |
7 / 7 |
|
83.33% |
5 / 6 |
|
50.00% |
2 / 4 |
|
100.00% |
1 / 1 |
2.50 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celemas\Quma; |
| 6 | |
| 7 | use InvalidArgumentException; |
| 8 | use RuntimeException; |
| 9 | |
| 10 | final class Placeholders |
| 11 | { |
| 12 | public const string NAME_PATTERN = '[A-Za-z_][A-Za-z0-9_.:-]*'; |
| 13 | |
| 14 | /** @var non-empty-string */ |
| 15 | private readonly string $tokenPattern; |
| 16 | |
| 17 | /** @var non-empty-string */ |
| 18 | private readonly string $tokenStartPattern; |
| 19 | |
| 20 | /** @var array<string, string> */ |
| 21 | private readonly array $values; |
| 22 | |
| 23 | /** @param array<array-key, mixed> $config */ |
| 24 | public function __construct( |
| 25 | private readonly string $driver, |
| 26 | array $config, |
| 27 | private readonly Delimiters $delimiters, |
| 28 | ) { |
| 29 | $open = preg_quote($this->delimiters->open, '/'); |
| 30 | $close = preg_quote($this->delimiters->close, '/'); |
| 31 | $this->tokenPattern = '/' . $open . '(' . self::NAME_PATTERN . ')' . $close . '/'; |
| 32 | $this->tokenStartPattern = '/^' . $open . '(' . self::NAME_PATTERN . ')' . $close . '/'; |
| 33 | |
| 34 | $normalized = $this->normalizeConfig($config); |
| 35 | $this->values = array_replace( |
| 36 | $normalized['all'] ?? [], |
| 37 | $normalized[$this->driver] ?? [], |
| 38 | ); |
| 39 | } |
| 40 | |
| 41 | public function compileSql(string $source, string $path): string |
| 42 | { |
| 43 | return $this->substituteFragment($source, $path, $source, 0); |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * @param array<array-key, mixed> $config |
| 48 | * |
| 49 | * @return array<string, array<string, string>> |
| 50 | */ |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 75 | } |
| 76 | |
| 77 | return $normalized; |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * @param array<array-key, mixed> $values |
| 82 | * |
| 83 | * @return array<string, string> |
| 84 | */ |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 115 | |
| 116 | private function substituteFragment( |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 133 | return $fragment; |
| 134 | } |
| 135 | |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 156 | |
| 157 | private function assertNoMalformedTokens( |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 171 | } |
| 172 | |
| 173 | $offset = $position + strlen($matches[0]); |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | private function unknownPlaceholder( |
| 178 | string $placeholder, |
| 179 | string $name, |
| 180 | string $path, |
| 181 | string $source, |
| 182 | int $offset, |
| 183 | ): RuntimeException { |
| 184 | [$line, $column] = $this->location($source, $offset); |
| 185 | |
| 186 | return new RuntimeException( |
| 187 | "Unknown static placeholder {$placeholder} in {$path}:{$line}:{$column} for driver \"{$this->driver}\".\n" |
| 188 | . "No value was configured for \"{$name}\".\n" |
| 189 | . "Add placeholders['all']['{$name}'] or placeholders['{$this->driver}']['{$name}'].\n" |
| 190 | . 'Static placeholders are raw SQL fragments. Use them only for trusted configuration, never for user input.', |
| 191 | ); |
| 192 | } |
| 193 | |
| 194 | private function malformedPlaceholder(string $path, string $source, int $offset): RuntimeException |
| 195 | { |
| 196 | [$line, $column] = $this->location($source, $offset); |
| 197 | |
| 198 | return new RuntimeException( |
| 199 | "Malformed static placeholder in {$path}:{$line}:{$column}.\n" |
| 200 | . 'Expected ' |
| 201 | . $this->delimiters->token('name') |
| 202 | . ' where name matches: ' |
| 203 | . self::NAME_PATTERN |
| 204 | . ".\n" |
| 205 | . 'Examples: ' |
| 206 | . $this->delimiters->token('prefix') |
| 207 | . ', ' |
| 208 | . $this->delimiters->token('schema.name') |
| 209 | . ', ' |
| 210 | . $this->delimiters->token('tenant-prefix') |
| 211 | . ', ' |
| 212 | . $this->delimiters->token('cms:prefix') |
| 213 | . '.', |
| 214 | ); |
| 215 | } |
| 216 | |
| 217 | /** @return array{0: int, 1: int} */ |
| 218 | private function location(string $source, int $offset): array |
| 219 | { |
| 220 | $before = substr($source, 0, $offset); |
| 221 | $line = substr_count($before, "\n") + 1; |
| 222 | $lineStart = strrpos($before, "\n"); |
| 223 | $column = $offset + 1; |
| 224 | |
| 225 | if ($lineStart !== false) { |
| 226 | $column = $offset - $lineStart; |
| 227 | } |
| 228 | |
| 229 | return [$line, $column]; |
| 230 | } |
| 231 | } |
Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not
necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once.
Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 25 | private readonly string $driver, |
| 26 | array $config, |
| 27 | private readonly Delimiters $delimiters, |
| 28 | ) { |
| 29 | $open = preg_quote($this->delimiters->open, '/'); |
| 30 | $close = preg_quote($this->delimiters->close, '/'); |
| 31 | $this->tokenPattern = '/' . $open . '(' . self::NAME_PATTERN . ')' . $close . '/'; |
| 32 | $this->tokenStartPattern = '/^' . $open . '(' . self::NAME_PATTERN . ')' . $close . '/'; |
| 33 | |
| 34 | $normalized = $this->normalizeConfig($config); |
| 35 | $this->values = array_replace( |
| 36 | $normalized['all'] ?? [], |
| 37 | $normalized[$this->driver] ?? [], |
| 38 | ); |
| 39 | } |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 175 | } |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 171 | } |
| 172 | |
| 173 | $offset = $position + strlen($matches[0]); |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 175 | } |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 171 | } |
| 172 | |
| 173 | $offset = $position + strlen($matches[0]); |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 175 | } |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 175 | } |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 171 | } |
| 172 | |
| 173 | $offset = $position + strlen($matches[0]); |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 175 | } |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 158 | string $fragment, |
| 159 | string $path, |
| 160 | string $source, |
| 161 | int $baseOffset, |
| 162 | ): void { |
| 163 | $offset = 0; |
| 164 | |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 166 | $matches = []; |
| 167 | $tail = substr($fragment, $position); |
| 168 | |
| 169 | if (preg_match($this->tokenStartPattern, $tail, $matches) !== 1) { |
| 170 | throw $this->malformedPlaceholder($path, $source, $baseOffset + $position); |
| 171 | } |
| 172 | |
| 173 | $offset = $position + strlen($matches[0]); |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 165 | while (($position = strpos($fragment, $this->delimiters->open, $offset)) !== false) { |
| 175 | } |
| 41 | public function compileSql(string $source, string $path): string |
| 42 | { |
| 43 | return $this->substituteFragment($source, $path, $source, 0); |
| 44 | } |
| 218 | private function location(string $source, int $offset): array |
| 219 | { |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 221 | $line = substr_count($before, "\n") + 1; |
| 222 | $lineStart = strrpos($before, "\n"); |
| 223 | $column = $offset + 1; |
| 224 | |
| 225 | if ($lineStart !== false) { |
| 226 | $column = $offset - $lineStart; |
| 227 | } |
| 228 | |
| 229 | return [$line, $column]; |
| 229 | return [$line, $column]; |
| 230 | } |
| 218 | private function location(string $source, int $offset): array |
| 219 | { |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 221 | $line = substr_count($before, "\n") + 1; |
| 222 | $lineStart = strrpos($before, "\n"); |
| 223 | $column = $offset + 1; |
| 224 | |
| 225 | if ($lineStart !== false) { |
| 229 | return [$line, $column]; |
| 230 | } |
| 218 | private function location(string $source, int $offset): array |
| 219 | { |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 221 | $line = substr_count($before, "\n") + 1; |
| 222 | $lineStart = strrpos($before, "\n"); |
| 223 | $column = $offset + 1; |
| 224 | |
| 225 | if ($lineStart !== false) { |
| 226 | $column = $offset - $lineStart; |
| 227 | } |
| 228 | |
| 229 | return [$line, $column]; |
| 229 | return [$line, $column]; |
| 230 | } |
| 218 | private function location(string $source, int $offset): array |
| 219 | { |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 220 | $before = substr($source, 0, $offset); |
| 221 | $line = substr_count($before, "\n") + 1; |
| 222 | $lineStart = strrpos($before, "\n"); |
| 223 | $column = $offset + 1; |
| 224 | |
| 225 | if ($lineStart !== false) { |
| 229 | return [$line, $column]; |
| 230 | } |
| 194 | private function malformedPlaceholder(string $path, string $source, int $offset): RuntimeException |
| 195 | { |
| 196 | [$line, $column] = $this->location($source, $offset); |
| 197 | |
| 198 | return new RuntimeException( |
| 199 | "Malformed static placeholder in {$path}:{$line}:{$column}.\n" |
| 200 | . 'Expected ' |
| 201 | . $this->delimiters->token('name') |
| 202 | . ' where name matches: ' |
| 203 | . self::NAME_PATTERN |
| 204 | . ".\n" |
| 205 | . 'Examples: ' |
| 206 | . $this->delimiters->token('prefix') |
| 207 | . ', ' |
| 208 | . $this->delimiters->token('schema.name') |
| 209 | . ', ' |
| 210 | . $this->delimiters->token('tenant-prefix') |
| 211 | . ', ' |
| 212 | . $this->delimiters->token('cms:prefix') |
| 213 | . '.', |
| 214 | ); |
| 215 | } |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 62 | if ($scope === 'default') { |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 62 | if ($scope === 'default') { |
| 68 | if (!is_array($values)) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 75 | } |
| 76 | |
| 77 | return $normalized; |
| 78 | } |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 62 | if ($scope === 'default') { |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 62 | if ($scope === 'default') { |
| 68 | if (!is_array($values)) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 75 | } |
| 76 | |
| 77 | return $normalized; |
| 78 | } |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 75 | } |
| 76 | |
| 77 | return $normalized; |
| 78 | } |
| 51 | private function normalizeConfig(array $config): array |
| 52 | { |
| 53 | $normalized = []; |
| 54 | |
| 55 | foreach ($config as $scope => $values) { |
| 55 | foreach ($config as $scope => $values) { |
| 56 | if (!is_string($scope) || $scope === '') { |
| 57 | throw new InvalidArgumentException( |
| 58 | 'Static placeholder scopes must be non-empty strings.', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | if ($scope === 'default') { |
| 63 | throw new InvalidArgumentException( |
| 64 | "Static placeholders use the shared scope 'all'. Replace placeholders['default'] with placeholders['all'].", |
| 65 | ); |
| 66 | } |
| 67 | |
| 68 | if (!is_array($values)) { |
| 69 | throw new InvalidArgumentException( |
| 70 | "Static placeholders for scope '{$scope}' must be an array of string values.", |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | $normalized[$scope] = $this->normalizeValues($scope, $values); |
| 75 | } |
| 76 | |
| 77 | return $normalized; |
| 78 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 98 | if (!is_string($value)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 85 | private function normalizeValues(string $scope, array $values): array |
| 86 | { |
| 87 | $normalized = []; |
| 88 | |
| 89 | foreach ($values as $name => $value) { |
| 89 | foreach ($values as $name => $value) { |
| 90 | if (!is_string($name) || !preg_match('/^' . self::NAME_PATTERN . '$/', $name)) { |
| 91 | throw new InvalidArgumentException( |
| 92 | "Invalid static placeholder name in scope '{$scope}'. Names must match " |
| 93 | . self::NAME_PATTERN |
| 94 | . '.', |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | if (!is_string($value)) { |
| 99 | throw new InvalidArgumentException( |
| 100 | "Static placeholder '{$name}' in scope '{$scope}' must be a string.", |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | if (str_contains($value, $this->delimiters->open)) { |
| 105 | throw new InvalidArgumentException( |
| 106 | "Static placeholder '{$name}' in scope '{$scope}' must not contain another static placeholder.", |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | $normalized[$name] = $value; |
| 111 | } |
| 112 | |
| 113 | return $normalized; |
| 114 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 133 | return $fragment; |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 133 | return $fragment; |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 117 | string $fragment, |
| 118 | string $path, |
| 119 | string $source, |
| 120 | int $baseOffset, |
| 121 | ): string { |
| 122 | $this->assertNoMalformedTokens($fragment, $path, $source, $baseOffset); |
| 123 | |
| 124 | $matches = []; |
| 125 | $result = preg_match_all( |
| 126 | $this->tokenPattern, |
| 127 | $fragment, |
| 128 | $matches, |
| 129 | PREG_SET_ORDER | PREG_OFFSET_CAPTURE, |
| 130 | ); |
| 131 | |
| 132 | if ($result === false || $result === 0) { |
| 132 | if ($result === false || $result === 0) { |
| 136 | $compiled = ''; |
| 137 | $cursor = 0; |
| 138 | |
| 139 | foreach ($matches as $match) { |
| 139 | foreach ($matches as $match) { |
| 140 | $placeholder = $match[0][0]; |
| 141 | $offset = $match[0][1]; |
| 142 | $name = $match[1][0]; |
| 143 | |
| 144 | $compiled .= substr($fragment, $cursor, $offset - $cursor); |
| 145 | |
| 146 | if (!array_key_exists($name, $this->values)) { |
| 147 | throw $this->unknownPlaceholder($placeholder, $name, $path, $source, $baseOffset + $offset); |
| 148 | } |
| 149 | |
| 150 | $compiled .= $this->values[$name]; |
| 151 | $cursor = $offset + strlen($placeholder); |
| 152 | } |
| 153 | |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 154 | return $compiled . substr($fragment, $cursor); |
| 155 | } |
| 178 | string $placeholder, |
| 179 | string $name, |
| 180 | string $path, |
| 181 | string $source, |
| 182 | int $offset, |
| 183 | ): RuntimeException { |
| 184 | [$line, $column] = $this->location($source, $offset); |
| 185 | |
| 186 | return new RuntimeException( |
| 187 | "Unknown static placeholder {$placeholder} in {$path}:{$line}:{$column} for driver \"{$this->driver}\".\n" |
| 188 | . "No value was configured for \"{$name}\".\n" |
| 189 | . "Add placeholders['all']['{$name}'] or placeholders['{$this->driver}']['{$name}'].\n" |
| 190 | . 'Static placeholders are raw SQL fragments. Use them only for trusted configuration, never for user input.', |
| 191 | ); |
| 192 | } |