Введение
JLayer - прослойка для JohnCMS, которая позволяет писать модули используя MVC.
В теории JLayer может поддерживать все версии JohnCMS начиная с третьей ветки. Но ориентироваться будет на последнии версии.
На данный момент поддержка осуществляется только для версии 5.0.1 и в будущем с выходом новых версий JohnCMS, будет обновляться.
Как использовать JLayer в своем модуле и какие преимущества это даёт вы можете узнать в данном мануале.
Установка и настройка
Для установки нам необходимо лишь скопировать директорий в корень вашего сайта.
Что касается настройки, тот тут тоже ничего сложного.

В файле /jlayer/jlayer.php находим следующие константы:

/** Path to files directory */
define('FILES_DIR', JL_MODULE_DIR . 'files' . DIR_SEP);
/** Path to output for uncaught exceptions */
define('JL_EXP_PATH', 1);
/** JLayer Logs Directory */
define('JL_LOGS', JL_DIR . 'jl' . DIR_SEP . 'logs' . DIR_SEP);

Константа FILES_DIR отвечает за директорий файлов по умолчанию. Используется она в плагине upload.
По умолчанию указана папка files вашего модуля.

Jl_EXP_PATH отвечает за вывод необработанных исключений. Если установить в 0, то вывод будет осуществляться в браузер, иначе в лог.
Директорий расположения логов устанавливается в константе JL_LOGS
По умолчанию логи пишутся в /jlayer/jl/logs при желании вы можете изменить путь.

Остальные константы трогать не рекомендуется.
Первые шаги
Для того, чтобы подключить JLayer нам необходимо:
Создать директорий модуля в корне директория с движком. Пусть это будет test
В созданном директории создаем файл index.php со следующим содержимым:

/** Path to module's directory */
define('JL_MODULE_DIR', rtrim(dirname(__FILE__), '\\/') . DIRECTORY_SEPARATOR);
/** Prefix for tables in database */
define('JL_TABLES_PREFIX', 'test');
/** Default controller */
define('JL_DEFAULT_CONTROLLER', 'index');
/** Default action */
define('JL_DEFAULT_ACTION', 'index');
/** JohnCMS version */
define('JOHNCMS_VERSION', '5.0.1');

require '../jlayer/jlayer.php';

Константа JL_MODULE_DIR содержит абсолютный путь к директорию нашего модуля.
Константа JL_TABLES_PREFIX содержит префикс для таблиц базы данных.
Константа JL_DEFAULT_CONTROLLER содержит имя контроллера, вызываемого по умолчанию.
Константа JL_DEFAULT_ACTION содержит имя метода контроллера, который будет вызываться по умолчанию. Её изменять не рекомендуется.
Константа JOHNCMS_VERSION содержит номер версии используемого движка.

Создаем .htaccess в этом же директории.
RewriteEngine On
RewriteBase /test
RewriteRule ^(?:controller|model|lang|view)\b.* index.php/$0 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php/$0 [PT]

В строке RewriteBase /test - /test - это путь к директорию модуля.
Если вы решили назвать ваш модуль по другому, замените test на имя директория вашего модуля.
Строка RewriteRule ^(?:controller|model|lang|view)\b.* index.php/$0 [L] Перенаправляет запросы с существующих директорий на index.php
Создаем директории:
controller - для контроллеров
model - для моделей
lang - для языковых файлов
view - для шаблонов оформления

Это не полный перечень директорий.
Вам так же могут понадобиться helpers для помощников и config для конфигурационных файлов.
Если вы их создадите, то незабудьте указать их в .htaccess для перенаправления на index.php

В директории контроллеров создаем дефолтный контроллер, который определили в JL_DEFAULT_CONTROLLER
В нашем случае - это index, значит создаем файл index.php со следующим содержимым:

class Controller_Index extends \jl\Controller {

/**
* Default action
*
* @return string
*/
public function action_index($arg = 0, $arg_type = '') {
return $this->lng->test;
}

}

Метод action_index обязательно должен присутствовать в каждом контроллере, т.к. он определен абстрактным в родительском классе.

В директории lang создаем файл с именем языка по умолчанию и расширением json со следующим содержимым:

{
"test": "Тест"
}

В итоге у нас должен получится файл /test/lang/ru.json
Где ru - язык установленный по умолчанию в панели управления.
Если у вас в пользовательских настройках системы (не в панели управления) стоит другой язык, значит нужно будет создать языковой файл и для него.
Вобщем имя файла должно соответствать имени директория с языковыми файлами в /incfiles/languages

Теперь можем перейти по адресу http://ваш_сайт/директорий_модуля
Должны увидеть слово Тест

Если страница пустая, проверьте логи в директории /jlayer/jl/logs
Предопределённые константы и Функции
Константы
JL_MODULE_DIR Абсолютный путь к директорию модуля
JL_TABLES_PREFIX Префикс для таблиц базы данных, используемых в модуле
JL_DEFAULT_CONTROLLER Контроллер модуля, вызываемый по умолчанию
JL_DEFAULT_ACTION Метод контроллера модуля, вызываемый по умолчанию
JOHNCMS_VERSION Версия JohnCMS
DIR_SEP Краткая запись php-константы DIRECTORY_SEPARATOR
JL_DIR Директорий, в котором располагается JLayer
ENGINE_DIR Директорий системных файлов JohnCMS. На данный момент это incfiles
FILES_DIR Директорий, предназначенный для загрузки файлов. Должен распологаться в директории модуля
JL_EXP_PATH Путь вывода исключений: 0 - в браузер; 1 - в лог
JL_LOGS Директорий для хранения логов исключений
JL_DB_WRAPPER Обработчик SQL запросов.
HTTP_HOST Адрес сайта со слешем на конце

Все эти константы доступны в JLayer и контроллерах, моделях, хелперах и шаблонах оформления модуля.

Функции

Все функции располагаются в пространстве имен jl\
По этому для их вызова к их названию слева необходимо добавлять название пространства имен.

string anchor(string $uri[, string $title[, string $options]])

Используется для вывода внутренней ссылки.
В качестве первого аргумента принимает URI
Если передан аргумент $title заключает ссылку в html тег <a>
Для того чтобы добавить дополнительные параметры к html тегу, используйте третий аргумент.
Например:

echo \jl\anchor('test', 'Тестовая ссылка', 'target="_blank"');

void exception_handler(\Exception $exception)

Используется для обработки не перехваченных исключений.
В качестве единственного аргумента принимает объект класса \Exception $exception
В зависимости от значения константы JL_EXP_PATH выводит исключение в браузер или в лог.
Завершает работу скрипта с кодом 1.
Эта функция регистрируется в качестве обработчика неперехваченных исключений с помощью set_exception_handler в JLayer.

string img(string $image[, string $options[, string $link]])

Получает uri изображения. Преобразует его в абсолютную ссылку и заключает в html тег <img />
В качестве первого аргумента принимает URI изображения.
Для передачи дополнительных опций тегу img используйте второй аргумент.
Третьим необязательным аргументом можно передать URI для заключения изображения в ссылку.
Примеры:

echo jl\img('test.png');
echo jl\img('test.png', 'alt="test"')
echo jl\img('test.png', '', 'test');
echo jl\img('test.png', 'width="24"', 'test');

На выходе получим соответствующий html-код

<img src="http://yoursite.com/test.png" />
<img src="http://yoursite.com/test.png" alt="test" />
<a href="http://yoursite.com/test"><img src="http://yoursite.com/test.png" /></a>
<a href="http://yoursite.com/test"><img src="http://yoursite.com/test.png" width="24" /></a>

void redirect(string $uri = '')

Осуществляет редирект по заданному URI и завершает работу скрипта.

Контроллеры и их окружение
Контроллеры.

Контроллеры распологаются в директории controllers, который расположен в директории вашего модуля.
Для примера создадим директорий test в директории движка. Это и будет директорий модуля. Подключим JLayer и создадим необходимые директории.
Как это сделать, описано в разделе Первые шаги.
Создаем в директории контроллеров файл test.php
Заносим в него следующий код:

class Controller_Test extends jl\Controller {

public function action_index($arg1 = 0, $arg2 = 1) {

var_dump($arg1, $arg2); }

public function action_test() {

return 'test' }

}

Контроллер представляет собой класс c именем, состоящим из префикса Controller_ и следующим после него
именем файла с заглавной буквы без расширения .php
Класс контроллера должен наследоваться от абстрактного класса jl\Controller и
обязательно иметь метод action_index(), т.к. в классе jl\Controller он объявлен абстрактным.
Методы контроллера, которые имеют префикс action_ доступны для вызова через URL,
методы не имеющие этот префикс доступны для вызова через URL не будут.
Давайте перейдем по адресу http://адрес_вашего_сайта/test/test/index/
Мы должны увидеть результат работы метода action_index
Для того, чтобы увидеть результат работы метода action_test нужно
перейти по адресу http://адрес_вашего_сайта/test/test/test/
Видите разницу? В первом случае мы увидили результат работы функции var_dump()
без каких-либо еще элементов на странице.
Во втором случае были подключены "шапка" и "ноги" движка.
Это всё из-за того, что впервом случае метод ничего не возвращает, а во втором метод возвращает строку.
Принцип, думаю, понятен.
Что касается аргументов методов, то их также можно передавать через URL.
Перейдите по адресу http://адрес_вашего_сайта/test/test/index/arg1/arg2
Увидите, что значения аргументов изменились на arg1 и arg2
Тут важно отметить, что вы всегда должны определять значения по умолчанию для аргументов,
иначе если этого не сделать, будет сгенерировано уведомление о неопределенной переменной.

Теперь переходим к свойствам контроллёра.
Контроллер имеет три protected свойства:

jl - объект класса jl\Jlayer

Используется для связи с JohnCMS

Поля объекта:

string $error_page - URI страницы ошибки.
Имеет следующие методы:
int get_id() Получает идентификатор текущего пользователя. Если пользователь не авторизован, возвращает 0.

int get_rights() Получает права доступа текущего пользователя. Если пользователь не авторизован, возвращает 0.
Права доступа в соответствии с текущей версией JohnCMS могут иметь следующие значения:
0 - обычный пользователь
3 - Модератор форума
4 - Модератор загруз-центра
5 - Модератор библиотеки
6 - Старший модератор
7 - Администратор
9 - Супервайзор

mixed get_data([string $key]) Получает данные авторизованного пользователя. Если аргумент $key не передан, возвращает весь массив данных.

array get_infringements() Получает список активных банов авторизованного пользователя.

mixed get_settings([string $key]) Получает настройки системы авторизованного пользователя. Если аргумент $key не передан, возвращает весь массив данных.

string get_table() Получает имя таблицы, в которой хранятся данные пользователей.

Имеет следующие методы:
mixed get_settings([string $key = '']) Получает системные настройки. Если аргумент $key не передан, возвращает весь массив.

int|string get_ip([boolean $format = false]) Возвращает IP адрес текущего пользователя.
Если аргумент $format имеет значение true, метод вернет строковое представление IP адреса, иначе вернет int

int|string get_ip_via_proxy([boolean $format = false]) Получает IP адрес текущего пользователя за PROXY-сервером.
Если аргумент $format имеет значение true, метод вернет строковое представление IP адреса, иначе вернет int

string get_user_agent() Получает User-Agent текущего пользователя.

boolean is_mobile() Определяет, является ли браузер текущего пользователя мобильным.

boolean|int anti_flood() Проверяет сколько времени прошло с момента отправки пользователем последнего поста.
Возвращает false, если времени прошло достаточно много, иначе возвращает кол-во секунд,
которых необходимо подождать пользователю, перед тем как отправить сообщение.
Этот метод используется совместно с методом set_last_post_time(), описание которого вы може найти чуть ниже.

string bb_panel(string $form, string $field); Возвращает html код панели BB-кодов.
string $form - имя формы;
string $field - имя текстового поля, в которое будет осуществлятся вставка бб-кодов с панели.

boolean check_captcha($code) Проверяет, верно ли введен проверочный код с картинки.
Этот метод используется вместе с методом get_captcha(), описание которого вы можете найти чуть ниже.

string check_in($string) Фильтрует строку. Избавляется от невидимых символов.

string check_out(string $string[, int $nl = 0[, int $bb_tags = 0[, int $smileys = 0]]]) Обрабатывает строку перед выводом.
string $string - строка для обработки.
int $br - обработка переносов строк:
0 - Не обрабатывать (по умолчанию).
1 - Заменять на <br />
2 - Заменять на пробелы.
int $bb_tags - обработка BB-кодов:
0 - Не обрабатывать (по умолчанию).
1 - Заменять на их html эквиваленты.
2 - Вырезать.
int $smileys - обработка смайлов:
0 - не обрабатывать (по умолчанию).
1 - обрабатывать.

string confirm_message(string $title, string $message, string $ok, string $cancel[, string $action = '']) Возвращает html код формы подтверждения.
string $title - Заголовок формы
string $message Сообщение
string $ok Надпись на кнопке подтверждения
string $cancel Надпись на кнопке отмены
string $action Адрес скрипта обработчика. Необязательный аргумент.

string count_time(int $timestamp) Пересчет на дни или часы.

string display_date(int $timestamp) Форматирует вывод даты с учётом временного сдвига. В качестве единственного аргумента принимает временную метку

string display_message(array|string $message[, int $level = 0]) Подготавливает сообщение к выводу.
array|string $message - Строка сообщения или массив сообщений.
int $level - уровень сообщения: 0 - уведомление. 1 - предупреждение.

string display_user(int|array $user[, boolean $last_visit = false[, boolean $status = true[, boolean $ips = true[, boolean $ip_history = true[, string $header = ''[, string $body = ''[, string $sub = ''[, string $footer = '']]]]]]]]); int|array $user - Данные пользователя. Если данные отстутствуют передайте 0.
boolean $last_visit Показывать дату последнего визита
boolean $status Скрыть статус
boolean $ips Скрыть юзер-агент и IP адрес
boolean $ip_history Показать ссылку на историю IP
string $header Строка для отображения возле ника пользователя
string $body Строка для отображения под ником пользователя
string $sub Строка для отображения в области sub
string $footer Строка для отбражения в самом низу блока

string do_translit(string $string) Транслитерация текста. Переводит кириллические символы в их латинские эквиваленты.

void|boolean force_download(string $filename, string $data[, string $mime = 'application/octet-stream']) Отдача файла в браузер.
string $filename - Имя файла.
string $data - Содержимое файла.
string $mime - MIME-тип файла.

string do_smileys(string $string[, boolean $adm = false]) Обработка смайлов.
string $string - Строка для обработки
boolean $adm - Включить обработку смайлов, предназначенных для администрации.

string do_untranslit(string $string) Детранслитерация текста. Преобразует латинские символы в их кириллические эквиваленты.

string get_captcha(string $field_name[, string $error = '']) Возвращает html код, содержащий изображение капчи, форму ввода и сообщение об ошибке, если присутствует.
Используется совместно с методом check_captcha(), описание которого вы можете найди выше.
string $field_name - Имя поля ввода.
string $error - Сообщение об ошибке, если есть.

array get_user(string|int $id[, string $by = 'id']) Получает данные пользователя по его ID или никнейму.
string|int $id - ID или никнейм пользователя.
string $by - По какому полю искать: id - для поиска по ID, name для поиска по никнейму.

boolean valid_ip(string $ip) Определяет, валиден ли IP адрес.

boolean set_last_post_time(int $user_id) Фиксирует время оправки последнего поста пользователем.
В качестве единственного аргумента принимает ID пользователя для которого нужно обновить время.
Используется совместно с методом anti_flood(), описание которого вы можете найти выше.
Методы объекта:

jl\Model model(string $name) Загружает модель.
Модели располагаются в директории model директория модуля.
Если модели не существует, выбрасывает исключение jl\Exception
Если модель была загружен ранее, вернет объект уже загруженной модели.

jl\Plugin plugin(string $name) Загружает плагин.
Если плагина не существует, выбрасывает исключение jl\Exception
Если плагин был загружен ранее, вернет объект уже загруженного плагина.

boolean helper(string $name) Загружает хэлпер.
Хелперы загружаются из директория helpers, который расположен в директории модуля.
Если директория не существует, создайте его.

array load_config(string $name[, string $from = 'module']) Загружает конфигурационный файл.
string $name - Имя конфигурационного файла.
string $from - Путь, откуда следует загружать конфигурационный файл.
Если метод вызывается из контроллера, то передавать какое-либо значение этому аргументу не нужно ни в коем случае.
Конфигурационные файлы будут загружаться из директория config директория модуля.
Если же метод вызывается из плагина, то нужно передать значение plugin/имя_плагина
В этом случае конфиг будет загружаться из директория config, который расположен в директори плагина.
Конфигурационные файлы должны представлять из себя json файлы, с расширением json.

lng - объект класса jl\Language

Используется для работы с языковым файлом.
Языковой файл должен распологаться в директории lang директория модуля.
Если в системе более одного языка, то для каждого языка желательно создать по файлу.
Хотя в этом нет особой необходимости и скрипт сможет работать и с одним файлом.
Главное, чтобы этот файл соответствовал установленному в системе языку по умолчанию.
Языковой файл представляет собой файл формата json.
В качестве имени файла используйте код языка и расширение json
Код необходимого языка вы можете узнать в директории incfiles/languages
Например фразы русского языка располагаются в директории incfiles/languages/ru
Значит имя нашего файла должно быть ru.json
Доступ к фразам в контроллере осуществляется через $this->lng->ключ_фразы
Если элемента с заданным ключем в языковом файле не существует, то на выходе вы получите имя ключа, заключенное в символы #

tpl - объект класса jl\Template

Используется для работы с шаблонами оформления.
Шаблоны оформления располагаются в директории view директория модуля.
Представляют собой файлы с расширением php.
Для удобства добавляйте к именам шаблонов префиксы имен в методов и контроллеров, в которых они используются.

Рассмотрим методы объекта шаблонизатора:

string|null get_title() Получает строку заголовка страницы. Если заголовок страницы не был установлен, вернет null

string load(string $name[, array $data = array()]) Загружает шаблон
string $name - имя шаблона
array $data - ассоциативный массив, содержимое которого при загрузке шаблона будет извлечено с помощью функции extract() без использования префиксов.

void output() Выводит данные в браузер

void set_output(string $data[, $priority = null]) Устанавливает данные для вывода
string $data - строка для вывода.
int|null $priority - приоритет данных. Если передать null, будет задан самый низкий приоритет.
Чем больше число, тем ниже приоритет.
Важно отметить, что под каким бы вы приоритетом не установили шаблон в контроллере, всегда самым последним будет выводится шаблон, отвечающий за "ноги" страницы.
Так же не стоит задавать нулевой приоритет для ваших шаблонов. Это место тоже зарезервировано.

void set_title(string $title) Устанавливает заголовок страницы.

Модели
Модели предназначены для работы с таблицами базы данных.
Располагаются они в директории model директория модуля.
Для создания модели нужно создать файл с именем необходимой модели и расширением php
В созданном файле определить класс с именем Model_Имя_файла_с_заглавной_буквы
Класс должен наследоваться от jl\Model
Модель по умолчанию имеет два protected свойства:
jl\Db $db - Объект класса jl\Db предназначенный для работы с базой данных
string $table_name - Имя таблицы базы данных, с которой будет работать модель.
Имя таблицы устанавливается с помощью метода string set_table_name()
К имени таблицы установленному с помощью этого метода автоматически добавляется префикс указанный в константе JL_TABLES_PREFIX
Конечно вы можете и не использовать метод string set_table_name() и указывать в запросах непосредственно имя таблицы с префиксом JL_TABLES_PREFIX

Например:
$this->db->query("SELECT * FROM `" . JL_TABLES_PREFIX . "_sometable`");
Символ нижнего подчеркивания между префиксом и названием таблицы обязателен.


Плагины
Загрузка плагина в контроллёре осуществляется через метод plugin объекта класса jl\Jlayer

$this->jl->plugin('имя_плагина');
Если плагин загружается в первые, то будет создан объект этого плагина и помещен во временное хранилище.
При повторной загрузке плагина, метод вернет объект созданного ранее плагина.

JLayer имеет следующий набор плагинов:

Создание собственных плагинов.

Все плагины располагаются в директории jlayer/jl/plugins
Для создания плагина создайте директорий с именем плагина в указанном выше директории.
В созданном директории создайте php файл c тем же именем.
В файле объявите класс с тем же именем и заключите его в пространство имен jl\plugins
Класс должен наследоваться от класса jl\Plugin
Окружение плагина:
Свойства:
jl\Db $db - Предназначено для работы с базой данных.
jl\Template $tpl - Обработчик шаблонов.
jl\Jlayer $jl - Взаимодействие с JohnCMS
jl\Language $lng - Работа с языковыми файлами.
Свойства и методы представленных выше объектов уже рассматривались, поэтому нет нужды повторять все тоже самое еще раз.
Для использования шаблонов создайте в директории плагина директорий view
Для работы с языками нужен директорий lang
Для работы с конфигурационными файлами - директорий config
Если ничего из этого вам в вашем плагине не понадобится, то создавать директории нет необходимости.
Адаптация под другие версии JohnCMS
После загрузки всех необходимых классов и проведения проверок Jlayer загружает конфигурационный файл
и обертку для функций движка из директория jlayer/jl/wrappers/johncms
Для адаптации jlayer под иную версию создайте в указанном директории директориий с названием поддерживаемой версии.
Например если планируется добавить поддержку версии 3.2.2 то путь к директорию должен выглядеть следующим образом:
jlayer/jl/wrappers/johncms/3.2.2/
В созданном директории создайте файл config.php и файл functions.php
Если необходимо использовать шаблоны оформления, то так же создайте директорий view
Файл config.php должен возвращать ассоциативный массив со следующими элементами:
'network'           => array(
    'ip'            => 0,                     // IP адрес текущего пользователя
    'ip_via_proxy'  => 0,                     // IP адрес текущего пользователя за PROXY сервером
    'user_agent'    => 'Not Recognised',      // User-Agent текущего пользователя
    'is_mobile'     => false,                 // Является ли браузер текущего пользователя мобильным?
),
'system_settings'   => array(),               // Настройки системы
'user'              => array(
    'data'          => array(),               // Данные пользователя
    'settings'      => array(),               // Настройки пользователя
    'infringements' => array(),               // Список нарушений пользователя
    'table_name'    => 'users',               // Имя таблицы базы данных, которая содержит данные пользователей
),
'language'          => '',                    // Язык системы
'db'                => array(                 // Данные MySQL соединения.
    'host'          => '',                    // Хост
    'user'          => '',                    // Имя пользователя
    'password'      => '',                    // Пароль
    'name'          => '',                    // Имя базы данных
),
'output'            => array(                 // Данные для вывода
    'head'          => '',                    // Header
    'end'           => '',                    // Footer
),
'error_page'        => '',                    // URI страницы ошибки
В файле functions.php объявите класс Functions унаследуйте его от класса jl\Functions и заключите в пространство имен jl\wrappers\johncms После чего, реализуйте абстрактные методы класса jl\Functions