目录¶
选择模板引擎¶
Twig 是一个现代的、灵活且强大的 PHP 模板引擎,具有清晰的语法和丰富的功能,广泛应用于 Symfony 等框架中。除了 Twig,还可以考虑 Blade(Laravel 的模板引擎)或 Smarty 等其他模板引擎。本文以 Twig 为例进行说明。
通过 Composer 安装 Twig¶
首先,使用 Composer 安装 Twig。确保项目已经初始化为一个 Composer 项目(即存在 composer.json
文件)。
步骤:¶
安装 Twig
在项目根目录下运行以下命令安装 Twig:
composer require twig/twig
更新自动加载
安装完成后,Composer 会自动更新
vendor/autoload.php
,无需额外操作。
配置模板目录¶
为了组织模板文件,在项目中创建一个专门的 views
目录,用于存放所有的视图模板。
步骤:¶
创建
views
目录在项目根目录下创建
views/
目录:mkdir views
组织模板文件
根据项目需求,在
views/
目录下创建子目录和模板文件。例如:my_framework/ ├── composer.json ├── composer.lock ├── vendor/ ├── index.php ├── src/ │ ├── Router.php │ └── Controller.php ├── src/Controllers/ │ ├── HomeController.php │ └── UsersController.php ├── views/ │ ├── home/ │ │ └── index.html.twig │ ├── users/ │ │ ├── list.html.twig │ │ └── show.html.twig │ └── auth/ │ ├── login.html.twig │ └── register.html.twig └── logs/ └── app.log
更新 Controller 类以支持模板渲染¶
为了简化视图渲染过程,在基础 Controller
类中集成 Twig 的渲染功能。
步骤:¶
导入 Twig 类
在
Controller.php
中,导入 Twig 的相关类:<?php use TwigEnvironment; use TwigLoaderFilesystemLoader;
初始化 Twig 环境
在
Controller
类的构造函数中初始化 Twig:<?php class Controller { protected $twig; public function __construct() { $loader = new FilesystemLoader(__DIR__ . '/../views'); $this->twig = new Environment($loader, [ 'cache' => __DIR__ . '/../../cache/twig', 'debug' => true, ]); } /** * 渲染模板 * * @param string $template 模板文件路径(相对于 views 目录) * @param array $data 传递给模板的数据 */ protected function render($template, $data = []) { echo $this->twig->render($template, $data); } }
说明:
FilesystemLoader
:指定模板文件所在的目录。Environment
:Twig 的核心类,负责渲染模板。可配置缓存和调试选项。render
方法:在控制器中调用此方法即可渲染指定的模板,并传递数据。
创建缓存目录(可选)
为了提高渲染性能,可以启用 Twig 的缓存功能。创建一个
cache/twig/
目录并确保 PHP 有写入权限:mkdir -p cache/twig chmod 755 cache/twig
创建视图模板¶
在 views/
目录下创建 Twig 模板文件,定义页面的结构和内容。
示例:¶
主页模板
views/home/index.html.twig
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <h1>欢迎来到主页!</h1> <p><a href="{{ path('users.list') }}">查看用户列表</a></p> </body> </html>
用户列表模板
views/users/list.html.twig
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>用户列表</title> </head> <body> <h1>用户列表</h1> <ul> {% for user in users %} <li><a href="{{ path('users.show', {'id': user.id}) }}">{{ user.name }}</a> ({{ user.email }})</li> {% endfor %} </ul> </body> </html>
说明:
模板变量:使用
{{ }}
来输出变量值。控制结构:使用
{% for %}
来循环渲染用户列表。反向路由:假设已实现
path
函数用于生成 URL(详见下文)。
在控制器中渲染视图¶
在具体的控制器方法中,调用 render
方法来渲染对应的模板,并传递所需的数据。
示例:¶
HomeController.php
<?php // src/Controllers/HomeController.php namespace MyFrameworkControllers; use MyFrameworkController; class HomeController extends Controller { public function index() { $this->logger->info("访问主页"); $this->render('home/index.html.twig'); } // ... 其他方法 ... } ?>
UsersController.php
<?php // src/Controllers/UsersController.php namespace MyFrameworkControllers; use MyFrameworkController; class UsersController extends Controller { public function list() { $this->logger->info("请求用户列表"); // 示例数据,实际应用中应从数据库获取 $users = [ ['id' => 1, 'name' => '张三', 'email' => 'zhangsan@example.com'], ['id' => 2, 'name' => '李四', 'email' => 'lisi@example.com'], ['id' => 3, 'name' => '王五', 'email' => 'wangwu@example.com'], ]; $this->render('users/list.html.twig', ['users' => $users]); } public function show($id) { $this->logger->info("请求用户详情", ['id' => $id]); // 示例数据,实际应用中应从数据库获取 $users = [ 1 => ['id' => 1, 'name' => '张三', 'email' => 'zhangsan@example.com'], 2 => ['id' => 2, 'name' => '李四', 'email' => 'lisi@example.com'], 3 => ['id' => 3, 'name' => '王五', 'email' => 'wangwu@example.com'], ]; if (isset($users[$id])) { $user = $users[$id]; $this->render('users/show.html.twig', ['user' => $user]); } else { $this->sendNotFound(); } } // ... 其他方法 ... } ?>
说明:
传递数据:在调用
render
方法时,通过数组传递数据给模板。数据获取:实际应用中,应从数据库或其他数据源获取数据。
总结¶
通过以上步骤,已经成功在自定义的 PHP 框架中集成了 Twig 模板引擎,实现了视图与业务逻辑的分离,提升了代码的可维护性和扩展性。以下是关键点的回顾:
选择合适的模板引擎:Twig 作为一个现代且强大的模板引擎,适合与自定义框架集成。
通过 Composer 安装:使用 Composer 轻松管理模板引擎的依赖。
配置模板目录:组织模板文件,确保项目结构清晰。
更新 Controller 类:在基础控制器中集成模板渲染功能,简化控制器方法中的视图渲染。
创建和使用模板:在
views/
目录下创建 Twig 模板,并在控制器中渲染这些模板,传递所需的数据。
进一步扩展建议¶
布局和继承:
利用 Twig 的模板继承功能,创建基础布局模板,减少重复代码。
{# views/base.html.twig #} <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>{% block title %}My Framework{% endblock %}</title> </head> <body> <header> <h1>我的框架</h1> <nav> <a href="{{ path('home.index') }}">主页</a> <a href="{{ path('users.list') }}">用户列表</a> </nav> </header> <main> {% block content %}{% endblock %} </main> <footer> <p>© 2024 My Framework</p> </footer> </body> </html>
子模板可以继承该布局:
{# views/home/index.html.twig #} {% extends 'base.html.twig' %} {% block title %}主页 - My Framework{% endblock %} {% block content %} <h2>欢迎来到主页!</h2> <p><a href="{{ path('users.list') }}">查看用户列表</a></p> {% endblock %}
Twig 全局变量和函数:
为了在所有模板中使用反向路由功能,可以将
path
函数作为 Twig 的全局函数注册。// 在 Controller 类的构造函数中添加 $this->twig->addFunction(new TwigTwigFunction('path', function ($name, $params = []) { return $this->router->generateUrl($name, $params); }));
处理静态资源:
配置模板引擎正确处理 CSS、JS 和图片等静态资源的路径,确保资源能够正确加载。
表单和 CSRF 保护:
利用 Twig 模板引擎,创建安全的表单,并集成 CSRF 令牌保护,提升应用的安全性。
国际化和本地化:
集成 Twig 的翻译扩展,支持多语言内容,提升应用的国际化能力。