定制 lliure/twig-container 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

lliure/twig-container

最新稳定版本:v1.0.1

Composer 安装命令:

composer require lliure/twig-container

包简介

Twig extension for container-based template composition with additive content injection

README 文档

README

Latest Version PHP Version License

Vue-like slots for Twig. Container-based template composition with additive content injection.

Perfect for injecting scripts, styles, and components from child templates into parent layouts.

Why This Library?

Twig's native {% block %} is substitutive - child blocks replace parent blocks. But sometimes you need additive composition:

{# ❌ Problem: Each component overwrites the scripts block #}
{% block scripts %}
    <script src="datepicker.js"></script>
{% endblock %}

{# ✅ Solution: Components ADD to the container #}
{% inject 'scripts' %}
    <script src="datepicker.js"></script>
{% endinject %}

Features

FeatureDescription
ContainersNamed areas that accumulate content
InjectAdd content from anywhere (before or after the container)
UniquePrevent duplicate injections (CSS/JS)
PackageReusable components with isolated context
content()Mix original content with injections

Comparison with Alternatives

Featuretwig-stacklliure/twig-container
Push/Inject
Prevent duplicatespushonceunique with auto or manual ID
Mix original + injected{{ content() }}
Reusable components{% package %}
Dynamic paths{% package path ~ '.twig' %}

Installation

composer require lliure/twig-container

Quick Start

use TwigContainer\Container;
use TwigContainer\ContainerRuntime;

// Add extension
$twig->addExtension(new Container());

// Add runtime loader
$twig->addRuntimeLoader(new class implements \Twig\RuntimeLoader\RuntimeLoaderInterface {
    private ?ContainerRuntime $runtime = null;
    public function load(string $class): ?object {
        if ($class === ContainerRuntime::class) {
            return $this->runtime ??= new ContainerRuntime();
        }
        return null;
    }
});

// Render with post-processing
$output = $twig->render('template.twig');
$runtime = $twig->getRuntime(ContainerRuntime::class);
echo $runtime->processPlaceholders($output);

Usage

Container

Define a named area:

{% container 'scripts' %}
    <script src="base.js"></script>
    {{ content() }}
{% endcontainer %}
  • {{ content() }} marks where injections appear
  • Without content(): injections replace original content
  • Without injections: shows original content

Inject

Add content to a container:

{% inject 'scripts' %}
    <script src="page.js"></script>
{% endinject %}

Works before or after the container (placeholder magic).

Unique Inject

Prevent duplicates (great for CSS/JS libraries):

{# Auto-unique based on file:line #}
{% inject 'styles' unique %}
    <link rel="stylesheet" href="datepicker.css">
{% endinject %}

{# Manual ID for cross-file deduplication #}
{% inject 'styles' unique 'datepicker-css' %}
    <link rel="stylesheet" href="datepicker.css">
{% endinject %}

Package

Include reusable components with isolated context:

{% package 'components/datepicker.twig' with {name: 'birthday', format: 'd/m/Y'} %}

Supports dynamic paths:

{% for field in fields %}
    {% package 'components/' ~ field.type ~ '.twig' with field.config %}
{% endfor %}

Real-World Example

The Problem

You have a datepicker component used multiple times. You need:

  • CSS loaded once
  • JS initialization for each instance
  • Everything in the right place (head/footer)

The Solution

components/datepicker.twig:

<input type="text" name="{{ name }}" class="datepicker" data-format="{{ format }}">

{# CSS - loads once per page #}
{% inject 'styles' unique 'datepicker' %}
    <link rel="stylesheet" href="datepicker.css">
{% endinject %}

{# JS - one per instance #}
{% inject 'scripts' %}
    <script>initDatepicker('{{ name }}', '{{ format }}');</script>
{% endinject %}

layout.twig:

<!DOCTYPE html>
<html>
<head>
    {% container 'styles' %}{{ content() }}{% endcontainer %}
</head>
<body>
    {% block content %}{% endblock %}

    {% container 'scripts' %}
        <script src="app.js"></script>
        {{ content() }}
    {% endcontainer %}
</body>
</html>

form.twig:

{% extends 'layout.twig' %}

{% block content %}
    <form>
        {% package 'components/datepicker.twig' with {name: 'start', format: 'd/m/Y'} %}
        {% package 'components/datepicker.twig' with {name: 'end', format: 'd/m/Y'} %}
    </form>
{% endblock %}

Output:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="datepicker.css">
</head>
<body>
    <form>
        <input type="text" name="start" class="datepicker" data-format="d/m/Y">
        <input type="text" name="end" class="datepicker" data-format="d/m/Y">
    </form>

    <script src="app.js"></script>
    <script>initDatepicker('start', 'd/m/Y');</script>
    <script>initDatepicker('end', 'd/m/Y');</script>
</body>
</html>

CSS loads once, scripts load per instance.

Running Tests

php tests/run.php              # Visual output
php tests/run.php --validate   # Exit code for CI

License

MIT - see LICENSE

Contributing

Issues and PRs welcome at Bitbucket.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 7
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-23

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固