Создание настроек сайта

Материал из Wiki from ADT Web Solutions
Перейти к навигации Перейти к поиску

Выбираем в админке раздел "Настройки сайта" и не видим никаких настроек:

Screenshot 2020-10-30 UMI CMS - Настройки.png

Жмём "Создать настройки", и создаём:

Screenshot 2020-10-30 UMI CMS - Создание.png

Название может быть любое, идентификатор - только латиница. Если создаем настройки для русской версии сайта, на английской они видны не будут. Что в принципе логично.

Теперь видим, что настройки появились:

Screenshot 2 UMI CMS - Настройки (2).png

Вопрос только - что с ними делать? Ставим рядом галку, в пиктографическом меню нажимаем "Редактировать" - и видим ту же самую форму, что только что заполнили. Где логотип, где копирайт? Так мы незаметно подошли к большой теме - Создание шаблонов данных.

Вывод настроек в шаблоне

Добавим в настройки логотип и копирайт:

Screenshot 4 UMI CMS - Редактирование.png

Теперь попробуем вывести всё это на страницах сайта.

И тут мы сталкиваемся с очередной засадой UMI CMS. Казалось бы, каждому сайту должен соответствовать какой-то один набор настроек. Но в интерфейсе видим, что этих наборов можно создать сколько угодно. Господа разработчики, может, стоило бы для упрощения ограничить эти возможности? Кто-то вообще использует больше одного набора настроек для конкретной языковой версии сайта? Было бы шикарно получать настройки прямо в массиве $variables, как вы считаете?

Зато есть повод поупражняться с API системы. Один из способов получить настройки - использовать заданный нами идентификатор настроек, в данном случае 'demo':

$settings = $this->getObjectById($this->macros('umiSettings', 'getIdByName', 'demo']));
var_dump($settings);

Здесь мы использовали метод getIdByName('...') модуля umiSettings для получения id настроек по названию (это именно название, не идентификатор), а потом получили сам объект настроек при помощи метода getObjectById().

Добавим этот код в самое начало common.phtml. К счастью, в настройках разных языковых версий можно задавать один и тот же идентификатор, а то было бы совсем грустно. В общем, получилось. Если добавить на страницу <?= $settings->copyright ?>, то увидим копирайт, который ввели.

Теперь попробуем другой путь, ведь мы не фанаты делать кучу настроек:

$set = new selector('objects');
$set->types('object-type')->name('umiSettings', 'settings');
$set->where('domain_id')->equals($variables['domain-id']);
$set->where('lang_id')->equals($variables['lang-id']);
$set->limit(0, 1);
$settings = $set->result(); 
var_dump($settings);

В этом коде был использован самый мощный класс ядра UMI - selector. Он подробно описан в документации. Чего в документации нет, так это - что подставлять в качестве 'object-type'. Но в админке есть где посмотреть: 'Шаблоны данных' - 'Настройки модуля' (ссылка справа вверху). Для начала лучше в этих настройках ничего не менять, но в качестве справочника - бесценно!

Здесь мы ищем селектором те единственные настройки, что соответствуют конкретной языковой версии нашего сайта. Синтаксически это почти SQL-запрос, на мой взгляд, тут всё просто.

UMI CMS в конце каждой страницы выдает время её формирования, что очень удобно. Легко убедиться, что второй способ на 0.001 секунды быстрее, помимо прочих его преимуществ. Конечно, неплохо бы проверить, что хоть какие-то настройки нашлись. Кроме этого, хотелось бы получить настройки в самом начале, а использовать их в произвольных фрагментах нашего шаблона. В результате модифицируем код common.phtml как-то так:

<?php
$set = new selector('objects');
$set->types('object-type')->name('umiSettings', 'settings');
$set->where('domain_id')->equals($variables['domain-id']);
$set->where('lang_id')->equals($variables['lang-id']);
$set->limit(0, 1);
$variables['settings'] = array_shift($set->result()); 
if (empty($variables['settings'])) {
    echo $this->translate('no settings');
    exit();
}
?>
<!DOCTYPE html>
<html>
<?= $this->render($variables, 'layout/head') ?>
<body>
<?= $this->render($variables, 'layout/header') ?>
<?= $this->render($variables, 'layout/main') ?>
<?= $this->render($variables, 'layout/footer') ?>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
</body>
</html>

Копирайт мы собирались использовать в подвале сайта, поэтому пишем в footer.phtml:

    <footer>
        <div class="container">
<?= $variables['settings']->copyright ?><?= date("Y") ?>

        </div>
    </footer>

Проверяем результат - всё получилось! Теперь надо разобраться с логотипом. Добавляем <?php var_dump($variables['settings']->logo); ?> в файл header.phtml, и видим, что это объект. Причем - ещё одна засада UMI CMS - все свойства без исключения protected!!! Зато в нем есть все, что нам нужно. Итак, изучаем документацию по классам umiFile и umiImageFile, и новый header.phtml будет выглядеть примерно так:

<?php
$pageId = isset($variables['pageId'])?$variables['pageId']:0;
$menuTree = $this->macros('content', 'menu', [0, 2, 0, true, $pageId]);
$logo = $variables['settings']->logo;
?>
    <header>
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="/">
<?php if ($logo): ?>
                <img src="/<?= $logo->getFilePath() ?>" title="<?= $logo->getTitle() ?>" alt="<?= $logo->getAlt() ?>">
<?php endif; ?>
            </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
<?php 
    foreach ($menuTree['lines'] as $item) {
        $dropdown = !empty($item['items']['nodes:item']);
        $active = !empty($item['attribute:status']);
        if (isset($item['link']) && isset($item['name'])) {
            if ($dropdown) {
?>
                    <li class="nav-item dropdown <?=$active?'active':''?>">
                        <a class="nav-link dropdown-toggle" href="<?= $item['link'] ?>" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><?= $item['name'] ?></a>
                        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
<?php
                foreach ($item['items']['item'] as $sub) {
                    if (isset($sub['link']) && isset($sub['name'])) {
?>
                            <a class="dropdown-item" href="<?= $sub['link'] ?>"><?= $sub['name'] ?></a>
<?php
                    }
                }
?>
                        </div>
                    </li>
<?php
            } else {
?>
                    <li class="nav-item  <?=$active?'active':''?>">
                        <a class="nav-link" href="<?= $item['link'] ?>"><?= $item['name'] ?></a>
                    </li>
<?php
            }
        }
    }
?>
                </ul>
            </div>
        </nav>
    </header>

Почему перед адресом изображения стоит '/'? Потому что getFilePath() зачем-то перед адресом ставит точку, хоть адрес возвращает абсолютный. Загадка. В качестве alt и title пробуем получить значения, которые должны были задать в админке при заливке файла. Но поскольку ничего не задали, они будут пустые. А вообще, по-хорошему, надо добавить в настройки еще одно поле - название компании, и выводить именно его.

Edit-in-place для настроек

Теперь осталось добавить возможность изменять эти поля прямо на сайте. В принципе, ничего сложного:

<img umi:object-id="<?= $logo->getId() ?>" umi:field-name="logo" src="/<?= $logo->getFilePath() ?>" title="<?= $logo->getTitle() ?>" alt="<?= $logo->getAlt() ?>">

Это для логотипа, а для копирайта:

    <span umi:object-id="<?= $logo->getId() ?>" umi:field-name="logo" umi:empty="<?= $this->translate('empty_copyright') ?>">
<?= $variables['settings']->copyright ?>
    </span> <?= date("Y") ?>

Заметим, что псевдо-атрибуты для id контентных страниц и объектов отличаются, если для страниц мы использовали атрибут umi:element-id, то для объектов приходится писать umi:object-id. Это отражение внутреннего деления UMI CMS на страницы контента и объекты, за работу с которыми отвечают разные методы.

Также пришлось добавить дополнительный <span>, чтобы копирайт был в отдельном контейнере.

Другие модули системы

Пока нам для сайта хватало модуля content, немного использовали umiSettings. Однако полезных модулей гораздо больше, и пора наконец добавить на сайт раздел Новости.