You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While basic template interpolation is useful, we know that a one-size-fits-all
stringification approach isn't always desirable. Sometimes you need to bypass the
standard formatting logic or transform a value before it hits the final string.
This commit introduces a flexible modifier system to solve that.
I’ve adopted the familiar `{{value|modifier}}` syntax found in many popular
template engines. To handle this transformation, I implemented a Chain of
Responsibility pattern. This allows us to pipe values through specific logic,
such as the new `|raw` modifier, which provides clean scalar output by
bypassing the default stringifier formatting.
The `StringifyModifier` remains the default fallback, ensuring that we don't
lose the robust type-handling we previously built. By separating these
transformations into an extensible modifier interface, we’ve made the system
future-proof—users can now plug in custom transformations without touching
the core formatting logic.
This change turns our simple placeholder replacement into a proper
interpolation engine, giving developers fine-grained control over how their
data is presented.
Assisted-by: OpenCode (GLM-4.6)
echo $formatter->format('Hello {{name}}, you are {{age}} years old.');
33
+
// Outputs: "Hello --John--, you are --30-- years old."
34
+
```
35
+
36
+
### Modifiers
37
+
38
+
Placeholders can include modifiers that transform values before final stringification. See the [Modifiers](modifiers/Modifiers.md) documentation for complete details.
39
+
40
+
```php
41
+
use Respect\StringFormatter\PlaceholderFormatter;
42
+
use Respect\StringFormatter\Modifier\RawModifier;
43
+
use Respect\StringFormatter\Modifier\StringifyModifier;
44
+
45
+
$formatter = new PlaceholderFormatter(['name' => 'John', 'age' => 30]);
46
+
47
+
echo $formatter->format('Hello {{name|raw}}, you are {{age}} years old.');
48
+
// Outputs: "Hello John, you are 30 years old."
34
49
```
35
50
51
+
**Available Topics:**
52
+
53
+
-[Modifiers Overview](modifiers/Modifiers.md) - How modifiers work and basic usage
54
+
-[RawModifier](modifiers/RawModifier.md) - Outputs scalar values without stringifier formatting
55
+
-[StringifyModifier](modifiers/StringifyModifier.md) - Default modifier using stringifier
56
+
-[Creating Custom Modifiers](modifiers/CreatingCustomModifiers.md) - Build your own modifiers
57
+
36
58
### Using Additional Parameters
37
59
38
60
The `formatWith` method allows passing additional parameters at format time. Constructor parameters take precedence and won't be overwritten.
Creates a new formatter instance with the specified parameters and stringifier.
82
+
Creates a new formatter instance with the specified parameters and optional modifier chain.
61
83
62
84
**Parameters:**
63
85
64
86
-`$parameters`: Associative array of placeholder names to values
65
-
-`$stringifier`: Stringifier instance for converting all non-string values to strings. If `null`, it creates its own stringifier.
87
+
-`$modifier`: Optional modifier chain for processing values before final stringification. If `null`, uses a default `RawModifier` with `StringifyModifier`. See [Modifiers](modifiers/Modifiers.md) for details.
88
+
89
+
The formatter internally uses `HandlerStringifier::create()` for stringifying non-string values.
66
90
67
91
### `format`
68
92
@@ -99,57 +123,48 @@ Formats the template string with additional parameters merged with constructor p
99
123
100
124
### Placeholder Format
101
125
102
-
Placeholders follow the format `{{name}}` where `name` is a valid parameter key.
126
+
Placeholders follow the format `{{name}}` where `name` is a valid parameter key. Modifiers can be added after a pipe: `{{name|modifier}}`. See [Modifiers](modifiers/Modifiers.md) for complete modifier documentation.
103
127
104
128
**Rules:**
105
129
106
130
- Placeholder names must match the regex pattern `\w+` (word characters: letters, digits, underscore)
107
131
- Names are case-sensitive: `{{Name}}` and `{{name}}` are different placeholders
108
132
- Placeholders can appear multiple times in the template
109
133
- Whitespace inside braces is not allowed: `{{ name }}` will not match
134
+
- No whitespace is allowed between the pipe and modifier name: `{{name| raw}}` will not work
110
135
111
136
**Valid placeholders:**
112
137
113
138
-`{{name}}`
114
139
-`{{firstName}}`
115
140
-`{{value123}}`
116
141
-`{{user_id}}`
142
+
-`{{name|raw}}`
143
+
-`{{count|raw}}`
117
144
118
145
**Invalid placeholders (treated as literals):**
119
146
120
147
-`{name}` (single braces)
121
148
-`{{ name }}` (contains spaces)
122
149
-`{{first-name}}` (contains hyphen)
123
150
-`{{}}` (empty)
151
+
-`{{name| raw}}` (space after pipe)
124
152
125
153
## Type Handling
126
154
127
-
The formatter uses the injected `Stringifier` to convert all parameter values to strings:
The formatter uses the injected `Stringifier` to convert all parameter values to strings. See the [Respect\Stringifier](https://github.com/Respect/Stringifier) documentation for details on type conversions.
141
156
142
157
## Behavior
143
158
144
159
### Successful Replacement
145
160
146
161
When a placeholder name exists as a parameter key:
147
162
148
-
- The placeholder is replaced with the stringified value (using the injected `Stringifier`)
149
-
- String values are used as-is without stringification
150
-
- All non-string values (including `null`) are converted using the stringifier
163
+
- The placeholder is replaced with the value processed through the modifier pipe
164
+
- All values (including `null`) are converted using the default `HandlerStringifier` unless a modifier handles them differently
151
165
- Empty strings are valid replacements: `""` replaces the placeholder with nothing
152
166
- Zero values are valid: `0` and `0.0` are replaced with their string representations
167
+
- Modifiers can transform values: `{{count|raw}}` outputs the raw scalar value without stringifier formatting (see [Modifiers](modifiers/Modifiers.md))
0 commit comments