Так давайте еще немного потерзаем наш второй проект.
Добавление активного класса
Помните вам в 3-ем задании надо было подсвечивать активный пункт в меню и там мы использовали <?= $is_image ? "active" : '' ?>
.
Теперь посмотрим как это делать в Twig. Можно, в принципе, использовать условный оператор.
Например, я хочу, чтобы на главной страницы был добавлен класс “active”. Делается это так:
<div>
<a href="/" class="{% if title == 'Главная' %}active{% endif %}">Главная</a>
<a href="/mermaid">Русалка</a>
<a href="/uranus">Уран</a>
</div>
выглядит немного проще чем на чистом php, но все равно громоздко.
К счастью в twig эту конструкцию можно записать в упрощённом виде с использование тернарного оператора, вот так:
<div>
<a href="/" class="{{ title == 'Главная' ? 'active' : '' }}">Главная</a>
<a href="/mermaid">Русалка</a>
<a href="/uranus">Уран</a>
</div>
так как это однострочная операция тут используются двойные фигурные скобки {{ ... }}
А на самом деле есть еще более простая форма записи, вот так:
<div>
<a href="/" class="{{ title == 'Главная' ? 'active' }}">Главная</a>
<a href="/mermaid">Русалка</a>
<a href="/uranus">Уран</a>
</div>
то есть, если вы после двоеточия выдаете пустую строку, то прописывать это не обязательно.
Формируем навигацию динамически
Сейчас у нас навигация делается вручную, то есть мы прописываем каждую ссылку прямо в разметке. Это нормально, когда пунктов меню мало, но создает проблемы, когда их становится много и еще если каждый надо стилизовать как-нибудь.
Для этих целей в twig встроена возможность создавать элементы в цикле. То есть у вас условно есть список элементов меню, а в шаблоне вы просто проходитесь по этому списку и динамически создаете элементы. И даже если у вас 100 пунктов меню вы разметку прописываете только для одного.
Давайте сделаем список под меню в index.php, вот так:
// ...
$title = "";
$template = "";
$context = [];
$menu = [ // добавил список словариков
[
"title" => "Главная",
"url" => "/",
],
[
"title" => "Русалка",
"url" => "/mermaid",
],
[
"title" => "Уран",
"url" => "/uranus",
]
];
// ...
теперь запихаем это в контекст:
// ...
$context['title'] = $title;
$context['menu'] = $menu; // передаем меню в контекст
echo $twig->render($template, $context);
и обновим шаблон __layout.twig
чтобы он создавал меню на основании этого списка:
<body>
<!-- ЭТО УБИРАЕМ
<div>
<a href="/">Главная</a>
<a href="/mermaid">Русалка</a>
<a href="/uranus">Уран</a>
</div>-->
<div> <!-- добавляем цикл по всем элементам меню -->
{% for item in menu %}
<!--так как item это словарик с двумя ключами, используем их для вывода ссылки -->
<a href="{{item.url}}">{{item.title}}</a>
{% endfor %}
</div>
{% block content %}
пустота
{% endblock %}
</body>
плюс можно и на активный элемент тут сразу проверять:
<div>
{% for item in menu %}
<a href="{{item.url}}" class="{{ title == item.title ? 'active' }}">{{item.title}}</a>
{% endfor %}
</div>
добавим какой-нибудь стиль для активной ссылки, чтобы лучше было видно:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
<style>
/* добавил стиль */
a.active {
background-color: yellow;
}
</style>
</head>
<body>
<div>
{% for item in menu %}
<a href="{{item.url}}" class="{{ title == item.title ? 'active' }}">{{item.title}}</a>
{% endfor %}
</div>
<!-- ... -->
</body>
</html>
и протестим:
работает! =)
Многоуровневое наследование шаблонов
Согласно заданию у вас есть главный шаблон, а есть еще шаблон объекта, который наследует главный шаблон. И этот шаблон объекта должен наследоваться шаблонами, уточняющими отображение объекта шаблона.
И допустим я хочу, чтобы для объектов писалась какая-нибудь фраза которая использует $title
ну как-то так:
давайте попробуем наследовать шаблон base_image от __object
ну типа чтобы у нас надпись была сверху и плюс еще картинка. Попробуем сначала так:
{% extends "__object.twig" %}
{% block content %}
<img src="{{ image }}" style="width: 300px;"/>
{% endblock %}
смотрим:
хм, почему-то ничего не поменялось…
В чем же дело?
Дело в том что наш шаблон base_image переопределяет содержимое блока {% block content %}{% endblock %}, и из-за этого фраза, которая там присутствует в шаблоне __object
теряется.
Поэтому, когда вы делаете двухуровненвое наследование надо внутри нового шаблона, в нашем случае __object
, определять новый блок внутри блока content, с другим именем. Вот так:
{% extends "__layout.twig" %}
{% block content %}
<div>
{{title}} -- чудо природы
</div>
{% block objectContent %}
{% endblock %}
{% endblock %}
в качестве имени objectContent
можно использовать что угодно, я вот решил так назвать, вы можете по-другому. Но суть в том, что теперь в base_image.twig
вы должны переопределять содержимое не {% block content %}{% endblock %}
а {% block objectContent %}{% endblock %}
, следующим образом
{% extends "__object.twig" %}
{% block objectContent %}<!-- поменял тут content на objectContent -->
<img src="{{ image }}" style="width: 300px;"/>
{% endblock %}
смотрим:
то что надо)
Понятно, что в данном примере такая иерархия избыточна. Но если у вас у того же Урана есть какой-то набор своих пунктов меню, это именно то что вам надо.
Что примерно должно получится
Можно теперь вернуться к основному проекту. Возникнет сразу вопрос, как туда все подключать и как там писать код. Должно получится что-то такое: