owned this note
owned this note
Published
Linked with GitHub
# Template
模板(template)是在你的應用程式中組織和渲染(render) HTML 的最佳方式,無論您是需要從控制器渲染 HTML還是生成電子郵件的內容。
Symfony 中的模板是使用 Twig 創建的:一個靈活、快速且安全的模板引擎。
## twig模板語言
twig模板語言允許你寫的簡潔,易讀,對網頁設計師更有好,並在一些方面,比PHP模板功能更強大。
看看以下的 Twig 模板範例。即使您是第一次看到 Twig,您也可能了解其中的大部分內容:
```htmlembedded=
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Symfony!</title>
</head>
<body>
<h1>{{ page_title }}</h1>
{% if user.isLoggedIn %}
Hello {{ user.name }}!
{% endif %}
{# ... #}
</body>
</html>
````
Twig 語法基於這三個結構:
- ```{{ ... }}```, 用於顯示變量的內容或表達式的計算結果;
- ```{% ... %}```, 用於運行一些邏輯,例如條件或loop;
- ```{# ... #}```, 用於向模板添加註釋(與 HTML 註釋不同,這些註釋不包含在呈現的頁面中)。
您不能在 Twig 模板中執行 PHP code,但 Twig 提供了實用程式來執行模板中的某些邏輯。
例如,過濾器在渲染之前修改內容,例如過濾器(filter)upper為大寫內容:
```php=
{{ title|upper }}
```
Twig 帶有一長串標籤(tag)、過濾器(filter)和預設可用的功能。
在 Symfony 應用程式中,您還可以使用Symfony 定義這些 Twig 過濾器和函數 ,您可以創建自己的 Twig 過濾器和函數。
Twig 在```prod```[環境](https://symfony.com/doc/4.3/configuration.html#configuration-environments)中速度很快 (因為模板被編譯成 PHP 並自動cahce),在```dev```環境中使用起來很方便(因為模板在更改時會自動重新編譯)。
### twig 配置
Twig 有幾個配置選項,來定義諸如用於顯示數字和日期的格式、模板cache等內容。
閱讀 [Twig 配置參考](https://symfony.com/doc/4.3/reference/configuration/twig.html)以了解它們。
## 創建模板
在詳細解釋如何創建和渲染模板之前,請查看以下範例以快速概覽整個過程。首先,您需要在```templates/```目錄中創建一個新文件來存儲模板內容:
```htmlembedded=
{# templates/user/notifications.html.twig #}
<h1>Hello {{ user_first_name }}!</h1>
<p>You have {{ notifications|length }} new notifications.</p>
```
然後,創建一個控制器來呈現這個模板並將所需的變量傳遞給它:
```php=
// src/Controller/UserController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class UserController extends AbstractController
{
// ...
public function notifications()
{
// get the user information and notifications somehow
$userFirstName = '...';
$userNotifications = ['...', '...'];
// the template path is the relative file path from `templates/`
return $this->render('user/notifications.html.twig', [
// this array defines the variables passed to the template,
// where the key is the variable name and the value is the variable value
// (Twig recommends using snake_case variable names: 'foo_bar' instead of 'fooBar')
'user_first_name' => $userFirstName,
'notifications' => $userNotifications,
]);
}
}
```
### 模板命名
Symfony 推薦以下模板名稱:
- 使用[snake case](https://en.wikipedia.org/wiki/Snake_case)對文件名和目錄命名(例如```blog_posts.twig```, ```admin/default_theme/blog/index.twig```等);
- 為文件名稱定義兩個擴展(```index.html.twig```或是```blog_posts.xml.twig```)第一個會是(```html```,```xml```等)後半部模板會自動產生。
儘管模板通常生成 HTML 內容,但它們可以生成任何基於文本(text-base)的格式。這就是為什麼兩個擴展約定簡化了為多種格式創建和渲染模板的方式。
### 模板位置
模板預設存儲在```templates/```目錄中。當服務或控制器渲染```product/index.html.twig```模板時,它們實際上是指```<your-project>/templates/product/index.html.twig```文件。
預設模板目錄可使用```twig.default_path```選項進行配置, 您可以添加更多模板目錄,如後面所述。
### 模板變量
模板的常見需求是印出存儲在從控制器或服務傳遞的模板中的值。
變量通常存儲object和array,而不是字串、數字和boolean。
這就是 Twig 提供對複雜 PHP 變量的快速訪問的原因。考慮以下模板:
```htmlembedded=
<p>{{ user.name }} added this comment on {{ comment.publishedAt|date }}</p>
```
該```user.name```符號表示您希望顯示```name```存儲在變數 (user)中的某些訊息。
```user```是array還是object?
是```name```屬性還是方法?在 Twig 中,這無關緊要。
使用```foo.bar```符號時,Twig 嘗試按以下順序獲取變量的值:
1. $foo['bar'] (array和元素);
2. $foo->bar (object和public 屬性);
3. $foo->bar() (object和public方法);
4. $foo->getBar()(object和```getter```方法);
5. $foo->isBar()(object和```isser```方法);
6. $foo->hasBar()(object和```hasser```方法);
7. 如果以上都不存在,使用```null```.
這允許改進您的應用程式code而無需更改模版code(您可以從應用是概念證明的array變量開始,然後移動到具有方法的object等)
### 鏈接(link)到頁面
不是手動編寫鏈接 URL,而是使用該```path()```函數根據路由配置生成 URL 。
如果您想修改特定頁面的 URL,您需要做的就是更改路由配置:模板將自動生成新的 URL。
考慮以下路由配置:
```
# config/routes.yaml
blog_index:
path: /
controller: App\Controller\BlogController::index
blog_post:
path: /article/{slug}
controller: App\Controller\BlogController::show
```
使用```path()```Twig 函數鏈接到這些頁面,並將路由名稱作為第一個參數傳遞,將路由參數作為第二個可選的參數傳遞:
```htmlembedded=
<a href="{{ path('blog_index') }}">Homepage</a>
{# ... #}
{% for post in blog_posts %}
<h1>
<a href="{{ path('blog_post', {slug: post.slug}) }}">{{ post.title }}</a>
</h1>
<p>{{ post.excerpt }}</p>
{% endfor %}
```
該```path()```函數生成相對 URL。
如果您需要生成絕對 URL(例如,在呈現電子郵件或 RSS 的模板時),請使用該```url()```函數,該函數採用與```path()``` (eg``` <a href="{{ url('blog_index') }}"> ... </a>```)相同的參數。
### 鏈接到 CSS、JavaScript 和image assets
如果模板需要鏈接到靜態assets(例如image),Symfony 提供了一個```asset()```Twig 函數來幫助生成該 URL。
首先,安裝```asset```軟體包:
```
composer require symfony/asset
```
您現在可以使用```asset()```功能:
```htmlembedded=
{# the image lives at "public/images/logo.png" #}
<img src="{{ asset('images/logo.png') }}" alt="Symfony!"/>
{# the CSS file lives at "public/css/blog.css" #}
<link href="{{ asset('css/blog.css') }}" rel="stylesheet"/>
{# the JS file lives at "public/bundles/acme/js/loader.js" #}
<script src="{{ asset('bundles/acme/js/loader.js') }}"></script>
```
該```asset()```函數的主要目的是使您的應用程式更具可移植性。
如果您的應用程式位於host的根目錄(例如https://example.com),則呈現的路徑應該是```/images/logo.png```.
但是,如果您的應用程式位於子目錄(例如https://example.com/my_app)中,則每個asset路徑都應與子目錄(例如```/my_app/images/logo.png```)一起呈現。
該```asset()```函數通過確定您的應用程式的使用方式並相應地生成正確的路徑來處理此問題。
:::success
該```asset()```函數通過[version](https://symfony.com/doc/4.3/reference/configuration/framework.html#reference-framework-assets-version)、 [version_format](https://symfony.com/doc/4.3/reference/configuration/framework.html#reference-assets-version-format)和 [json_manifest_path](https://symfony.com/doc/4.3/reference/configuration/framework.html#reference-assets-json-manifest-path)配置選項支持各種chche busting技術 。
:::
:::success
如果您想以現代方式幫助打包、版本控制和縮小您的 JavaScript 和 CSS assets,請閱讀Symfony 的 [Webpack Encore](https://symfony.com/doc/4.3/frontend.html)。
:::
如果您需要asset的絕對 URL,請使用```absolute_url()```Twig 函數,如下所示:
```htmlembedded=
<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!"/>
<link rel="shortcut icon" href="{{ absolute_url('favicon.png') }}">
```
### 應用程式全域變量
Symfony 創建了一個內文object,該object作為一個名為```app```的變量自動注入到每個 Twig 模板中。
它提供對一些應用程式資訊的存取:
```htmlembedded
<p>Username: {{ app.user.username ?? 'Anonymous user' }}</p>
{% if app.debug %}
<p>Request method: {{ app.request.method }}</p>
<p>Application Environment: {{ app.environment }}</p>
{% endif %}
```
該```app```變量(這是一個[AppVariable](https://api.symfony.com/4.3/Symfony/Bridge/Twig/AppVariable.html)實例),您可以存取這些變量:
- ```app.user```
在當前user的object或者```null```如果user沒有被認證。
- ```app.request```
存儲當前請求object的資料(取決於您的應用程式,這可以是[子請求](https://symfony.com/doc/4.3/components/http_kernel.html#http-kernel-sub-requests)或常規請求)。
- ```app.session```
該session object表示當前user的session或者如果沒有的會會顯示```null```。
- ```app.flashes```
存儲在session中的所有Flash 資訊的array。
您也可以只獲取某種類型的資訊(例如```app.flashes('notice')```)。
- ```app.environment```
當前配置環境的名稱 (```dev```,```prod```,等)。
- ```app.debug```
如果處於debug模式,則為true。否則為false。
- ```app.token```
```[TokenInterface](https://github.com/symfony/symfony/blob/4.3/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php)``` 表示安全token object。
除了透過symfony注入的全局變量```app```外,你還可以[自動向所有Twig 模板注入變量](https://symfony.com/doc/4.3/templating/global_variables.html)。
## 渲染模板
### 在控制器中渲染模板
如果您的控制器從```AbstractController```擴展,請使用```render()```幫助程式(helpr):
```php=
// src/Controller/ProductController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class ProductController extends AbstractController
{
public function index()
{
// ...
return $this->render('product/index.html.twig', [
'category' => '...',
'promotions' => ['...', '...'],
]);
}
}
```
如果您的控制器沒有從```AbstractController```擴展,需要在您的控制器中獲取服務並使用```render()```此twig服務的方法。
### 在服務中渲染模板
將```twig``` 此Symfony服務注入到您自己的服務中並使用其```render()```方法。
使用服務自動配置時,您只需要在服務構造函數中添加一個參數並使用```Environment``` class對其進行類型提示(type-hint):
```php=
// src/Service/SomeService.php
namespace App\Service;
use Twig\Environment;
class SomeService
{
private $twig;
public function __construct(Environment $twig)
{
$this->twig = $twig;
}
public function someMethod()
{
// ...
$htmlContents = $this->twig->render('product/index.html.twig', [
'category' => '...',
'promotions' => ['...', '...'],
]);
}
}
```
### 在電子郵件中渲染模板
閱讀有關[郵件程式](https://symfony.com/doc/4.3/mailer.html#mailer-twig)和 Twig integration的文件。
### 直接從路由渲染模板
儘管模板通常在控制器和服務中渲染,但您可以直接從路由定義中渲染,不需要任何變量的靜態頁面。
使用```TemplateController```此Symfony 提供的特殊功能:
```
# config/routes.yaml
acme_privacy:
path: /privacy
controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController
defaults:
# the path of the template to render
template: 'static/privacy.html.twig'
# special options defined by Symfony to set the page cache
maxAge: 86400
sharedAge: 86400
# optionally you can define some arguments passed to the template
site_name: 'ACME'
theme: 'dark'
```
### 檢查模板是否存在
模板使用Twig模板loader load到應用程式中,它還提供了一種檢查模板是否存在的方法。首先,獲取loader:
```php
// in a controller extending from AbstractController
$loader = $this->get('twig')->getLoader();
// in a service using autowiring
use Twig\Environment;
public function __construct(Environment $twig)
{
$loader = $twig->getLoader();
}
```
然後,將 Twig 模板的路徑傳遞給```exists()``` loader的方法:
```php=
if ($loader->exists('theme/layout_responsive.html.twig')) {
// the template exists, do something
// ...
}
```
## debug模板
Symfony 提供了幾個實用程式來幫助您debug模板中的問題。
### Linting Twig 模板
```lint:twig```指令會檢查您的 Twig 模板是否沒有任何語法錯誤。
在將應用程式部署到生產環境(例如在您持續integration server的中)之前執行它很有用:
```
# check a;; the templates stored in a directory
php bin/console lint:twig templates/
# you can also check individual templates
php bin/console lint:twig templates/article/recent_list.html.twig
```
### 檢查twig訊息
該```debug:twig```命令列出了有關 Twig 的所有可用訊息(函數、過濾器、全域變數等)。
對於安裝軟體包時,檢查您的自定義 Twig 擴展是否正常工作以及添加的 Twig 功能 :
```
#list general information
php bin/console debug:twig
#filter optput by any keyword
php bin/console debug:twig --filter=date
# pass a template path to show the physical file which will be loaded
php bin/console debug:twig @Twig/Exception/error.html.twig
```
## Dump(傾瀉) twig 實用程式
Symfony 提供了一個[dump()](https://symfony.com/doc/4.3/components/var_dumper.html#components-var-dumper-dump)函數作為 PHP ```var_dump()```函數的替代方案。
這個函數對於檢查任何變量的內容很有用,你也可以在 Twig 模板中使用它。
首先,確保應用程式安裝了 VarDumper 組件:
```
composer require symfony/var-dumper
```
然後,根據您的需要使用```{% dump %}```標籤或```{{ dump() }}```函數:
```htmlembedded=
{# templates/article/recent_list.html.twig #}
{# the contents of this variable are sent to the Web Debug Toolbar
instead of dumping them inside the page contents #}
{% dump articles %}
{% for article in articles %}
{# the contents of this variable are dumped inside the page contents
and they are visible on the web page #}
{{ dump(article) }}
<a href="/article/{{ article.slug }}">
{{ article.title }}
</a>
{% endfor %}
```
為避免洩露敏感資訊,dump()tag/function僅在```dev```和```test``` 配置環境中可用。
如果你嘗試在```prod```環境中使用它,你會看到一個 PHP error。
## 重複使用模板內容
### include模板
如果某些 Twig code在多個模板中重複,您可以將其提取為單個“模板片段”並將其include在其他模板中。
以下顯示user資訊的code在幾個地方重複:
```htmlembedded=
{# templates/blog/index.html.twig #}
{# ... #}
<div class="user-profile">
<img src="{{ user.profileImageUrl }}"/>
<p>{{ user.fullName }} - {{ user.email }}</p>
</div>
```
首先,創建一個名為的```blog/_user_profile.html.twig```新twig模板( ```_```前綴(prefix)是可選的,但是最好用在不同的模板與模板片段之中)。
然後,從原始```blog/index.html.twig```模板中刪除該內容並添加以下內容以include模板片段:
```htmlembedded=
{# templates/blog/index.html.twig #}
{# ... #}
{{ include('blog/_user_profile.html.twig') }}
```
該```include()```twig功能把參數作為模板的路徑include。
include的模板可以存取包含它的模板的所有變量(使用```with_context```選項來控制它)。
您還可以將變量傳遞給include的模板。
例如,這對於重新命名變量很有用。
您的模板將user 資訊存儲在一個名為```blog_post.author```的```user```變量中,而不是模板片段所期望變量中。
使用以下命令重新命名變量:
```htmlembedded=
{# templates/blog/index.html.twig #}
{# ... #}
{{ include('blog/_user_profile.html.twig', {user: blog_post.author}) }}
```
### 嵌入(embedding)控制器
include模板片段對於在多個頁面上重複的內容很有用。
然而,這種技術在某些情況下並不是最好的解決方案。
模板片段顯示了三篇最近的blog 文章。
為此,它需要進行資料庫庫查詢以獲取這些文章。
使用該include()函數時,您需要在include該片段的每個頁面中執行相同的資料庫查詢。這不是很方便。
更好的選擇是將執行某些控制器的結果嵌入到```render()```和```controller()```這兩個Twig 函數中。
首先,創建渲染一定數量最近文章的控制器:
```php=
// src/Controller/BlogController.php
namespace App\Controller;
// ...
class BlogController extends AbstractController
{
public function recentArticles($max = 3)
{
// get the recent articles somehow (e.g. making a database query)
$articles = ['...', '...', '...'];
return $this->render('blog/_recent_articles.html.twig', [
'articles' => $articles
]);
}
}
```
然後,創建```blog/_recent_articles.html.twig```模板片段(```_```模板名稱中的前綴是可選的,但是最好用在不同的模板與模板片段之中):
```htmlembedded=
{# templates/blog/_recent_articles.html.twig #}
{% for article in articles %}
<a href="{{ path('blog_show', {slug: article.slug}) }}">
{{ article.title }}
</a>
{% endfor %}
```
現在你可以從任何模板呼叫這個控制器來嵌入它的結果:
```htmlembedded=
{# templates/base.html.twig #}
{# ... #}
<div id="sidebar">
{# if the controller is associated with a route, use the path() or url() functions #}
{{ render(path('latest_articles', {max: 3})) }}
{{ render(url('latest_articles', {max: 3})) }}
{# if you don't want to expose the controller with a public URL,
use the controller() function to define the controller to execute #}
{{ render(controller(
'App\\Controller\\BlogController::recentArticles', {max: 3}
)) }}
</div>
```
使用```controller()```功能時,控制器不是使用常規的 Symfony 路由存取的,而是透過專門用於為這些模板片段提供服務的特殊 URL 來存取的。
在```fragments```選項中配置該特殊 URL :
```
# config/packages/framework.yaml
framework:
# ...
fragments: { path: /_fragment }
```
:::danger
Caution
嵌入控制器需要向這些控制器發出請求並渲染一些模板作為結果。
如果您嵌入大量控制器,這會對應用程式性能產生重大影響。如果可能,[cahce模板片段](https://symfony.com/doc/4.3/http_cache/esi.html)。
:::
>note
>模板還可以使用JavaScript的函式庫```hinclude```[嵌入不同步內容](https://symfony.com/doc/4.3/templating/hinclude.html)。
### 模板繼承和佈局(layout)
隨著應用程式的增長,您會發現頁面之間的重複元素越來越多,例如header、footer、sidebars等。
include模板和嵌入控制器會有所幫助,但當頁面共享公共結構時,最好使用繼承。
Twig 模板繼承的概念類似於 PHP class繼承。
您定義一個父模板,其他模板可以從中擴展,子模板可以覆蓋父模板的一部分。
Symfony 為中等和複雜的應用程式推薦以下三層級模板繼承:
- ```templates/base.html.twig```定義所有應用程式模板的共同的元件,例如```<head>,<header>,<footer>```等;
- ```templates/layout.html.twig```, 擴展```base.html.twig```並定義了所有或大部分頁面中使用的內容結構,例如內容 + sidebar layout。應用程式的某些部分可以定義自己的佈局(例如```templates/blog/layout.html.twig```);
- ```templates/*.html.twig```,從主```layout.html.twig```模板或任何其他部分layout擴展的應用程式頁面 。
在範例練習中,```base.html.twig```模板看起來像這樣:
```htmlembedded=
{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}My Application{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="{{ path('homepage') }}">Home</a></li>
<li><a href="{{ path('blog_index') }}">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block body %}{% endblock %}
</div>
</body>
</html>
```
twig ```block``` tag定義可以在子模板覆蓋的頁面部分。
它們可以是空的,如```body```block,也可以定義預設內容,如```title```block,當子模板不覆蓋它們時顯示。
```blog/layout.html.twig```模板可能是這樣的:
```htmlembedded=
{# templates/blog/layout.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<h1>Blog</h1>
{% block content %}{% endblock %}
{% endblock %}
```
模板從block中擴展```base.html.twig```並且只定義```body``` block的內容。
其餘的父模板block將顯示它們的預設內容。
但是,它們可以被第三級繼承模板覆蓋,例如```blog/index.html.twig```顯示blog index :
```htmlembedded=
{# templates/blog/index.html.twig #}
{% extends 'blog/layout.html.twig' %}
{% block title %}Blog Index{% endblock %}
{% block content %}
{% for article in articles %}
<h2>{{ article.title }}</h2>
<p>{{ article.body }}</p>
{% endfor %}
{% endblock %}
```
此模板從二級模板 ( ```blog/layout.html.twig```)擴展而來,但覆蓋了不同父模板的block:```contentfrom blog/layout.html.twig```和```titlefrom base.html.twig```。
當你渲染```blog/index.html.twig```模板時,Symfony 使用三個不同的模板來創建最終的內容。
這種繼承機制可提高您的工作效率,因為每個模板僅包含其獨特的內容,而將重複的內容和 HTML 結構留給某些父模板。
閱讀[Twig 模板繼承文件](https://twig.symfony.com/doc/2.x/tags/extends.html)以了解有關如何在覆蓋模板和其他高級功能時重用父block內容的更多資訊。
## 輸出轉譯(escaping)
假設您的模板包含```Hello {{ name }}```顯示user名稱的code。
如果惡意使用者將```<script>alert('hello!')</script>```設置為他們的名稱並且您輸出該值不變,應用程式將顯示一個 JavaScript 彈出窗口。
這稱為跨站點腳本(XSS) 攻擊。
雖然前面的例子看起來無害,但攻擊者可以編寫更高級的 JavaScript code來執行惡意操作。
為了防止這種攻擊,請使用“輸出轉譯(escaping)”來轉換具有特殊含義的符號(例如,替換```<```為```<```;HTML entity)。
預設情況下,Symfony 應用程式是安全的,因為它們使用Twig自動轉譯選項執行自動輸出轉譯:
```htmlembedded=
<p>Hello {{ name }}</p>
{# if 'name' is '<script>alert('hello!')</script>', Twig will output this:
'<p>Hello <script>alert('hello!')</script></p>' #}
```
如果您正在渲染一個受信任且包含 HTML 內容的變量,請使用[Twig raw過濾器](https://twig.symfony.com/doc/2.x/filters/raw.html)禁用該變量的輸出轉譯:
```htmlembedded=
<h1>{{ product.title|raw }}</h1>
{# if 'product.title' is 'Lorem <strong>Ipsum</strong>', Twig will output
exactly that instead of 'Lorem <strong>Ipsum</strong>' #}
```
閱讀[Twig輸出轉譯文件](https://twig.symfony.com/doc/2.x/api.html#escaper-extension)以了解有關如何禁用block甚至整個模板的輸出轉譯的更多資訊。
## 模板命名空間(namespace)
儘管大多數應用程式將其模板存儲在預設```templates/``` 目錄中,但您可能需要將部分或全部模板存儲在不同的目錄中。
使用```twig.paths```選項來配置這些額外的目錄。
每個路徑都定義為一```key: value``` pair,其中```key```是模板目錄,```value```是 Twig 命名空間,稍後解釋:
```
# config/packages/twig.yaml
twig:
# ...
paths:
# directories are relative to the project root dir (but you
# can also use absolute directories)
'email/default/templates': ~
'backend/templates': ~
```
渲染模板時,Symfony 首先在```twig.paths``` 未定義命名空間的目錄中查找它,然後回傳到預設模板目錄(通常為```templates/```)。
使用上述配置,如果您的應用程式呈現例如```layout.html.twig```模板,Symfony 將首先查找 ```email/default/templates/layout.html.twig```和```backend/templates/layout.html.twig```。
如果這些模板中的任何一個存在,Symfony 將使用它而不是 ```using templates/layout.html.twig```,這可能是您想要使用的模板。
Twig 用```namespaces```解決了這個問題,它把幾個模板組合在一個與其實際位置無關的邏輯名稱下。
更新之前的配置,為每個模板目錄定義一個命名空間:
```
# config/packages/twig.yaml
twig:
# ...
paths:
'email/default/templates': 'email'
'backend/templates': 'admin'
```
現在,如果你渲染```layout.html.twig```模板,Symfony 將渲染 ```templates/layout.html.twig```文件。
使用特殊語法```@```+ 命名空間來引用其他命名空間模板(例如```@email/layout.html.twig```和 ```@admin/layout.html.twig```)。
>note
>單個 Twig 命名空間可以與多個模板目錄相關聯。
>在這種情況下,添加路徑的順序很重要,因為 Twig 將從第一個定義的路徑開始尋找模板。
### 綑綁(bundle)模板
如果您在應用程式中安裝[packages/bundles](https://symfony.com/doc/4.3/setup.html#symfony-flex),它們可能包含自己的 Twig 模板(在```Resources/views/```每個捆綁(bundle)的目錄中)。
為了避免弄亂你自己的模板,Symfony 在bundle名稱後創建的自動命名空間下添加bundle模板。
例如,被呼叫的bundle模板```AcmeFooBundle```在```AcmeFoo```命名空間下可用。如果此bundle包含模板 ```<your-project>/vendor/acmefoo-bundle/Resources/views/user/profile.html.twig```,您可以將其稱為```@AcmeFoo/user/profile.html.twig.```
:::success
如果您想更改原始bundle模板的某些部分,您還可以[覆蓋bundle模板](https://symfony.com/doc/4.3/bundles/override.html#override-templates)。
:::
其餘[資訊](https://symfony.com/doc/4.3/templates.html#learn-more)可以在此找到