الفرق بين المراجعتين لصفحة: «Twig/recipes»
جميل-بيلوني (نقاش | مساهمات) ط مراجعة |
جميل-بيلوني (نقاش | مساهمات) طلا ملخص تعديل |
||
(2 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة) | |||
سطر 1: | سطر 1: | ||
{{DISPLAYTITLE:وصفات خاصة لمحرك القوالب Twig}} | {{DISPLAYTITLE:وصفات خاصة لمحرك القوالب Twig}} | ||
تعرض هذه الصفحة وصفات سرية تستحق الإطلاع عليها قد تساعدك في عملك مع محرك قوالب Twig ووضبطه وتخصيص استخدامك المتقدم له. | تعرض هذه الصفحة وصفات سرية تستحق الإطلاع عليها قد تساعدك في عملك مع محرك قوالب Twig ووضبطه وتخصيص استخدامك المتقدم له. | ||
== عرض إشعارات الإهمال | == عرض إشعارات الإهمال Deprecation Notices == | ||
تولِّد المزايا المهملة إشعارات إهمال من خلال استدعاء إلى الدالة <code>trigger_error()</code> في لغة [[PHP]]، وتُسكَت تلك الإشعارات افتراضيًا ولا تُعرض أو تسجَّل أبدًا، فإذا أردت إزالة جميع استخدامات المزايا المهملة من قوالبك فاكتب سكربت وشغلها مع الأسطر التالية:<syntaxhighlight lang="php"> | تولِّد المزايا المهملة إشعارات إهمال من خلال استدعاء إلى الدالة <code>trigger_error()</code> في لغة [[PHP]]، وتُسكَت تلك الإشعارات افتراضيًا ولا تُعرض أو تسجَّل أبدًا، فإذا أردت إزالة جميع استخدامات المزايا المهملة من قوالبك فاكتب سكربت وشغلها مع الأسطر التالية:<syntaxhighlight lang="php"> | ||
require_once __DIR__.'/vendor/autoload.php'; | require_once __DIR__.'/vendor/autoload.php'; | ||
سطر 23: | سطر 22: | ||
print_r($deprecations); | print_r($deprecations); | ||
</syntaxhighlight>لاحظ أن أغلب إشعارات الإهمال تُطلَق أثناء التصريف | </syntaxhighlight>لاحظ أن أغلب إشعارات الإهمال تُطلَق أثناء التصريف compilation، لذا لن تولَّد إذا كانت القوالب مخزَّنة أصلًا، وإذا أردت إدارة إشعارات الإهمال من اختبارات PHPUnit الخاصة بك فانظر حزمة [https://github.com/symfony/phpunit-bridge symfony/phpunit-bridge] إذ ستيسر عليك تلك المهمة. | ||
== جعل التخطيطات شرطية == | == جعل التخطيطات شرطية == | ||
إن العمل مع Ajax يعني أن بعض المحتوى قد يُعرض أحيانًا كما هو، وقد يزخرَف أحيانًا أخرى بتخطيط أو | إن العمل مع Ajax يعني أن بعض المحتوى قد يُعرض أحيانًا كما هو، وقد يزخرَف أحيانًا أخرى بتخطيط أو layout، وبما إن أسماء قوالب تخطيطات Twig قد تكون أي تعبير صالح فيمكنك تمرير متغير يقيَّم إلى <code>true</code> عند إنشاء الطلب من خلال Ajax، ويختار التخطيط وفقًا لذلك:<syntaxhighlight lang="twig"> | ||
{% extends request.ajax ? "base_ajax.html" : "base.html" %} | {% extends request.ajax ? "base_ajax.html" : "base.html" %} | ||
سطر 37: | سطر 36: | ||
لا يُشترط أن يكون اسم القالب عند إدراجه سلسلة نصية، إذ قد يعتمد الاسم مثلًا على قيمة متغير ما: <syntaxhighlight lang="twig"> | لا يُشترط أن يكون اسم القالب عند إدراجه سلسلة نصية، إذ قد يعتمد الاسم مثلًا على قيمة متغير ما: <syntaxhighlight lang="twig"> | ||
{% include var ~ '_foo.html' %} | {% include var ~ '_foo.html' %} | ||
</syntaxhighlight>إذا كانت <code>var</code> تقيَّم إلى <code>index</code> فسيتم تصيير | </syntaxhighlight>إذا كانت <code>var</code> تقيَّم إلى <code>index</code> فسيتم تصيير render القالب <code>index_foo.html</code>، وعمومًا قد يكون اسم القالب أي تعبير صالح، انظر:<syntaxhighlight lang="twig"> | ||
{% include var|default('index') ~ '_foo.html' %} | {% include var|default('index') ~ '_foo.html' %} | ||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 44: | سطر 43: | ||
يمكن تخصيص القالب بإحدى طريقتين: | يمكن تخصيص القالب بإحدى طريقتين: | ||
* '''الوراثة | * '''الوراثة inheritance''': يرث القالب من قالب أب parent template ويبدل override بعض الكتل الموروثة ويعدلها. | ||
* '''الاستبدال | * '''الاستبدال Replacement''': إذا كنت تستخدم محمِّل نظام ملفات فإن Twig يحمِّل أول قالب يجده في قائمة المجلدات المهيأة، ويحل القالب الموجود في المجلد مكان قالب آخر من مجلد أبعد في القائمة. | ||
لكن كيف نستبدل قالبًا يرث نفسه -قالب في مجلد أبعد في القائمة-؟ | لكن كيف نستبدل قالبًا يرث نفسه -قالب في مجلد أبعد في القائمة-؟ | ||
سطر 66: | سطر 65: | ||
== تخصيص البنية اللغوية == | == تخصيص البنية اللغوية == | ||
يسمح Twig ببعض التخصيصات في البنية اللغوية | يسمح Twig ببعض التخصيصات في البنية اللغوية syntax لمحدِّدات الكتل، ولا يُنصح باستخدام هذه الميزة بما أن القوالب ستكون مرتبطة ببنيتك المخصصة، لكن قد يكون ذلك هو الخيار الأنسب في بعض المشاريع الخاصة. ستحتاج إلى إنشاء كائن معجم lexer خاص بك لتغيير محددات الكتل :<syntaxhighlight lang="php"> | ||
$twig = new \Twig\Environment(...); | $twig = new \Twig\Environment(...); | ||
سطر 124: | سطر 123: | ||
== الوصول إلى السياق الأب في الحلقات التكرارية المتشعبة == | == الوصول إلى السياق الأب في الحلقات التكرارية المتشعبة == | ||
قد تحتاج أحيانًا عند استخدام الحلقات التكرارية المتشعبة | قد تحتاج أحيانًا عند استخدام الحلقات التكرارية المتشعبة nested loops إلى أن تصل إلى السياق الأب، ويتم ذلك عن طريق المتغير <code>loop.parent</code>، فمثلًا إذا كانت لديك بيانات القالب التالية:<syntaxhighlight lang="php"> | ||
$data = [ | $data = [ | ||
'topics' => [ | 'topics' => [ | ||
سطر 148: | سطر 147: | ||
== التعريف السريع للدوال غير المعرفة والمرشحات والوسوم == | == التعريف السريع للدوال غير المعرفة والمرشحات والوسوم == | ||
<blockquote>أضيف التابع <code>registerUndefinedTokenParserCallback()</code> في الإصدار 3.2 من Twig.</blockquote>إذا كانت الدالة غير معرَّفة -أو الوسم أو المرشح- فإن Twig يرفع اعتراض<code>\Twig\Error\SyntaxError</code> افتراضيًا، لكن قد يستدعي استدعاءً خلفيًا | <blockquote>أضيف التابع <code>registerUndefinedTokenParserCallback()</code> في الإصدار 3.2 من Twig.</blockquote>إذا كانت الدالة غير معرَّفة -أو الوسم أو المرشح- فإن Twig يرفع اعتراض<code>\Twig\Error\SyntaxError</code> افتراضيًا، لكن قد يستدعي استدعاءً خلفيًا callback قد يكون أي نوع بيانات "callable" صالح، والذي يعيد وسمًا أو دالة أو مرشحًا (فلتر). وبالنسبة للوسوم، سجِّل الاستدعاءات الخلفية باستخدام <code>registerUndefinedTokenParserCallback()</code>، أما المرشحات فسجلها باستخدام <code>registerUndefinedFilterCallback()</code>، وبالمثل بالنسبة للدوال، سجلها باستخدام <code>registerUndefinedFunctionCallback()</code>:<syntaxhighlight lang="php"> | ||
// Twig المضمنة لتكون دوال PHP سجل جميع دوال | // Twig المضمنة لتكون دوال PHP سجل جميع دوال | ||
// هذا غير آمن، ولا تنفذه في مشروع أبدًا | // هذا غير آمن، ولا تنفذه في مشروع أبدًا | ||
سطر 158: | سطر 157: | ||
return false; | return false; | ||
}); | }); | ||
</syntaxhighlight>إذا لم يستطع نوع البيانات "[[PHP/callable|callable]]" أن يعيد وسمًا صالحًا أو دالة أو مرشحًا صالحيْن فيجب أن يعيد <code>false</code>، وإذا سجلت أكثر من رد نداء callable واحد فسيستدعيها Twig إلى أن يعيد واحد منها شيئًا غير <code>false</code>. وبما أن حل | </syntaxhighlight>إذا لم يستطع نوع البيانات "[[PHP/callable|callable]]" أن يعيد وسمًا صالحًا أو دالة أو مرشحًا صالحيْن فيجب أن يعيد <code>false</code>، وإذا سجلت أكثر من رد نداء callable واحد فسيستدعيها Twig إلى أن يعيد واحد منها شيئًا غير <code>false</code>. وبما أن حل resolution الدوال والمرشحات والوسوم يتم أثناء التصريف فليس ثمة حمل زائد عند تسجيل هذه الاستدعاءات الخلفية. | ||
== التحقق من البنية اللغوية للقالب == | == التحقق من البنية اللغوية للقالب == | ||
سطر 179: | سطر 178: | ||
} | } | ||
} | } | ||
</syntaxhighlight>لاحظ أن هذا التابع لن يلتقط أي خروقات في سياسة صندوق الاختبار | </syntaxhighlight>لاحظ أن هذا التابع لن يلتقط أي خروقات في سياسة صندوق الاختبار sandbox لأن تلك السياسة تنفَّذ أثناء تصيير القالب بما أن Twig يحتاج إلى السياق لإجراء بعض الفحوصات مثل التوابع المسموح بها في الكائنات. | ||
== تحديث القوالب المعدلة عند تفعيل OPcache أو APC == | == تحديث القوالب المعدلة عند تفعيل OPcache أو APC == | ||
سطر 207: | سطر 206: | ||
== استخدام قاعدة بيانات لتخزين القوالب == | == استخدام قاعدة بيانات لتخزين القوالب == | ||
إذا كنت تطور نظامًا لإدارة محتوى | إذا كنت تطور نظامًا لإدارة محتوى Content Management System، فإن القوالب تُخزن حينها في قاعدة بيانات عادة، وتعطيك الوصفة التالية محملًا بسيطًا لقالب PDO تستطيع استخدامه كنقطة انطلاق تبني عليها. لننشئ أولًا قاعدة بيانات SQLite3 مؤقتة داخل الذاكرة للعمل معها:<syntaxhighlight lang="php"> | ||
$dbh = new PDO('sqlite::memory:'); | $dbh = new PDO('sqlite::memory:'); | ||
$dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)'); | $dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)'); | ||
سطر 299: | سطر 298: | ||
* تهريب محددات AngularJS بتغليف أقسامها بوسم <code>[[Twig/verbatim|{% verbatim %}]]</code> أو بتهريب كل محدد باستخدام <code>{{ '<nowiki>{{' }}</nowiki></code> و <code><nowiki>{{ '}}</nowiki>' }}</code>. | * تهريب محددات AngularJS بتغليف أقسامها بوسم <code>[[Twig/verbatim|{% verbatim %}]]</code> أو بتهريب كل محدد باستخدام <code>{{ '<nowiki>{{' }}</nowiki></code> و <code><nowiki>{{ '}}</nowiki>' }}</code>. | ||
* تغيير محددات أحد محركي القوالب وفقًا للمحرك الذي ستدخله آخرًا: | * تغيير محددات أحد محركي القوالب وفقًا للمحرك الذي ستدخله آخرًا: | ||
** إذا كنت ستدخِل AngularJS على Twig فغيِّر إقحام الوسوم باستخدام خدمة <code>interpolateProvider</code>، كما في حالة وقت تهيئة الوحدات | ** إذا كنت ستدخِل AngularJS على Twig فغيِّر إقحام الوسوم باستخدام خدمة <code>interpolateProvider</code>، كما في حالة وقت تهيئة الوحدات module initialization time: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
angular.module('myApp', []).config(function($interpolateProvider) { | angular.module('myApp', []).config(function($interpolateProvider) { | ||
سطر 321: | سطر 320: | ||
* [https://twig.symfony.com/doc/3.x/recipes.html صفحة Recipes في توثيق Twig الرسمي] | * [https://twig.symfony.com/doc/3.x/recipes.html صفحة Recipes في توثيق Twig الرسمي] | ||
[[تصنيف:Twig]] | [[تصنيف:Twig]] | ||
[[تصنيف: | [[تصنيف:Twig Intro]] | ||
المراجعة الحالية بتاريخ 06:02، 11 مايو 2021
تعرض هذه الصفحة وصفات سرية تستحق الإطلاع عليها قد تساعدك في عملك مع محرك قوالب Twig ووضبطه وتخصيص استخدامك المتقدم له.
عرض إشعارات الإهمال Deprecation Notices
تولِّد المزايا المهملة إشعارات إهمال من خلال استدعاء إلى الدالة trigger_error()
في لغة PHP، وتُسكَت تلك الإشعارات افتراضيًا ولا تُعرض أو تسجَّل أبدًا، فإذا أردت إزالة جميع استخدامات المزايا المهملة من قوالبك فاكتب سكربت وشغلها مع الأسطر التالية:
require_once __DIR__.'/vendor/autoload.php';
$twig = create_your_twig_env();
$deprecations = new \Twig\Util\DeprecationCollector($twig);
print_r($deprecations->collectDir(__DIR__.'/templates'));
يصرِّف التابع collectDir()
جميع القوالب الموجودة في المجلد ويلتقط إشعارات الإهمال ويعيدها، فإذا لم تكن قوالبك مخزَّنة في نظام الملفات فاستخدم التابع collect()
الذي يأخذ Traversable
الذي يجب أن يعيد بدوره أسماء قوالب كمفاتيح، ومحتويات قوالب كقيَم، كما في \Twig\Util\TemplateDirIterator
، لكن لن تعثر هذه الشيفرة على كل الإهمالات -كأصناف Twig المهملة مثلًا-، فسجِّل معالج خطأ مخصص لالتقاطها مثل المعالج أدناه:
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) {
if (E_USER_DEPRECATED === $type) {
$deprecations[] = $msg;
}
});
// شغِّل تطبيقك
print_r($deprecations);
لاحظ أن أغلب إشعارات الإهمال تُطلَق أثناء التصريف compilation، لذا لن تولَّد إذا كانت القوالب مخزَّنة أصلًا، وإذا أردت إدارة إشعارات الإهمال من اختبارات PHPUnit الخاصة بك فانظر حزمة symfony/phpunit-bridge إذ ستيسر عليك تلك المهمة.
جعل التخطيطات شرطية
إن العمل مع Ajax يعني أن بعض المحتوى قد يُعرض أحيانًا كما هو، وقد يزخرَف أحيانًا أخرى بتخطيط أو layout، وبما إن أسماء قوالب تخطيطات Twig قد تكون أي تعبير صالح فيمكنك تمرير متغير يقيَّم إلى true
عند إنشاء الطلب من خلال Ajax، ويختار التخطيط وفقًا لذلك:
{% extends request.ajax ? "base_ajax.html" : "base.html" %}
{% block content %}
This is the content to be displayed.
{% endblock %}
جعل الإدراج ديناميكي
لا يُشترط أن يكون اسم القالب عند إدراجه سلسلة نصية، إذ قد يعتمد الاسم مثلًا على قيمة متغير ما:
{% include var ~ '_foo.html' %}
إذا كانت var
تقيَّم إلى index
فسيتم تصيير render القالب index_foo.html
، وعمومًا قد يكون اسم القالب أي تعبير صالح، انظر:
{% include var|default('index') ~ '_foo.html' %}
استبدال قالب يرث نفسه
يمكن تخصيص القالب بإحدى طريقتين:
- الوراثة inheritance: يرث القالب من قالب أب parent template ويبدل override بعض الكتل الموروثة ويعدلها.
- الاستبدال Replacement: إذا كنت تستخدم محمِّل نظام ملفات فإن Twig يحمِّل أول قالب يجده في قائمة المجلدات المهيأة، ويحل القالب الموجود في المجلد مكان قالب آخر من مجلد أبعد في القائمة.
لكن كيف نستبدل قالبًا يرث نفسه -قالب في مجلد أبعد في القائمة-؟
لنقل أنك قوالبك حُمِّلت من كل من .../templates/mysite
و .../templates/default
على الترتيب، فعندئذ يكون القالب page.twig
المخزَّن في .../templates/default
كما يلي:
{# page.twig #}
{% extends "layout.twig" %}
{% block content %}
{% endblock %}
تستطيع استبدال هذا القالب من خلال وضع ملف بنفس الاسم في .../templates/mysite
، وإذا أردت وراثة القالب الأصلي فربما تكتب شيئًا كما يلي:
{# page.twig in .../templates/mysite #}
{% extends "page.twig" %} {# from .../templates/default #}
غير أن هذا لن يعمل بما أن Twig يحمّل القالب من .../templates/mysite
، لكن تبين أننا نستطيع إصلاح ذلك بإضافة مجلد في نهاية مجلدات القوالب لديك، وسيكون أبًا (مجلدًا رئيسيًا) لجميع المجلدات الأخرى وهو .../templates
في حالتنا نحن. وهذا يجعل كل ملف قالب داخل نظامنا له عنوان فريد.
ورغم أنك ستستخدم المسارات العادية أغلب الوقت، لكن ستكون ثمة حالات خاصة تريد فيها وراثة قالب عبر تخطي نسخة منه فتستطيع الإشارة إلى مسار القالب الكامل للمجلد الأب له في وسم extends
:
{# page.twig in .../templates/mysite #}
{% extends "default/page.twig" %} {# from .../templates #}
لاحظ أن هذه الوصفة مستقاة من هذه الصفحة من ويكي Django.
تخصيص البنية اللغوية
يسمح Twig ببعض التخصيصات في البنية اللغوية syntax لمحدِّدات الكتل، ولا يُنصح باستخدام هذه الميزة بما أن القوالب ستكون مرتبطة ببنيتك المخصصة، لكن قد يكون ذلك هو الخيار الأنسب في بعض المشاريع الخاصة. ستحتاج إلى إنشاء كائن معجم lexer خاص بك لتغيير محددات الكتل :
$twig = new \Twig\Environment(...);
$lexer = new \Twig\Lexer($twig, [
'tag_comment' => ['{#', '#}'],
'tag_block' => ['{%', '%}'],
'tag_variable' => ['{{', '}}'],
'interpolation' => ['#{', '}'],
]);
$twig->setLexer($lexer);
انظر المثال التالي الذي يوضح بعض الإعدادات التي تحاكي البنية اللغوية لمحركات قوالب أخرى:
// Ruby erb syntax
$lexer = new \Twig\Lexer($twig, [
'tag_comment' => ['<%#', '%>'],
'tag_block' => ['<%', '%>'],
'tag_variable' => ['<%=', '%>'],
]);
// SGML Comment Syntax
$lexer = new \Twig\Lexer($twig, [
'tag_comment' => ['<!--#', '-->'],
'tag_block' => ['<!--', '-->'],
'tag_variable' => ['${', '}'],
]);
// Smarty like
$lexer = new \Twig\Lexer($twig, [
'tag_comment' => ['{*', '*}'],
'tag_block' => ['{', '}'],
'tag_variable' => ['{$', '}'],
]);
استخدام الخصائص الديناميكية للكائن
يحاول Twig حين يقابل متغيرًا مثل article.title
أن يجد خاصية title
عامة في كائن article
، وهذا يصلح أيضًا إذا كانت الخاصية غير موجودة لكنها معرَّفة ديناميكيًا بفضل التابع _get()
، فتحتاج حينئذ أن تستخدم التابع _isset()
كما هو موضح في الشيفرة التالية:
class Article
{
public function __get($name)
{
if ('title' == $name) {
return 'The title';
}
// ارفع خطأً ما هنا
}
public function __isset($name)
{
if ('title' == $name) {
return true;
}
return false;
}
}
الوصول إلى السياق الأب في الحلقات التكرارية المتشعبة
قد تحتاج أحيانًا عند استخدام الحلقات التكرارية المتشعبة nested loops إلى أن تصل إلى السياق الأب، ويتم ذلك عن طريق المتغير loop.parent
، فمثلًا إذا كانت لديك بيانات القالب التالية:
$data = [
'topics' => [
'topic1' => ['Message 1 of topic 1', 'Message 2 of topic 1'],
'topic2' => ['Message 1 of topic 2', 'Message 2 of topic 2'],
],
];
والقالب التالي من أجل عرض جميع الرسائل في كل الموضوعات:
{% for topic, messages in topics %}
* {{ loop.index }}: {{ topic }}
{% for message in messages %}
- {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }}
{% endfor %}
{% endfor %}
فإن الخرج سيكون شبيهًا بما يلي:
* 1: topic1
- 1.1: The message 1 of topic 1
- 1.2: The message 2 of topic 1
* 2: topic2
- 2.1: The message 1 of topic 2
- 2.2: The message 2 of topic 2
يُستخدم المتغير loop.parent
في الحلقة الداخلية للوصول إلى السياق الخارجي، لذا يمكن الوصول إلى فهرس الموضوع topic
الحالي المعرَّف في حلقة for
الخارجية من خلال المتغير loop.parent.loop.index
.
التعريف السريع للدوال غير المعرفة والمرشحات والوسوم
أضيف التابع
registerUndefinedTokenParserCallback()
في الإصدار 3.2 من Twig.
إذا كانت الدالة غير معرَّفة -أو الوسم أو المرشح- فإن Twig يرفع اعتراض\Twig\Error\SyntaxError
افتراضيًا، لكن قد يستدعي استدعاءً خلفيًا callback قد يكون أي نوع بيانات "callable" صالح، والذي يعيد وسمًا أو دالة أو مرشحًا (فلتر). وبالنسبة للوسوم، سجِّل الاستدعاءات الخلفية باستخدام registerUndefinedTokenParserCallback()
، أما المرشحات فسجلها باستخدام registerUndefinedFilterCallback()
، وبالمثل بالنسبة للدوال، سجلها باستخدام registerUndefinedFunctionCallback()
:
// Twig المضمنة لتكون دوال PHP سجل جميع دوال
// هذا غير آمن، ولا تنفذه في مشروع أبدًا
$twig->registerUndefinedFunctionCallback(function ($name) {
if (function_exists($name)) {
return new \Twig\TwigFunction($name, $name);
}
return false;
});
إذا لم يستطع نوع البيانات "callable" أن يعيد وسمًا صالحًا أو دالة أو مرشحًا صالحيْن فيجب أن يعيد false
، وإذا سجلت أكثر من رد نداء callable واحد فسيستدعيها Twig إلى أن يعيد واحد منها شيئًا غير false
. وبما أن حل resolution الدوال والمرشحات والوسوم يتم أثناء التصريف فليس ثمة حمل زائد عند تسجيل هذه الاستدعاءات الخلفية.
التحقق من البنية اللغوية للقالب
قد ترغب في التحقق من البنية اللغوية للقالب إذا جاءت شيفرته من طرف ثالث -من واجهة ويب مثلًا-. انظر كيف تتحقق منها إذا كانت شيفرة القالب مخزنة في متغير $template
:
try {
$twig->parse($twig->tokenize(new \Twig\Source($template)));
// صالح $template المتغير
} catch (\Twig\Error\SyntaxError $e) {
// على خطأ لغوي أو أكثر $template يحتوي المتغير
}
إذا نفذت تكرارًا على مجموعة من الملفات فتستطيع تمرير اسم الملف إلى التابع tokenize()
للحصول على اسم الملف في رسالة الاعتراض:
foreach ($files as $file) {
try {
$twig->parse($twig->tokenize(new \Twig\Source($template, $file->getFilename(), $file)));
// صالح $template المتغير
} catch (\Twig\Error\SyntaxError $e) {
// على خطأ لغوي أو أكثر $template يحتوي المتغير
}
}
لاحظ أن هذا التابع لن يلتقط أي خروقات في سياسة صندوق الاختبار sandbox لأن تلك السياسة تنفَّذ أثناء تصيير القالب بما أن Twig يحتاج إلى السياق لإجراء بعض الفحوصات مثل التوابع المسموح بها في الكائنات.
تحديث القوالب المعدلة عند تفعيل OPcache أو APC
إذا كنت تستخدم OPcache وكان opcache.validate_timestamps
مضبوطًا على 0
أو كنت تستخدم APC وكان apc.stat
مضبوطًا على 0
، فلن يتم تحديث الذاكرة المؤقتة للقالب بمجرد إفراغها. ولحل ذلك، أجبر Twig على إبطال ذاكرة bytecode المؤقتة:
$twig = new \Twig\Environment($loader, [
'cache' => new \Twig\Cache\FilesystemCache('/some/cache/path', \Twig\Cache\FilesystemCache::FORCE_BYTECODE_INVALIDATION),
// ...
]);
إعادة استخدام زائر عقدة كبير
عند إلحاق زائر بنسخة من \Twig\Environment
فإن Twig يستخدمه لزيارة جميع القوالب التي يصرِّفها، فإذا أردت الإبقاء على بعض بيانات الحالة فربما تود إعادة ضبطها عند زيارة قالب جديد، ويمكن فعل هذا بالشيفرة التالية:
protected $someTemplateState = [];
public function enterNode(\Twig\Node\Node $node, \Twig\Environment $env)
{
if ($node instanceof \Twig\Node\ModuleNode) {
// إعادة ضبط الحالة عند الدخول إلى قالب جديد.
$this->someTemplateState = [];
}
// ...
return $node;
}
استخدام قاعدة بيانات لتخزين القوالب
إذا كنت تطور نظامًا لإدارة محتوى Content Management System، فإن القوالب تُخزن حينها في قاعدة بيانات عادة، وتعطيك الوصفة التالية محملًا بسيطًا لقالب PDO تستطيع استخدامه كنقطة انطلاق تبني عليها. لننشئ أولًا قاعدة بيانات SQLite3 مؤقتة داخل الذاكرة للعمل معها:
$dbh = new PDO('sqlite::memory:');
$dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)');
$base = '{% block content %}{% endblock %}';
$index = '
{% extends "base.twig" %}
{% block content %}Hello {{ name }}{% endblock %}
';
$now = time();
$dbh->prepare('INSERT INTO templates (name, source, last_modified) VALUES (?, ?, ?)')->execute(['base.twig', $base, $now]);
$dbh->prepare('INSERT INTO templates (name, source, last_modified) VALUES (?, ?, ?)')->execute(['index.twig', $index, $now]);
إن ما أنشأناه كان جدول templates
بسيط يستضيف قالبين هما base.twig
و index.twig
. لنعرِّف الآن محملًا قادرًا على استخدام قاعدة البيانات تلك:
class DatabaseTwigLoader implements \Twig\Loader\LoaderInterface
{
protected $dbh;
public function __construct(PDO $dbh)
{
$this->dbh = $dbh;
}
public function getSourceContext(string $name): Source
{
if (false === $source = $this->getValue('source', $name)) {
throw new \Twig\Error\LoaderError(sprintf('Template "%s" does not exist.', $name));
}
return new \Twig\Source($source, $name);
}
public function exists(string $name)
{
return $name === $this->getValue('name', $name);
}
public function getCacheKey(string $name): string
{
return $name;
}
public function isFresh(string $name, int $time): bool
{
if (false === $lastModified = $this->getValue('last_modified', $name)) {
return false;
}
return $lastModified <= $time;
}
protected function getValue($column, $name)
{
$sth = $this->dbh->prepare('SELECT '.$column.' FROM templates WHERE name = :name');
$sth->execute([':name' => (string) $name]);
return $sth->fetchColumn();
}
}
وفيما يلي مثال على كيفية استخدامه:
$loader = new DatabaseTwigLoader($dbh);
$twig = new \Twig\Environment($loader);
echo $twig->render('index.twig', ['name' => 'Fabien']);
استخدام مصادر مختلفة للقوالب
الوصفة التالية تمامٌ على ما قبلها، فحتى لو كنت خزنت القوالب التي كتبتها في قاعدة بيانات فستحتاج إلى تخزين القوالب الأساسية أو الأصلية في نظام الملفات، وستحتاج إلى استخدام المحمِّل \Twig\Loader\ChainLoader
إذا أمكن تحميل القوالب من مصادر مختلفة.
ونحن نشير إلى القالب بنفس الطريقة التي نشير بها إلى محمل نظام تشغيل عادي، كما ترى في الوصفة السابقة، وهذا هو سر قدرتنا على خلط القوالب القادمة من قاعدة البيانات أو نظام الملفات أو أي محمل آخر ومن ثم مطابقتها، إذ يجب أن يكون اسم القالب اسمًا منطقيًا وليس مسارًا من نظام الملفات:
$loader1 = new DatabaseTwigLoader($dbh);
$loader2 = new \Twig\Loader\ArrayLoader([
'base.twig' => '{% block content %}{% endblock %}',
]);
$loader = new \Twig\Loader\ChainLoader([$loader1, $loader2]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index.twig', ['name' => 'Fabien']);
تعرَّف قوالب base.twig
الآن في محمل مصفوفة تستطيع حذفها من قاعدة البيانات دون تعطيل أي شيء.
تحميل قالب من سلسلة نصية
تستطيع تحميل قالب مخزن في سلسلة نصية من قالب آخر عن طريق الدالة template_from_string
، من التوسعة \Twig\Extension\StringLoaderExtension
:
{{ include(template_from_string("Hello {{ name }}")) }}
وتستطيع تحميل القالب المخزن في سلسلة نصية من PHP عن طريق \Twig\Environment::createTemplate()
:
$template = $twig->createTemplate('hello {{ name }}');
echo $template->render(['name' => 'Fabien']);
استخدام Twig و AngularJS في نفس القالب
لا يُحبَّذ خلط بنى لغوية لقوالب مختلفة في نفس الملف بما أن Twig و AngularJS يستخدمان نفس المحدِّدات {{
و }}
في بنياتهما. لكن إذا أردت استخدام Twig و AngularJS في نفس القالب فثم طريقتين تختار إحداهما وفقًا لمقدار ما تريد إدخاله من AngularJS في قوالبك:
- تهريب محددات AngularJS بتغليف أقسامها بوسم
{% verbatim %}
أو بتهريب كل محدد باستخدام{{ '{{' }}
و{{ '}}' }}
. - تغيير محددات أحد محركي القوالب وفقًا للمحرك الذي ستدخله آخرًا:
- إذا كنت ستدخِل AngularJS على Twig فغيِّر إقحام الوسوم باستخدام خدمة
interpolateProvider
، كما في حالة وقت تهيئة الوحدات module initialization time:
- إذا كنت ستدخِل AngularJS على Twig فغيِّر إقحام الوسوم باستخدام خدمة
angular.module('myApp', []).config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[').endSymbol(']}');
});
- أما إذا كان Twig هو الثاني فغير المحدِّدات باستخدام الخيار المعجمي
tag_variable
:
- أما إذا كان Twig هو الثاني فغير المحدِّدات باستخدام الخيار المعجمي
$env->setLexer(new \Twig\Lexer($env, [
'tag_variable' => ['{[', ']}'],
]));
انظر أيضًا
- المكونات الداخلية لمحرك القوالب Twig
- محرك Twig لمصممي القوالب
- معايير كتابة الشيفرات في محرك القوالب Twig