الوسم extends في Twig
يُستخدم الوسم extends لتوسيع قالب من قالب آخر.
لاحظ أن Twig لا يدعم الوراثة المتعددة شأنه في ذلك شأن لغة PHP، فلا يمكنك استدعاء إلا وسم extends
واحد عند كل إخراج (rendering)، لكن Twig يدعم إعادة الاستخدام الأفقية، انظر وسم use
.
لنعرّف قالبًا أساسيًا (base template) هو base.html
، الذي يعرّف مستند HTML هيكلي:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css"/>
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2011 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
</html>
تعرّف أوسمة block
في المثال السابق أربعة كتل تستطيع القوالب الأبناء أن تملأها، ويخبر وسم block محرك القالب أن القالب الابن قد يتخطى هذه الأجزاء من القالب.
القالب الابن
الشيفرة التالية مثال على قالب ابن (child template):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome on my awesome homepage.
</p>
{% endblock %}
في المثال أعلاه يخبر الوسم extends
محرك القالب أن هذا القالب يوسع قالبًا آخر، وعندما يقيّم نظام القالب هذا القالب فإنه يحدد قالبه الأب أولًا، ويجب أن يكون الوسم extends
هو أول وسم في القالب.
وبما أن القالب الابن لا يعرّف كتلة footer
فإن القيمة التي من القالب الأب هي التي تُستخدم. لا تستطيع تعريف عدة وسوم block بنفس الاسم في نفس القالب، وهذا لأن وسم block يعمل في اتجاهين، فإنه يوفر فراغًا لملئه ويعرّف المحتوى الذي يملأ ذلك الفراغ في القالب الأب في نفس الوقت، وإذا كان لدينا وسمان block في قالب واحد فإن القالب الأب لن يعرف أي الوسمين يختار كي يستخدم محتواه.
لكن إذا أردت طباعة كتلة عدة مرات فيمكنك استخدام دالة block
:
<title>{% block title %}{% endblock %}</title>
<h1>{{ block('title') }}</h1>
{% block body %}{% endblock %}
الكتلة الأب
من الممكن إخراج محتويات الكتلة الأب باستخدام دالة parent، ويعطينا ذلك نتيجة الكتلة الأب:
{% block sidebar %}
<h3>Table Of Contents</h3>
...
{{ parent() }}
{% endblock %}
وسم النهاية للكتلة المسماة
يسمح لك Twig أن تضع اسم الكتلة بعد وسم النهاية من أجل تيسير قراءتها، ويجب أن يطابق الاسم الذي بعد كلمة endblock
اسم الكتلة:
{% block sidebar %}
{% block inner_sidebar %}
...
{% endblock inner_sidebar %}
{% endblock sidebar %}
نطاق الكتل وتشعبها
من الممكن أن تتشعب الكتل لتنشئ بها تخطيطات معقدة، وإن لها افتراضيًا وصول إلى المتغيرات من النطاقات الخارجية :
{% for item in seq %}
<li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}
اختصارات الكتل
من الممكن استخدام صياغة مختصرة في حالة الكتل التي ليس بها محتوى كبير، والبنى التالية تنفذ مثل ذلك:
{% block title %}
{{ page_title|title }}
{% endblock %}
{% block title page_title|title %}
الوراثة الديناميكة
يدعم Twig الوراثة الديناميكية (Dynamic Inheritance) عن طريق استخدام المتغير كقالب أساسي (base template):
{% extends some_var %}
إذا كان المتغير يقيَّم إلى \Twig\Template
أو نسخة من \Twig\TemplateWrapper
فإن Twig سيستخدمه كقالب أب:
// {% extends layout %}
$layout = $twig->load('some_layout_template.twig');
$twig->display('template.twig', ['layout' => $layout]);
يمكنك توفير قائمة من القوالب التي تم التحقق من وجودها، وسيُستخدم أول قالب موجود كقالب أب:
{% extends ['layout.html', 'base_layout.html'] %}
الوراثة الشرطية
بما أن اسم القالب الأب قد يكون أي تعبير Twig صالح، فمن الممكن أن نجعل آلية الوراثة آلية شرطية:
{% extends standalone ? "minimum.html" : "base.html" %}
في المثال أعلاه، يوسِّع القالب قالب التخطيط "minimum.html" إذا قُيِّم المتغير standalone
إلى true
، ويوسع "base.html" إن كان false
.
كيفية عمل الكتل
توفر الكتلة طريقة لتغيير الكيفية التي يُخرَج بها جزء ما من القالب، لكن لا تتدخل في المنطق المحيط به. انظر إلى المثال التالي الذي يوضح كيف تعمل كتلة ما، والحالة التي لا تعمل فيها كذلك:
{# base.twig #}
{% for post in posts %}
{% block post %}
<h1>{{ post.title }}</h1>
<p>{{ post.body }}</p>
{% endblock %}
{% endfor %}
إذا أخرجت هذا القالب فإن النتيجة ستكون نفسها سواء استخدمت وسم block
أو لا، ذلك أن block
التي داخل حلقة for
ما هي إلا طريقة لتجعلها قابلة للتخطي بواسطة قالب ابن:
{# child.twig #}
{% extends "base.twig" %}
{% block post %}
<article>
<header>{{ post.title }}</header>
<section>{{ post.text }}</section>
</article>
{% endblock %}
عند إخراج القالب الابن فإن الحلقة تستخدم الكتلة المعرفة فيه بدلًا من الكتلة المعرفة في القالب الأساس، ثم يقيَّم القالب المنفَّذ بعدها إلى التالي:
{% for post in posts %}
<article>
<header>{{ post.title }}</header>
<section>{{ post.text }}</section>
</article>
{% endfor %}
لنأخذ مثلًا آخر تكون فيه الكتلة مدرَجة داخل تعليمة if
:
{% if posts is empty %}
{% block head %}
{{ parent() }}
<meta name="robots" content="noindex, follow">
{% endblock head %}
{% endif %}
لا يعرِّف هذا القالب كتلة تعريفًا شرطيًا، على عكس ما قد يظن المرء لأول وهلة، بل يجعل الخرج قابلًا للتخطي بواسطة قالب ابن إذا كان تحقق الشرط، أي كان true
.
وإذا أردت عرض الخرج عرضًا شرطيًا فاستخدم ما يلي:
{% block head %}
{{ parent() }}
{% if posts is empty %}
<meta name="robots" content="noindex, follow">
{% endif %}
{% endblock head %}