本文目录导读:

我来详细介绍如何在Symfony项目中创建自定义Twig扩展。
创建自定义Twig扩展类
首先创建一个继承 AbstractExtension 的类:
// src/Twig/AppExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class AppExtension extends AbstractExtension
{
// 注册过滤器
public function getFilters(): array
{
return [
new TwigFilter('price', [$this, 'formatPrice']),
new TwigFilter('truncate', [$this, 'truncateText']),
];
}
// 注册函数
public function getFunctions(): array
{
return [
new TwigFunction('greet', [$this, 'greetUser']),
new TwigFunction('random_color', [$this, 'getRandomColor']),
];
}
// 自定义过滤器方法
public function formatPrice($number, $currency = '¥', $decimals = 2)
{
$formatted = number_format($number, $decimals);
return $currency . ' ' . $formatted;
}
public function truncateText($text, $length = 100, $suffix = '...')
{
if (mb_strlen($text) <= $length) {
return $text;
}
return mb_substr($text, 0, $length) . $suffix;
}
// 自定义函数方法
public function greetUser($name)
{
$time = date('H');
$greeting = 'Hello';
if ($time < 12) {
$greeting = 'Good morning';
} elseif ($time < 18) {
$greeting = 'Good afternoon';
} else {
$greeting = 'Good evening';
}
return sprintf('%s, %s!', $greeting, ucfirst($name));
}
public function getRandomColor()
{
$colors = ['primary', 'secondary', 'success', 'danger', 'warning', 'info'];
return $colors[array_rand($colors)];
}
}
注册服务
如果使用自动装配(Symfony 5+),扩展会自动注册,否则手动配置:
# config/services.yaml
services:
App\Twig\AppExtension:
tags: ['twig.extension']
在模板中使用
{# 使用自定义函数 #}
{{ greet('John') }}
{# 输出: Good morning, John! #}
{# 使用随机颜色函数 #}
<div class="alert alert-{{ random_color() }}">
This is a random colored alert!
</div>
{# 使用自定义过滤器 #}
{{ 99.99|price }}
{# 输出: ¥ 99.99 #}
{{ 99.99|price('$', 0) }}
{# 输出: $ 100 #}
{{ 'This is a very long text...'|truncate(10) }}
{# 输出: This is a... #}
高级用法 - 带依赖注入
// src/Twig/AdvancedExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Routing\RouterInterface;
class AdvancedExtension extends AbstractExtension
{
private $entityManager;
private $security;
private $router;
public function __construct(
EntityManagerInterface $entityManager,
Security $security,
RouterInterface $router
) {
$this->entityManager = $entityManager;
$this->security = $security;
$this->router = $router;
}
public function getFunctions(): array
{
return [
new TwigFunction('get_user_count', [$this, 'getUserCount']),
new TwigFunction('is_admin', [$this, 'isAdmin']),
new TwigFunction('active_route', [$this, 'isActiveRoute']),
];
}
public function getUserCount(): int
{
return $this->entityManager
->getRepository(User::class)
->count([]);
}
public function isAdmin(): bool
{
return $this->security->isGranted('ROLE_ADMIN');
}
public function isActiveRoute(string $routeName): bool
{
$currentRoute = $this->router->getRouteCollection()
->get($routeName);
return $currentRoute !== null;
}
}
创建带全局变量的扩展
// src/Twig/GlobalExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;
class GlobalExtension extends AbstractExtension implements GlobalsInterface
{
private $appName;
private $appVersion;
public function __construct(string $appName, string $appVersion)
{
$this->appName = $appName;
$this->appVersion = $appVersion;
}
public function getGlobals(): array
{
return [
'app_name' => $this->appName,
'app_version' => $this->appVersion,
'current_year' => date('Y'),
];
}
}
在模板中使用全局变量
{# 直接使用全局变量 #}
<footer>
© {{ current_year }} {{ app_name }} v{{ app_version }}
</footer>
测试自定义扩展
// tests/Twig/AppExtensionTest.php
namespace App\Tests\Twig;
use App\Twig\AppExtension;
use PHPUnit\Framework\TestCase;
class AppExtensionTest extends TestCase
{
private $extension;
protected function setUp(): void
{
$this->extension = new AppExtension();
}
public function testFormatPrice()
{
$result = $this->extension->formatPrice(99.99);
$this->assertEquals('¥ 99.99', $result);
}
public function testTruncateText()
{
$text = 'This is a very long text that needs to be truncated';
$result = $this->extension->truncateText($text, 10);
$this->assertEquals('This is a...', $result);
}
public function testGreetUser()
{
$result = $this->extension->greetUser('john');
$this->assertStringContainsString('john', strtolower($result));
}
}
最佳实践建议
- 命名规范:使用有意义的名称,添加后缀如
Extension - 单一职责:每个扩展负责一组相关功能
- 缓存友好:避免在扩展中进行数据库查询(使用服务层)
- 类型提示:使用PHP类型声明
- 文档注释:为方法添加PHPDoc注释
这样你就可以在Symfony项目中轻松创建和使用自定义Twig扩展了!