Skip to content

Commit fd791b5

Browse files
committed
DOC Document changes to template layer
1 parent 0774f54 commit fd791b5

27 files changed

+380
-165
lines changed

en/00_Getting_Started/04_Directory_Structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ We use `app/` as the default folder.
3232
| `app/_config` | YAML configuration specific to your application |
3333
| `app/src` | PHP code specific to your application (subdirectories are optional) |
3434
| `app/tests` | PHP unit/functional/end-to-end tests |
35-
| `app/templates` | HTML [templates](/developer_guides/templates) with `*.ss-extension` for the `$default` theme |
35+
| `app/templates` | [templates](/developer_guides/templates) for the `$default` theme |
3636
| `app/client/src` | Conventional directory for source resources (images/CSS/JavaScript) for your CMS customisations |
3737
| `app/client/dist` | Conventional directory for transpiled resources (images/CSS/JavaScript) for your CMS customisations |
3838
| `app/client/lang` | Conventional directory for [JavaScript translation tables](/developer_guides/i18n/#translation-tables-in-javascript) |

en/02_Developer_Guides/01_Templates/01_Syntax.md

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ icon: code
66

77
# Template syntax
88

9-
A template can contain any markup language (e.g HTML, CSV, JSON, etc) and before being rendered to the user, they're
10-
processed through [SSViewer](api:SilverStripe\View\SSViewer). This process replaces placeholders such as `$Var` with real content from your
9+
A template can contain any markup language (e.g HTML, CSV, JSON, etc). The rendering process replaces placeholders such as `$Var` with real content from your
1110
model (see [Model and Databases](../model)) and allows you to use logic like `<% if $Var %>` in your templates.
1211

1312
An example of a Silverstripe CMS template is below:
@@ -69,32 +68,33 @@ This will result in trying to fetch a `Title` property from the data being displ
6968
Variables can be chained together, and include arguments.
7069

7170
```ss
72-
$Foo(param)
71+
$Foo("param")
7372
$Foo.Bar
7473
```
7574

7675
These variables will call a method / field on the object and insert the returned value as a string into the template.
7776

77+
Arguments don't have to be literals - you can pass template variables as arguments as well.
78+
7879
> [!WARNING]
79-
> If you wish to pass arguments to getter functions, you must use the full method name. e.g. `$Thing` will try to access `Thing` as a property, which will ultimately result in `getThing()` being called with no arguments To pass arguments you must use `$getThing('param')`.
80-
>
81-
> Also, arguments must be literals, and cannot be other template variables (`$getThing($variable)` will pass the literal string `'$variable'` to the `getThing()` method).
80+
> Arguments cannot be literal arrays (e.g `$myMethod(["val1", "val2"])`). The behaviour for this is currently undefined.
8281
8382
- `$Foo("param")` will call `$obj->Foo("param")`
8483
- `$Foo.Bar` will call `$obj->Foo()->Bar`
84+
- `$Foo($Bar)` will call `$obj->Bar` and then pass the result into `$obj->Foo($result)`
8585

8686
> [!NOTE]
87-
> Arguments passed into methods can be any non-array literal type (not just strings), e.g:
87+
> Arguments passed into methods can be almost any type (not just strings), e.g:
8888
>
8989
> - `$Foo(1)` will pass `1` as an int
9090
> - `$Foo(0.5)` will pass `0.5` as a float
9191
> - `$Foo(true)` will pass `true` as a boolean
9292
> - `$Foo(null)` will pass `null` as a null primitive
93-
> - `$Foo("param")`, `$Foo('param')`, and `$Foo(param)` will all pass `'param'` as a string. It is recommended that you always use quotes when passing a string for clarity
93+
> - `$Foo("param")`, `$Foo('param')`, and `$Foo(param)` will all pass `'param'` as a string. It is recommended that you always use quotes when passing a string for clarity and for future-proofing.
9494
9595
If a variable returns a string, that string will be inserted into the template. If the variable returns an object, then
9696
the system will attempt to render the object through its `forTemplate()` method. If the `forTemplate()` method has not
97-
been defined, the system will return an error.
97+
been defined, the system will attempt to cast the object to a string.
9898

9999
> [!NOTE]
100100
> For more details around how variables are inserted and formatted into a template see
@@ -111,8 +111,7 @@ use SilverStripe\ORM\DataObject;
111111
class MyObject extends DataObject
112112
{
113113
// ...
114-
115-
public function UsersIpAddress()
114+
public function usersIpAddress()
116115
{
117116
return $this->getRequest()->getIP();
118117
}
@@ -125,10 +124,11 @@ class MyObject extends DataObject
125124
```
126125

127126
> [!NOTE]
128-
> Method names that begin with `get` will automatically be resolved when their prefix is excluded. For example, the above method call `$UsersIpAddress` would also invoke a method named `getUsersIpAddress()`.
127+
> Method names that begin with `get` will automatically be resolved when their prefix is excluded. For example, if the method `usersIpAddress()` didn't exist, the above reference to `$UsersIpAddress` would invoke a method named `getUsersIpAddress()`.
128+
> Note that a method with the exact name you're referencing will always be used if it exists.
129129
130130
The variables that can be used in a template vary based on the object currently in scope (see [scope](#scope) below). Scope defines what
131-
object the methods get called on. For the standard `Page.ss` template the scope is the current [`ContentController`](api:SilverStripe\CMS\Controllers\ContentController)
131+
object the methods get called on. For the standard `Page.ss` template the scope is usually the current [`ContentController`](api:SilverStripe\CMS\Controllers\ContentController)
132132
object. This object provides access to all the public methods on that controller, as well as the public methods, relations, and database fields for its corresponding [`SiteTree`](api:SilverStripe\CMS\Model\SiteTree) record.
133133

134134
```ss
@@ -141,6 +141,12 @@ $SilverStripeNavigator
141141
$Content
142142
```
143143

144+
### Case sensitivity
145+
146+
Just like in PHP, method names are case insensitive, but property names are case sensitive.
147+
148+
Using `$MyValue` in a template will successfully call a `myValue()` method, or a `getMyvalue()` method even though the case doesn't match what you used in the template. But it *will not* match a `myValue` property or database field because the case doesn't match.
149+
144150
## Conditional logic
145151

146152
The simplest conditional block is to check for the presence of a value. This effectively works the same as [`isset()`](https://www.php.net/manual/en/function.isset.php) in PHP - i.e. if there is no variable available with that name, or the variable's value is `0`, `false`, or `null`, the condition will be false.
@@ -206,7 +212,7 @@ For more nuanced conditions you can use the `!=` operator.
206212

207213
### Boolean logic
208214

209-
Multiple checks can be done using `||`/`or`, or `&&`/ `and`.
215+
Multiple checks can be done using `||`/`or`, or `&&`/`and`.
210216

211217
> [!NOTE]
212218
> `or` is functionally equivalent to `||` in template conditions, and `and` is functionally equivalent to `&&`.
@@ -564,39 +570,24 @@ refer directly to properties and methods of the [`Member`](api:SilverStripe\Secu
564570

565571
### `fortemplate()` and `$Me` {#fortemplate}
566572

567-
If you reference some `ModelData` object directly in a template, the `forTemplate()` method on that object will be called.
568-
This can be used to provide a default template for an object.
569-
570-
```php
571-
// app/src/PageType/HomePage.php
572-
namespace App\PageType;
573-
574-
use Page;
575-
576-
class HomePage extends Page
577-
{
578-
public function forTemplate(): string
579-
{
580-
// We can also render a template here using $this->renderWith()
581-
return 'Page: ' . $this->Title;
582-
}
583-
}
584-
```
573+
If you reference some object directly in a template, the `forTemplate()` method on that object will be called. This can be used to provide a default template for an object.
574+
If the `forTemplate()` method isn't implemented, the system will attempt to cast your object to a string.
575+
The default implementation of this method on `ModelData` renders the model using templates named after the class or its superclasses.
585576

586577
```ss
587-
<%-- calls forTemplate() on the first page in the list and prints Page: Home --%>
578+
<%-- calls forTemplate() on the first page in the list --%>
588579
$Pages->First
589580
```
590581

591582
You can also use the `$Me` variable, which outputs the current object in scope by calling `forTemplate()` on the object.
592583
This is especially helpful when you want to directly render items in a list you're looping over.
593584

594585
> [!WARNING]
595-
> If the object does not have a `forTemplate()` method implemented, this will throw an error.
586+
> If the object does not have an appropriate template, implement the `forTemplate()` method, or implement [`__toString()`](https://www.php.net/manual/en/language.oop5.magic.php#object.tostring), this will throw an error.
596587
597588
```ss
598589
<% loop $Pages %>
599-
<%-- calls forTemplate() on the current object in scope and prints Page: Home --%>
590+
<%-- calls forTemplate() on the current object in scope --%>
600591
$Me
601592
<% end_loop %>
602593
```

en/02_Developer_Guides/01_Templates/02_Common_Variables.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ have a read of the [Formatting, Modifying and Casting Variables](casting) docume
3636
</head>
3737
```
3838

39-
The `<% base_tag %>` placeholder is replaced with the HTML base element. Relative links within a document (such as
39+
The `<% base_tag %>` placeholder is replaced with the HTML `<base>` element. Relative links within a document (such as
4040
`<img src="someimage.jpg" alt="">`) will become relative to the URI specified in the base tag. This ensures the
4141
browser knows where to locate your site’s images and CSS files.
4242

43-
It renders in the template as `<base href="https://www.example.com" /><!--[if lte IE 6]></base><![endif]-->`
43+
It renders in the template as `<base href="https://www.example.com/">`
4444

4545
> [!CAUTION]
4646
> A `<% base_tag %>` is nearly always required or assumed by Silverstripe CMS to exist.
@@ -117,20 +117,20 @@ on a per-page basis.
117117
118118
By default `$MetaTags` renders (assuming 5.1.0 is the current version of `silverstripe/framework`):
119119

120-
```ss
120+
```html
121121
<title>Title of the Page</title>
122122
<meta name="generator" content="Silverstripe CMS 5.1">
123123
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
124124
```
125125

126126
`$MetaTags(false)` will render
127127

128-
```ss
128+
```html
129129
<meta name="generator" content="Silverstripe CMS 5.1">
130130
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
131131
```
132132

133-
If using `$MetaTags(false)` we can provide a more custom `title`.
133+
If using `$MetaTags(false)` we can provide a custom `<title> tag`.
134134

135135
```ss
136136
$MetaTags(false)

en/02_Developer_Guides/01_Templates/03_Requirements.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Also see [Direct resource urls](#direct-resource-urls) below if you need to incl
9494
## PHP requirements API
9595

9696
It is common practice to include most Requirements either in the `init()` method of your [controller](../controllers/), or
97-
as close to rendering as possible (e.g. in [FormField](api:SilverStripe\Forms\FormField)).
97+
as close to rendering as possible (e.g. in [`FormField::Field()`](api:SilverStripe\Forms\FormField::Field())).
9898

9999
```php
100100
namespace App\Control;
@@ -451,7 +451,7 @@ If you want to get a resource for a *specific* theme or from somewhere that is n
451451
```
452452

453453
> [!TIP]
454-
> Notice the `vendor/module:some/path/to/file.jpg` syntax (used to get a resource from a specific module) is only valid for the `$resourceURL()` helper method. It won't work for `themedResourceURL()`.
454+
> Notice the `vendor/module:some/path/to/file.jpg` syntax (used to get a resource from a specific module) is only valid for the `$resourceURL()` helper method. It won't work for `$themedResourceURL()`.
455455
456456
### Resource URLs or filepaths from a PHP context
457457

en/02_Developer_Guides/01_Templates/04_Rendering_Templates.md

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ icon: code
66

77
# Rendering data to a template
88

9+
> [!NOTE]
10+
> The template syntax, file extensions, and specifics about which tempaltes are chosen from a set as described on this page are specific to the default [`SSTemplateEngine`](api:SilverStripe\View\SSTemplateEngine) - but many of the concepts here (especially the PHP code) should work with any template engine you choose to use.
11+
912
Templates do nothing on their own. Rather, they are used to generate markup - most typically they are used to generate HTML markup, using variables from some `ModelData` object.
1013
All of the `<% if %>`, `<% loop %>` and other variables are methods or parameters that are called on the current object in
1114
scope (see [scope](syntax#scope) in the syntax section).
@@ -19,6 +22,9 @@ The following will render the given data into a template. Given the template:
1922

2023
Our application code can render into that view using the [`renderWith()`](api:SilverStripe\Model\ModelData) method provided by `ModelData`. Call this method on any instance of `ModelData` or its subclasses, passing in a template name or an array of templates to render.
2124

25+
> [!IMPORTANT]
26+
> Don't include the `.ss` file extension when referencing templates.
27+
2228
```php
2329
namespace App\Model;
2430

@@ -44,6 +50,11 @@ class MyModel extends DataObject
4450

4551
If you want to render an arbitrary template into the `$Layout` section of a page, you need to render your layout template and pass that as the `Layout` parameter to the Page template.
4652

53+
These examples assume you have moved the `templates/Coach_Message.ss` template file to `templates/Layout/Coach_Message.ss`
54+
55+
> [!WARNING]
56+
> While a lot of the concepts on this page apply for any template engine, the `$Layout` functionality is specific to the default [`SSTemplateEngine`](api:SilverStripe\View\SSTemplateEngine).
57+
4758
```php
4859
namespace App\Model;
4960

@@ -71,7 +82,6 @@ class MyModel extends DataObject
7182
In this case it may be better to use an *implicit* `Layout` type template, and rely on template inheritance to figure out which templates to use.
7283

7384
```php
74-
// This assumes you have moved the Coach_Message template to `templates/Layout/Coach_Message.ss`
7585
$this->customise($data)->renderWith(['Coach_Message', 'Page']);
7686
```
7787

@@ -157,16 +167,15 @@ class MyPageController extends PageController
157167
158168
## Rendering arbitrary data in templates
159169
160-
Any data you want to render into the template that does not extend `ModelData` should be wrapped in an object that
161-
does, such as `ArrayData` or `ArrayList`.
170+
While `ModelData` has some methods on it you may find useful for reprensenting complex data, you should be able to use just about anything as a model in a template.
171+
172+
To actually render the data, you can use the `customise()` method to add your arbitrary data on top of an existing model:
162173
163174
```php
164175
namespace App\PageType;
165176
166177
use PageController;
167178
use SilverStripe\Control\Director;
168-
use SilverStripe\Model\ArrayData;
169-
use SilverStripe\Model\List\ArrayList;
170179
171180
class MyPageController extends PageController
172181
{
@@ -178,14 +187,14 @@ class MyPageController extends PageController
178187
return $this->customise([
179188
'Name' => 'John',
180189
'Role' => 'Head Coach',
181-
'Experience' => ArrayList::create([
182-
ArrayData::create([
190+
'Experience' => [
191+
[
183192
'Title' => 'First Job',
184-
])
185-
ArrayData::create([
193+
],
194+
[
186195
'Title' => 'Second Job',
187-
]),
188-
]),
196+
],
197+
],
189198
])->renderWith('AjaxTemplate');
190199
} else {
191200
return $this->httpError(400);
@@ -194,5 +203,62 @@ class MyPageController extends PageController
194203
}
195204
```
196205
197-
> [!WARNING]
198-
> A common mistake is trying to loop over an array directly in a template - this won't work. You'll need to wrap the array in some `ModelData` instance as mentioned above.
206+
Or wrap the data in a `ModelData` subclass:
207+
208+
```php
209+
namespace App\PageType;
210+
211+
use PageController;
212+
use SilverStripe\Model\ArrayData;
213+
214+
class MyPageController extends PageController
215+
{
216+
// ...
217+
218+
public function getMyRenderedData()
219+
{
220+
return ArrayData::create([
221+
'Name' => 'John',
222+
'Role' => 'Head Coach',
223+
'Experience' => [
224+
[
225+
'Title' => 'First Job',
226+
],
227+
[
228+
'Title' => 'Second Job',
229+
],
230+
],
231+
])->renderWith('MyTemplate');
232+
}
233+
}
234+
```
235+
236+
Or you can hand the data to `SSViewer` directly:
237+
238+
```php
239+
namespace App\PageType;
240+
241+
use PageController;
242+
use SilverStripe\View\SSViewer;
243+
244+
class MyPageController extends PageController
245+
{
246+
// ...
247+
248+
public function getMyRenderedData()
249+
{
250+
return SSViewer::create('MyTemplate')->process([
251+
'Name' => 'John',
252+
'Role' => 'Head Coach',
253+
'Experience' => [
254+
[
255+
'Title' => 'First Job',
256+
],
257+
[
258+
'Title' => 'Second Job',
259+
],
260+
],
261+
]);
262+
}
263+
}
264+
```

en/02_Developer_Guides/01_Templates/05_Template_Inheritance.md

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,6 @@ to determine resolution priority. This search is based on the following three co
103103
the module author, and does not normally need to be customised. This includes the `$project` and
104104
`$other_modules` placeholder values.
105105

106-
### ThemeResourceLoader
107-
108-
The resolution of themes is performed by a [ThemeResourceLoader](api:SilverStripe\View\ThemeResourceLoader)
109-
instance, which resolves a template (or list of templates) and a set of themes to a system template path.
110-
111-
For each path the loader will search in this order:
112-
113-
- Loop through each theme which is configured.
114-
- If a theme is a set (declared with the `$` prefix, e.g. `$default`) it will perform a nested search within
115-
that set.
116-
- When searching the `$default` set, all modules will be searched in the order declared via the `module_priority`
117-
config, interpolating keys `$project` and `$other_modules` as necessary. By default, your project's templates should
118-
be checked before any vendor modules.
119-
- When the first template is found, it will be immediately returned, and will not continue to search.
120-
121106
### Declaring themes
122107

123108
All themes can be enabled and sorted via the `SilverStripe\View\SSViewer.themes` config value. For reference

0 commit comments

Comments
 (0)