Расширение функциональности модулей: различия между версиями

Материал из Wiki from ADT Web Solutions
Перейти к навигации Перейти к поиску
Строка 93: Строка 93:
 
<?php
 
<?php
  
 +
    /** Сервисные классы, которые понадобятся для выполнения методов */
 
     use UmiCms\Classes\System\Utils\Captcha\Strategies\GoogleRecaptcha;
 
     use UmiCms\Classes\System\Utils\Captcha\Strategies\GoogleRecaptcha;
 
     use UmiCms\Service;
 
     use UmiCms\Service;
Строка 102: Строка 103:
 
</pre>
 
</pre>
  
Далее, открываем файл config.ini
+
Далее, открываем файл config.ini, который перед этим создали в папке шаблона, там уже есть настройки для "причёсывания" отдаваемых методами массивов, и добавляем туда 2 строчки:
 +
 
 +
<pre>
 +
[php-templater]
 +
extensions[] = "/templates/default/php/library/PhpExtension"
 +
</pre>
 +
 
 +
'''Важно!''' Имя класса в принципе может быть любым, но имя файла, содержащего этот класс, а также путь к файлу, прописанный в конфиге, должны в точности его повторять, вплоть до капитализации.
 +
 
 +
Поскольку extensions - это массив, понятно, что таких классов расширений можно добавить сколько угодно. Но нам хватит и одного.
 +
 
 +
Все публичные методы этого класса теперь будут доступны в шаблоне при помощи волшебной переменной $this. Но лучше это посмотреть на примере.
 +
 
 +
=== Добавление глобальных переменных ===
 +
 
 +
Ранее мы сделали одну не очень красивую вещь - добавили полученные прямо в шаблоне настройки к массиву $variables, и вынуждены были и дальше передавать их в методе render(), чтобы не потерялись. Значительно лучше было бы создать какие-то глобальные переменные, которые были бы доступны в любом фрагменте нашего шаблона.
 +
 
 +
Итак, добавляем в наш класс расширения следующие функции:
 +
 
 +
<pre>
 +
<?php
 +
 
 +
    /** Сервисные классы, которые понадобятся для выполнения методов */
 +
    use UmiCms\Classes\System\Utils\Captcha\Strategies\GoogleRecaptcha;
 +
    use UmiCms\Service;
 +
 
 +
    /** Расширение php шаблонизатора для шаблона default */
 +
    class PhpExtension extends ViewPhpExtension {
 +
 
 +
        /**
 +
        * Инициализирует общие переменные для шаблонов.
 +
        * @param array $variables глобальные переменные запроса
 +
        */
 +
        public function initializeCommonVariables($variables) {
 +
            $templateEngine = $this->getTemplateEngine();
 +
            $templateEngine->setCommonVar('domain', $variables['domain']);
 +
            $templateEngine->setCommonVar('lang', $variables['lang']);
 +
            $templateEngine->setCommonVar('settings', $this->requestSettingsContainer());
 +
        }
 +
 
 +
        /**
 +
        * Запрашивает актуальный объект настроек и возвращает его
 +
        * @return bool|iUmiObject
 +
        */
 +
        public function requestSettingsContainer() {
 +
/** @var umiSettings|UmiSettingsMacros $module */
 +
$module = cmsController::getInstance()
 +
->getModule('umiSettings');
 +
$id = $module->getIdByCustomId('gofroart');
 +
return umiObjectsCollection::getInstance()
 +
->getObject($id);
 +
        }
 +
 
 +
    }
 +
</pre>

Версия 23:51, 3 ноября 2020

Некоторые методы UMI CMS оставляют желать лучшего. Например, метод lastlist модуля news не возвращает значение поля anons новости, который может понадобиться в списке новостей. Можно ли с этим что-то сделать?

Кастомные методы стандартных модулей

Открываем директорию /classes/components/news и видим там файлы macros.php и customMacros.php. В файле macros.php находим функцию lastlist(), копируем её и целиком вставляем в customMacros.php после строки public $module;.

Находим там кусок кода:

$line_arr = [];
$line_arr['attribute:id'] = $element_id;
$line_arr['node:name'] = $element->getName();
$line_arr['attribute:link'] = $umiLinksHelper->getLinkByParts($element);
$line_arr['xlink:href'] = 'upage://' . $element_id;
$line_arr['void:header'] = $lines_arr['name'] = $element->getName();

Там и правда не добавляется анонс. Поэтому вставляем одну строчку:

$line_arr['attribute:anons'] = $element->anons;

Все эти node: и attribute: предназначены для других шаблонизаторов, но лучше их сохранить для общности.

Теперь при вызове метода lastlist() получим также и элемент массива 'anons'.

Что будет, если внести исправления сразу в файл macros.php? Очевидно, что все исправления будут потеряны при очередном обновлении системы.

Сразу замечу, что переопределять стандартные методы - ОЧЕНЬ ДУРНАЯ ПРАКТИКА. Если с сайтом будет работать другой программист, ему придется потратить кучу сил и времени на поиск ошибки, ведь он будет уверен, что вызывается стандартный метод. Поэтому ВСЕГДА, скопировав код стандартного метода, ПЕРЕИМЕНОВЫВАЙТЕ ЕГО! Пусть этот метод будет целиком и полностью кастомным, и это будет видно уже при вызове. И тогда возникает следующая задача - настройка разрешений.

Настройка разрешений для выполнения метода

Да, переопределение метода - нехороший поступок, но когда мы так делаем, автоматически избегаем множества проблем. Дело в том, что в UMI CMS есть сложная система разрешений, для каждого модуля существует собственный набор, посмотреть его можно в папке модуля в файле permissions.php.

Когда мы создаем метод с новым именем, то он не будет выполняться, т к отсутствует в файле permissions.php. Но это можно исправить, создав в той же папке модуля файл permissions.custom.php.

Предположим, по аналогии с методом lastlist() мы создали метод newslist(), куда внесли все необходимые нам изменения. Если посмотреть содержимое файла permissions.php, увидим, что это массив:

    /** Группы прав на функционал модуля */
    $permissions = [
        /** Права на просмотр новостей */
        'view' => [
            'lastlist',
            'listlents',
            'rubric',
        /** ... и так далее, не буду приводить его целиком */
        ]
    ];

По логике, нам надо добавить один элемент в массив $permissions['view'], поэтому в файле permissions.custom.php пишем:

$permissions['view'][] =  'newslist';

Интересный факт: даже если название метода содержит буквы с разной капитализацией, в этом массиве все нужно писать маленькими буквами. Не спрашивайте, почему.

Пока всё просто? Это только кажется. В каждом модуле структура и ключи массива разрешений разные, и в них нет никакой системы. Хорошо, если метод должен быть общедоступным, как правило, можно угадать, в какой именно массив его добавлять. Сложнее, если доступ можно давать только авторизоваанным пользователям, и то не всем. Так что - удачи!

Кастомные методы внутри шаблона

Описанный выше способ хорош, но добавленный код находится вне нашего шаблона default. А нам бы хотелось, во-первых, при установке системы на другом хостинге просто закинуть туда готовый шаблон и получить готовый сайт, больше ничего не трогая, особенно системные директории. И во-вторых, хотелось бы для разных сайтов на разных щаблонах использовать разные кастомные методы.

И что приятно, это можно сделать! Для этого создаем внутри нашего шаблона папку classes, внутри неё папку modules, в ней папку с именем модуля, например, news, а там - файл class.php, куда и скопировать то, что находится в файле customMacros.php. Таким образом, получим файл classes/modules/news/class.php с кодом:

<?php

	/** Класс пользовательских макросов */
	class NewsCustomMacros {

		/** @var news $module */
		public $module;
	}
?>

В этот файл можно добавлять свои методы, которые могут быть использованы при помощи вызова $this->macros(...).

Создадим кастомный метод newslist() по аналогии с lastlist(). Не буду приводит тут весь код, его лучше взять из файла macros.php, а изменения описаны выше, добавили одну строку. Если набрать в браузере


Собственный класс сайта

До сих пор мы рассматривали очень правильный с точки зрения MVC путь создания своих методов. Однако есть более простой и быстрый, но немного менее "канонический" способ, доступный только для PHP-шаблонизатора. Это создание класса расширения шаблонизатора.

Для начала создадим в директории php папку library. В данном случае название может быть любым. А в ней файл PhpExtension.php с вот таким кодом:

<?php

    /** Сервисные классы, которые понадобятся для выполнения методов */
    use UmiCms\Classes\System\Utils\Captcha\Strategies\GoogleRecaptcha;
    use UmiCms\Service;

    /** Расширение php шаблонизатора для шаблона default */
    class PhpExtension extends ViewPhpExtension {

    }

Далее, открываем файл config.ini, который перед этим создали в папке шаблона, там уже есть настройки для "причёсывания" отдаваемых методами массивов, и добавляем туда 2 строчки:

[php-templater]
extensions[] = "/templates/default/php/library/PhpExtension"

Важно! Имя класса в принципе может быть любым, но имя файла, содержащего этот класс, а также путь к файлу, прописанный в конфиге, должны в точности его повторять, вплоть до капитализации.

Поскольку extensions - это массив, понятно, что таких классов расширений можно добавить сколько угодно. Но нам хватит и одного.

Все публичные методы этого класса теперь будут доступны в шаблоне при помощи волшебной переменной $this. Но лучше это посмотреть на примере.

Добавление глобальных переменных

Ранее мы сделали одну не очень красивую вещь - добавили полученные прямо в шаблоне настройки к массиву $variables, и вынуждены были и дальше передавать их в методе render(), чтобы не потерялись. Значительно лучше было бы создать какие-то глобальные переменные, которые были бы доступны в любом фрагменте нашего шаблона.

Итак, добавляем в наш класс расширения следующие функции:

<?php

    /** Сервисные классы, которые понадобятся для выполнения методов */
    use UmiCms\Classes\System\Utils\Captcha\Strategies\GoogleRecaptcha;
    use UmiCms\Service;

    /** Расширение php шаблонизатора для шаблона default */
    class PhpExtension extends ViewPhpExtension {

        /**
         * Инициализирует общие переменные для шаблонов.
         * @param array $variables глобальные переменные запроса
         */
        public function initializeCommonVariables($variables) {
            $templateEngine = $this->getTemplateEngine();
            $templateEngine->setCommonVar('domain', $variables['domain']);
            $templateEngine->setCommonVar('lang', $variables['lang']);
            $templateEngine->setCommonVar('settings', $this->requestSettingsContainer());
        }

        /**
         * Запрашивает актуальный объект настроек и возвращает его
         * @return bool|iUmiObject
         */
        public function requestSettingsContainer() {
			/** @var umiSettings|UmiSettingsMacros $module */
			$module = cmsController::getInstance()
				->getModule('umiSettings');
			$id = $module->getIdByCustomId('gofroart');
			return umiObjectsCollection::getInstance()
				->getObject($id);
        }

    }