Only this pageAll pages
Powered by GitBook
1 of 45

9.3

Loading...

Начало работы

Loading...

Loading...

Loading...

Общие сведения

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Шаблоны

Loading...

Loading...

Loading...

Модули

Loading...

Loading...

Loading...

Мультиязычность

Loading...

База данных

Loading...

Loading...

Loading...

Loading...

Loading...

Eloquent ORM

Loading...

Пользователи

Loading...

Loading...

Loading...

Проблемы и их решение

Иногда при переносе сайта на другой хостинг или после каких-то изменений в коде вы можете столкнуться с ошибками. Здесь мы рассмотрим распространенные проблемы и варианты их решений.

Ошибка 500.

Причин появления этой ошибки много. Каждую причину нужно рассматривать индивидуально. Для начала чтобы понять от чего отталкиваться нужно включить вывод ошибок.

Для включения вывода ошибок откройте файл config/constants.php, найдите строки

// Включаем режим отладки
const DEBUG = false;

Замените false на true

const DEBUG = true;

После этих действий на сайте должен отображаться текст ошибки.

Если этого не произошло, нужно смотреть журнал ошибок на сервере.

Настройка

После установки JohnCMS перейдите в панель администратора.

  1. Выберите пункт Система > Обновить смайлы. Это обновит кэш смайлов и после этой операции смайлы в сообщениях будут работать

  2. Выберите пункт Система > Настройки языка. Далее нажмите Обновить список после этого выберите язык по умолчанию, на котором будет работать Ваш сайт.

Далее по желанию Вы можете проверить и изменить все остальные параметры системы. Для этого просто переходите в другие разделы панели администратора и меняйте настройки так, как Вам необходимо.

Введение

В данной документации мы постараемся описать все ключевые моменты, с которыми вы столкнетесь при работе с системой.

Если документация не смогла помочь Вам в решении Вашего вопроса, Вы всегда можете обратиться за помощью на

наш форум

Структура файлов/папок

JohnCMS имеет следующую структуру папок:

  • assets

  • config

  • data

  • install

  • modules

  • system

  • themes

  • upload

assets

В папке хранятся аватары (avatars), смайлы (emoticons) и некоторые системные скрипты (modules) для генерации картинок предпросмотра.

Подпапка modules будет удалена в следующих версиях.

config

data

В папке data хранятся различные системные данные, такие как кэш и логи

install

В папке install хранятся скрипты и прочие данные необходимые для установки системы. Данную папку необходимо удалять после установки JohnCMS

modules

Папка modules содержит все модули системы Подробно про структуру папки модуля будет описано отдельно.

system

Папка system содержит все системные библиотеки В этой папке не рекомендуется ничего менять и добавлять в целях сохранения возможности простого обновления на следующие версии JohnCMS

themes

Папка themes содержит шаблоны сайта В этой папке расположен шаблон default в папке с этим шаблоном не рекомендуется ничего менять для сохранения возможности простого обновления на следующие версии JohnCMS Для кастомизации шаблона создайте отдельную папку и скопируйте в неё содержимое папки default. Более подробно про работу с шаблонами читайте в соответствующем разделе документации

upload

Папка upload содержит файлы модулей, такие как загрузки, прикрепленные файлы форума, библиотеки, альбомы, аватары и файлы личных сообщений.

В папке хранятся различные конфигурационные файлы необходимые для работы системы. Файл routes.php отвечает за настройку адресов страниц. Файл constants.php содержит константы необходимые для работы системы. В подпапке autoload хранятся файлы, которые автоматически загружаются системой. Работа с конфигурационными файлами подробно описана здесь: .

Конфигурационные файлы

Конфигурационные файлы (configs)

Наверное Вы уже задавались вопросом "Где хранятся настройки JohnCMS и как добавлять свои настройки?". Давайте рассмотрим подробнее.

Когда мы открываем папку config, то видим в ней примерно такую структуру:

Файлов достаточно много, давайте разберёмся за что они отвечают.

Файлы в директории autoload:

Директория autoload содержит все конфигурационные файлы, которые автоматически загружаются системой. Как вы наверное заметили есть файлы содержащие в названии global и local. Файлы global это обычно файлы, которые могут обновляться при выходе новых версий JohnCMS. Не рекомендуем их редактировать, т.к. это осложнит обновление CMS.

Файлы local - это локальные файлы конкретно для вашего сайта. Они не содержаться в дистрибутиве JohnCMS. Некоторые из них создаются автоматически при установке системы, а некоторые вы можете создавать вручную.

Как же быть если вы хотите изменить какие-то параметры, которые есть в global файле?

Всё очень просто. Нужно создать файл с таким же названием, но заменить global на local.

Например, вы хотите изменить настройки в файле mail.global.php, для этого скопируйте этот файл и сохраните под именем mail.local.php. Далее измените в нем нужные параметры и они переопределят те параметры, которые уже содержатся в mail.global.php.

Обратите внимание. При необходимости Вы можете изменить только определенные параметры, а остальные останутся стандартными.

Давайте рассмотрим пример:

Содержимое mail.global.php

return [
    'mail' => [
        // Default transport (can be sendmail, smtp, file or memory)
        'transport' => 'sendmail',

        // Transport settings
        'options'   => [
            'smtp' => [
                'name'              => 'localhost.localdomain',
                'host'              => '127.0.0.1',
                'connection_class'  => 'plain',
                'connection_config' => [
                    'username' => 'user',
                    'password' => 'pass',
                ],
            ],
            'file' => [
                'path'     => DATA_PATH . 'mail/',
                'callback' => static function (FileTransport $transport) {
                    return 'Message_' . microtime(true) . '_' . mt_rand() . '.txt';
                },
            ],
        ],
    ],
];

Допустим нам нужно изменить имя пользователя: username. Это можно сделать так:

Содержимое файла mail.local.php

return [
    'mail' => [
        // Transport settings
        'options'   => [
            'smtp' => [
                'connection_config' => [
                    'username' => 'my_user',
                ],
            ],
        ],
    ],
];

Давайте теперь получим итоговый результат.

Содержимое всех конфигурационных файлов можно получить следующим образом: $config = di('config'); Это вернет содержимое всех конфигурационных файлов из папки config/autoload.

Чтобы получить содержимое файла mail, выполним следующий код:

d($config['mail']);

Это вернет следующий результат:

Array
(
    [transport] => sendmail
    [options] => Array
        (
            [smtp] => Array
                (
                    [name] => localhost.localdomain
                    [host] => 127.0.0.1
                    [connection_class] => plain
                    [connection_config] => Array
                        (
                            [username] => my_user
                            [password] => pass
                        )
                )
            [file] => Array
                (
                    [path] => /Users/maksim/MyProjects/johncms_public/data/mail/
                    [callback] => Closure Object
                        (
                            [parameter] => Array
                                (
                                    [$transport] => 
                                )
                        )
                )
        )
)

Как видите, в итоговом результате username переопределился тем, что мы указали в файле mail.local.php

Вы можете самостоятельно поэкспериментировать, создать свой конфигурационный файл (global/local), а так же можете переопределить настройки из других файлов.

Для удобства можете создать файл test.php в корне вашего сайта со следующим содержимым:

<?php

require 'system/bootstrap.php';
$config = di('config');

// Выведем содержимое конфига mail
d($config['mail']);

После этого в браузере перейдите по адресу site.com/test.php и увидите результат. (site.com необходимо заменить на адрес вашего сайта).

Обратите внимание. Хоть технически вы можете создавать конфигурационные файлы любой структуры и с любыми именами содержащими local.php или global.php, мы бы рекомендовали создавать осмысленные названия и первый элемент массива называть так же как и сам конфигурационный файл чтобы избежать путаницы и пересечения параметров. Например файл my.global.php, должен возвращать следующую структуру: return [ 'my' => [ 'name' => 'value' ], ];

Autoload рассмотрели, теперь кратко рассмотрим остальные файлы.

Прочие конфигурационные файлы:

constants.php - Файл содержит различные константы. В нем вам скорее всего понадобятся константы USE_CRON (для перевода отправки email на cron) и DEBUG для включения режима отладки при возникновении ошибок или при разработке модулей.

notifications.global.php - Этот файл содержит шаблоны уведомлений. Параметры в данном файле можно переопределить или дополнить с помощью файла notifications.local.php

places.global.php - Файл содержит информацию о местоположении пользователей. Параметры в данном файле можно переопределить или дополнить с помощью файла places.local.php

Установка и системные требования

Системные требования

Для корректной работы JohnCMS, на хостинге, который вы используете, должно быть установлено следующее программное обеспечение

  • Web сервер Apache

  • PHP 7.3 и выше

  • MySQL 5.6.4 и выше

Для работы системы требуются следующие расширения php:

  • imagick или gd

  • mbstring

  • pdo

  • simplexml

Установка

  • Скачиваем архив

  • Распаковываем в корневую папку на хостинге (обычно это папка с названием вашего сайта или public_html)

  • Переходим по адресу ваш.сайт/install

  • Следуйте инструкциям описанным на странице установки

Обязательно указывайте существующий e-mail адрес при установке т.к. он будет использоваться для отправки e-mail.

После установки обязательно удалите папку install

Ранее когда мы рассматривали , мы уже упоминали в ней папку . Теперь рассмотрим, что и за что отвечает...

routes.php - файл для настройки маршрутизации. Подробно работу с ним мы рассматривали в этой статье:

Для работы с MуSQL должен использоваться встроенный драйвер

структуру папок
config
Маршрутизация (роутинг)
MySQL Native Driver (mysqlnd)

NotEmpty - Не пустое значение

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

По умолчанию этот валидатор работает иначе, чем вы ожидаете, работая с PHP функцией empty(). В частности, этот валидатор будет оценивать как целое число 0, так и строку «0» как пустые.

Вам может не подойти это поведение и, например, в вашем случае 0 не должен считаться пустым. Для таких случаев в валидаторе NotEmpty вы можете задать некоторые настройки.

Поддерживаемые параметры

  • type: Устанавливает тип проверки, которая будет выполнена.

Обрабатываемые типы

  • boolean: Возвращает false, когда логическое значение равно false.

  • integer: Возвращает false, когда задано целое число 0. По умолчанию эта проверка не активирована и возвращает true для любых целочисленных значений.

  • float: Возвращает false, когда задано значение с плавающей запятой 0.0. По умолчанию эта проверка не активирована и возвращает true для любых значений с плавающей запятой.

  • string: Возвращает false, когда задана пустая строка.

  • zero: Возвращает false, когда задан один символ ноль ('0').

  • empty_array: Возвращает false, когда задан пустой массив.

  • null: Возвращает false, когда задано значение null.

  • php: Возвращает false везде, где PHP empty () возвращает true.

  • space: Возвращает false, если задана строка, содержащая только пробел.

  • object: Возвращает true. false будет возвращено, когда объект не разрешен, но объект задан.

  • object_string: Возвращает false, когда объект задан, а его метод __toString () возвращает пустую строку.

  • object_count: Возвращает false, когда объект задан, он реализует Countable, и его количество равно 0.

  • all: Возвращает false для всех вышеперечисленных типов.

Рассмотрим пример как передавать эти параметры в валидатор.

Примеры использования

// Массив полей и значений
$data = [
    'test' => 0,
];

// Настройки валидатора
$rules = [
    'test' => [
        'NotEmpty' => [
            'type' => [
                'integer',
                'zero',
            ],
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

Как видите, для валидатора NotEmpty задан массив настроек, в нем передается параметр type со значениями из списка выше (обрабатываемые типы).

Отправка электронной почты (email)

Драйверы и настройка

На данный момент поддерживаются следующие драйверы: Sendmail, SMTP, File. Этих драйверов обычно более чем достаточно большинству проектов.

Отправка сообщений

Отправка email достаточно затратная операция. Для решения этой проблемы отправку email можно переложить на сервер. Для этого в JohnCMS реализована очередь сообщений. Чтобы отправить письмо, необходимо просто добавить его в очередь.

Рассмотрим пример добавления письма в очередь:

(new \Johncms\Mail\EmailMessage())->create(
    [
        'locale'   => 'ru',
        'template' => 'system::mail/templates/registration',
        'fields'   => [
            'email_to'        => 'user@example.com',
            'name_to'         => 'Имя Пользователя',
            'subject'         => 'Регистрация на сайте',
            'user_name'       => 'UserName',
            'user_login'      => 'UserLogin',
            'link_to_confirm' => 'https://johncms.com',
        ],
    ]
);

Что делает этот код? Он добавляет запись в таблицу email_messages. А дальше система проверяет наличие не отправленных писем в очереди и отправляет их.

Какие поля необходимы?

  • priority - Приоритет отправки сообщения. Чем меньше, тем выше. (не обязательно)

  • locale - Поле обязательно и содержит код языка, на котором будет отправлено сообщение.

  • template - содержит шаблон, который будет использоваться для формирования письма.

  • fields - содержит массив полей, которые будут доступны в шаблоне, а так же будут использоваться для отправки:

    • email_to - E-mail адрес получателя сообщения (обязательное поле)

    • name_to - Имя получателя, которое будет отображаться в почтовом клиенте. (не обязательно)

    • subject - Тема сообщения. (не обязательно, но рекомендуется)

    • Прочие поля доступны только в шаблоне, не требуются для работы драйвера и могут отсутствовать.

Отправка почтовых сообщений по умолчанию выполняется на хитах. Это значит, что для отправки письма какой либо пользователь должен зайти на сайт. В момент на сайт, выполняется проверка наличия неотправленных сообщений и если таковые находятся, выполняется отправка. Этот вариант не всегда подходит, особенно если сообщений отправляется много. По этому рекомендуется перевести отправку сообщений на cron.

Перевод отправки Email на CRON

Для того, чтобы избежать подвисания страницы для пользователей в JohnCMS реализована отправка сообщений с помощью планировщика cron. Если ваш хостинг поддерживает cron, то рекомендуем перевести отправку сообщений на него. Для этого откройте файл: config/constants.php Найдите строчку:

const USE_CRON = false;

И замените false на true.

Далее необходимо добавить задачу в cron:

php system/cron.php

Периодичность выполнения установить раз в 1 минуту. Обратите внимание, что может потребоваться указать полный путь к файлу от корня. Посмотреть его можно в phpinfo(), параметр DOCUMENT_ROOT или вывести так: echo $_SERVER['DOCUMENT_ROOT']; Более подробно про то как добавить задачу, вы можете уточнить у вашего хостинг провайдера.

В JohnCMS для отправки электронной почты используется библиотека Она позволяет обобщить отправку сообщений и легко переключать драйверы через которые будет отправляться письмо. Благодаря этому вы сможете выбрать наиболее подходящий вам метод отправки в зависимости от возможностей вашего хостинга и наличия его ip в спам фильтрах.

Драйвер по умолчанию и настройки драйвера указываются в конфигурационном файле config/autoload/mail.global.php. По умолчанию установлен sendmail, но вы можете сменить драйвер на smtp или file. Примеры настроек есть в указанном файле. Вы можете просто их переопределить. Как это сделать, а так же про работу с конфигурационными файлами рекомендуем прочитать здесь:

laminas-mail
Конфигурационные файлы.

Работа с запросом (Request)

Для работы с данными HTTP запроса в JohnCMS используется класс \Johncms\System\Http\Request. Он позволяет получить доступ к таким суперглобальным переменным как: $_POST, $_GET, $_COOKIE, $_FILES, $_SERVER. Это позволяет упростить получение значений по умолчанию, и фильтрацию данных, пришедших от пользователя. Давайте посмотрим на примеры.

Для начала необходимо получить объект класса Request.

/** @var \Johncms\System\Http\Request $request */
$request = di(\Johncms\System\Http\Request::class);

Строка /** @var \Johncms\System\Http\Request $request */ не обязательна и служит лишь для работы автодополнения в IDE если вы конечно используете IDE.

Получение данных из $_GET

Предположим, что пользователь открыл страницу http://domain.com/?user_id=123 и нам нужно получить идентификатор пользователя 123. Сделать это можно следующим образом:

$user = $request->getQuery('user_id', 0, FILTER_VALIDATE_INT);

Коротко что делает строка из примера: Пытается получить параметр GET запроса user_id, если его нет, то возвращает 0, если есть, то очищает и возвращает число. Если передано не число, то вернет значение по умолчанию, то есть 0.

Получение данных из $_POST

Предположим, что отправлена форма, которая содержит user_id и name. Форма отправлена методом POST.

$user = $request->getPost('user_id', 0, FILTER_VALIDATE_INT);
$name = $request->getPost('name', '', FILTER_SANITIZE_STRING);

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

Получение данных из $_COOKIE

$name = $request->getCookie('name', '', FILTER_SANITIZE_STRING);

В этом примере как видите всё так же просто как и в предыдущих. Просто поменялось название метода, а принцип работы такой же.

Получение данных из $_SERVER

$user_agent = $request->getServer('HTTP_USER_AGENT', '', FILTER_SANITIZE_STRING);

Этот пример работает так же как и остальные. Получает HTTP_USER_AGENT из суперглобальной переменной $_SERVER.

Получение данных из $_FILES

$files = $request->getUploadedFiles();

Этот код вернет массив файлов, в котором каждый элемент будет представлен объектом класса GuzzleHttp\Psr7\UploadedFile. Если вы уже работали с выгрузкой файлов в php, то наверное знаете, что множественные файлы в массиве $_FILES описываются примерно так:

array(
    'files' => array(
        'name' => array(
            0 => 'file0.txt',
            1 => 'file1.html',
        ),
        'type' => array(
            0 => 'text/plain',
            1 => 'text/html',
        ),
        /* etc. */
    ),
)

для работы с этим стандартными средствами вам необходимо позаботиться о сборе всех данных в нормальную структуру. Если вы используете метод getUploadedFiles, то эта задача уже решена для вас и массив файлов будет уже в нормальной структуре:

array(
    'files' => array(
        0 => array(
            'name' => 'file0.txt',
            'type' => 'text/plain',
            /* etc. */
        ),
        1 => array(
            'name' => 'file1.html',
            'type' => 'text/html',
            /* etc. */
        ),
    ),
)

Давайте рассмотрим пример сохранения файлов

Допустим, у нас есть такая форма, которая принимает 1 обычный файл и поле с возможностью выбирать несколько файлов.

<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="file" name="multiple_files[]" multiple>
    <button type="submit">Отправить</button>
</form>

Пример сохранения файлов будет выглядеть так:

$files = $request->getUploadedFiles();

// Сохраняем файл из обычного поля
if (! empty($files['file'])) {
    /** @var  $attached_file \Psr\Http\Message\UploadedFileInterface */
    $attached_file = $files['file'];
    try {
        $attached_file->moveTo(UPLOAD_PATH . '/tmp/' . $attached_file->getClientFilename());
        echo 'Файл успешно сохранен';
    } catch (\Exception $exception) {
        echo 'Ошибка сохранения файла: ' . $exception->getMessage();
    }
}

// Сохраняем файлы из множественного поля
if (! empty($files['multiple_files'])) {
    /** @var  $multiple_files \Psr\Http\Message\UploadedFileInterface[] */
    $multiple_files = $files['multiple_files'];
    foreach ($multiple_files as $multiple_file) {
        try {
            $multiple_file->moveTo(UPLOAD_PATH . '/tmp/' . $multiple_file->getClientFilename());
            echo 'Файл успешно сохранен';
        } catch (\Exception $exception) {
            echo 'Ошибка сохранения файла: ' . $exception->getMessage();
        }
    }
}

В результате отправки формы с файлами, все файлы будут сохранены в папке upload/tmp c оригинальными названиями, с которыми отправил клиент.

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

Разберем что же тут происходит. Метод getQuery пытается получить user_id из суперглобального массива $_GET. Первым параметром принимает название параметра запроса, вторым параметром можно передать стандартное значение, а третим параметром передается фильтр, с помощью которого будет обработано значение. Вы можете ознакомиться со списком фильтров в официальной документации по этой ссылке:

https://www.php.net/manual/ru/filter.filters.php

StringLength - длина строки

Валидатор StringLength позволяет проверить находится ли длина строки в диапазоне заданных значений или нет.

По умолчанию этот валидатор проверяет, находится ли значение между min и max, используя минимальное значение по умолчанию, равное 0, и максимальное значение по умолчанию, равное NULL (то есть неограниченное). Таким образом, без каких-либо опций, валидатор только проверяет, что ввод является строкой.

Поддерживаемые параметры

  • encoding: Устанавливает кодировку ICONV в которой будет проверяться строка.

  • min: Устанавливает минимально допустимую длину строки.

  • max: Устанавливает максимально допустимую длину для строки.

Примеры использования

// Массив полей и значений
$data = [
    'test' => 'Строка',
];

// Настройки валидатора
$rules = [
    'test' => [
        'StringLength' => [
            'min'      => 3,
            'max'      => 60,
            'encoding' => 'UTF-8',
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В указанном примере валидатор проверит строку в кодировке UTF-8 на длину от 3 до 60 символов.

Проверка только минимальной длины:

// Массив полей и значений
$data = [
    'test' => 'Строка',
];

// Настройки валидатора
$rules = [
    'test' => [
        'StringLength' => [
            'min' => 3
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В этом примере будет проверяться только минимальная длина строки (3 символа). Максимальная будет считаться не ограниченной.

Проверка только максимальной длины:

// Массив полей и значений
$data = [
    'test' => 'Строка',
];

// Настройки валидатора
$rules = [
    'test' => [
        'StringLength' => [
            'max' => 50
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В этом же примере будет проверяться только максимальная длина строки. Если строка будет длиннее 50 символов, проверка не пройдет, если менее 50 символов, то проверка пройдет.

Строгое ограничение длины строки:

// Массив полей и значений
$data = [
    'test' => 'Строка',
];

// Настройки валидатора
$rules = [
    'test' => [
        'StringLength' => [
            'max' => 6,
            'min' => 6,
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

А в этом примере мы строго ограничили длину строки 6 символами. Т.е. проверка пройдет только если строка будет длиной в 6 символов. Больше или меньше не допускается.

Flood - проверка на флуд

Валидатор Flood предназначен для упрощения проверки формы на флуд. Валидатор не имеет параметров, не привязывается к какому либо полю и обычно используется вместе с валидатором токена из-за особенностей технической реализации валидаторов.

Пример использования

// Массив полей и значений
$data = [
    'test' => 'token',
];

// Настройки валидатора
$rules = [
    'test' => [
        'Csrf',
        'Flood',
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В указанном примере валидатор Flood добавлен для того же поля, что и валидатор токена.

Структура стандартного шаблона

Шаблоны располагаются в папке themes

Обычно шаблон для JohnCMS имеет следующую структуру:

  • themes

    • template_name

      • assets

      • src

      • templates

В данной структуре обязательными являются только папки assets и templates, но в некоторых исключениях они вам могут не понадобиться.

Что такое шаблон в JohnCMS?

С точки зрения структуры шаблоном является любая папка в папке /themes В этой папке есть тема по умолчанию - default В этой теме находятся все необходимые для работы файлы по умолчанию: шаблоны, стили, картинки, скрипты и т.д. Также, каждый отдельный модуль может иметь свою папку с шаблонами /module_name/templates, или другими файлами общего доступа /assets/modules/module_name.

Для частичной кастомизации стандартного шаблона, вы можете создать свою тему только с теми файлами, которые хотите изменить. При создании темы, просто сохраните такое же расположение нужного файла в папке с вашей кастомной темой. Более подробно про создание собственных тем, читайте на соответствующей странице.

EmailAddress - Проверка email адреса

Валидатор EmailAddress позволяет выполнить различные проверки email адреса. Валидатор сначала разбивает адрес электронной почты на local-part@hostname и пытается сопоставить их с известными спецификациями для адресов электронной почты и имен хостов.

Поддерживаемые параметры

  • allow: Определяет, какой тип доменных имен принимает валидатор. Эта опция используется вместе с опцией hostnameValidator для установки валидатора имени хоста. Возможные значения этой опции определены в константах ALLOW_ * валидатора Hostname:

    • ALLOW_DNS: (по умолчанию) Разрешает доменные имена (например example.com)

    • ALLOW_IP: Разрешает IP адреса.

    • ALLOW_LOCAL: Разрешает локальные домены такие как localhost или www.localdomain

    • ALLOW_ALL: Разрешить все типы хостов.

  • useDeepMxCheck: Указывает валидатору на необходимость усиленной проверки MX записей домена. Если для этого параметра установлено значение true, то в дополнение к записям MX также используются записи A, A6 и AAAA для проверки того, принимает ли сервер электронную почту. Эта опция по умолчанию имеет значение false.

  • useDomainCheck: Определяет, должна ли быть проверена часть домена. Если для этого параметра установлено значение false, будет проверяться только локальная часть адреса электронной почты. В этом случае валидатор имени хоста не будет вызван. Эта опция по умолчанию имеет значение true.

  • hostnameValidator: Задает экземпляр объекта валидатора имени хоста, с помощью которого будет проверяться доменная часть адреса электронной почты.

  • useMxCheck: Определяет, должны ли быть обнаружены записи MX с сервера. Если для этого параметра задано значение true, то MX-записи используются для проверки того, принимает ли сервер электронную почту или нет. Эта опция по умолчанию имеет значение false.

Пример использования

Рассмотрим наиболее распространенный пример, которого скорее всего вам будет достаточно. Этот пример проверяет существование домена и возможность принимать email. Т.е. выполняется максимально возможная проверка. Она пропустит только точно существующий домен с MX записями.

// Массив полей и значений
$data = [
    'test' => 'info@johncms.com',
];

// Настройки валидатора
$rules = [
    'test' => [
        'EmailAddress'   => [
            'allow'          => Laminas\Validator\Hostname::ALLOW_DNS,
            'useMxCheck'     => true,
            'useDeepMxCheck' => true,
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

Шаблоны электронных сообщений (email)

Начиная с JohnCMS 9.3 в системе появилась поддержка шаблонов для email.

Для чего это нужно?

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

Как это работает?

Рассмотрим пример письма:

В письмах как и на всем сайте есть основной шаблон, который является общим практически для всех страниц (header/footer. На скриншоте отмечен цифрами 1 и 3). Сам текст письма - это контентная область (на скриншоте отмечена цифрой 2), которая в разных письмах может выглядеть по разному.

Базовых шаблонов может быть несколько и каждый шаблон сообщения может использовать любой базовый шаблон.

Всё это позволит вам менять базовый шаблон не меняя все шаблоны писем. Например, вы можете сделать несколько шаблонов на все времена года, зимний, летний, весенний, осенний и менять их когда это необходимо. При этом вам нужно будет изменить всего 1 файл, а шаблоны писем изменять не придется вовсе.

Где хранятся шаблоны?

Почтовые шаблоны так же как и основные шаблоны сайта хранятся в папке themes.

Основной шаблон расположен в папке themes/default/templates/system/mail/layouts/default.phtml

В этом файле расположен основной макет письма.

Шаблоны конкретных сообщений расположены в папке themes/default/templates/system/mail/templates

Шаблонная система для почтовых сообщений работает так же как и шаблоны основного сайта. Поддерживается возможность переопределения и все прочие возможности. Для кастомизации системных шаблонов копируйте их в папку с собственным шаблоном. Таким образом вам не придется переносить изменения при обновлении CMS.

ALLOW_URI: Разрешает имена хостов в универсальном синтаксисе URI. См.

RFC 3986

Создание собственного шаблона

Давайте создадим свой первый простой шаблон. Начнем с задачи, которая изначально возникнет практически у всех, кто установит себе JohnCMS: мы будем менять Главную страницу сайта и логотип. Перед тем, как взяться за создание своего шаблона, давайте составим примерный план предполагаемых работ.

Что мы сделаем?

  • Создадим свою тему с названием "lesson"

  • Поменяем Главную страницу сайта. Вместо имеющегося по умолчанию текста, на ней крупными буквами выведем "Добро пожаловать!"

  • Заменим логотип сайта. Вместо JohnCMS будем использовать свою .PNG картинку.

  • Изменим цвет боковой панели навигации: вместо белого использовать какой-нибудь темный оттенок, подходящий по дизайну. Соответственно поменяем цвет иконок.

Внимание!

У движка есть тема "default", которая является системной, поставляется вместе с дистрибутивом и находится в папке /themes/default. В этой теме находятся все необходимые для работы файлы по умолчанию: шаблоны, стили, картинки, скрипты и т.д. Также, каждый отдельный модуль может иметь свою папку с шаблонами /module_name/templates, или другими файлами общего доступа /assets/modules/module_name.

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

Пошаговая инструкция

  1. В папке /themes создаем папку lesson

  2. Заходим в админку и далее в системные настройки. Там в списке имеющихся тем мы увидим нашу lesson. Выбираем ее и нажимаем "Сохранить". Теперь для нашего сайта применена тема "lesson" и все, что мы будем в ней делать, сразу же будет видно.

  3. Чтобы поменять Главную страницу сайта, мы должны отредактировать ее шаблон, который находится в модуле /modules/homepage. В папке с модулем есть папка /templates а в ней лежит файл index.phtml - это и есть Главная страница, этот файл нам и нужен. Из предупреждения выше мы знаем, что менять шаблон в самом модуле нельзя, поэтому мы должны сначала скопировать файл шаблона в свою тему, и только потом его изменять. Не переместить, а именно скопировать, оригинал файла должен остаться на своем месте

  4. Куда? /themes/lesson - это папка с нашей темой, которую мы создали выше. Мы должны скопировать сюда файл index.phtml из модуля homepage. Для шаблонов в папке с нашей темой должна быть подпапка templates. Чтоб не возникало конфликтов (например файл index.phtml может быть у многих модулей), в папке templates создается подпапка с названием пространства имен для шаблонов модуля (обычно совпадает с именем папки модуля) и уже в нее копируется нужный нам файл.

  5. В папке с нашей темой /themes/lesson создаем подпапку templates а в ней подпапку с именем модуля ( в нашем случае это homepage) откуда мы копируем шаблон. В итоге должно получиться /themes/lesson/templates/homepage/ сюда и копируем наш index.phtml Теперь, пока у нас в админке включена наша тема "lesson", для Главной страницы используется именно тот файл, который мы только что скопировали в нашу тему. И все изменения в этом файле сразу будут видны на Главной странице нашего сайта.

Инструкция будет дополнена.

Структура модуля

Модули располагаются в папке modules Обычно модуль для JohnCMS имеет следующую структуру:

  • modules

    • module_name

      • includes

      • locale

      • templates

      • index.php

Данная структура носит лишь рекомендательный характер и не является обязательной. Система не накладывает ограничений на разработчика и разработчик вправе использовать свою структуру модуля, которая для него будет удобнее.

Давайте подробнее посмотрим на структуру и разберемся что и для чего предназначено.

modules - это обычная системная папка с модулями. module_name - это папка с названием модуля (например forum, community и т.п.) includes - папка для дополнительных страниц. Её может и не быть если модуль достаточно простой и не содержит большого количества страниц. locale - это папка в которой хранятся файлы локализации модуля. Если модуль мультиязычный, то эта папка обычно есть. templates - в этой папке хранятся шаблоны модуля. index.php - Этот файл обычно служит точкой входа в модуль и содержит программный код или часть кода всего модуля.

Создание модуля

Давайте создадим свой первый простой модуль. Это будет обычная простая страница контактов для связи с администрацией сайта.

Как нам уже известно, модули располагаются в папке modules

Сначала давайте создадим папку с модулем и назовем её contacts путь к папке получится такой: modules/contacts

Пока создадим простой модуль без мультиязычности.

Внутри папки modules/contacts создадим подпапку templates для шаблона нашей страницы. Дополнительные папки нам больше не понадобятся т.к. модуль у нас будет содержать всего лишь одну страницу. Создадим точку входа в модуль, которая будет открываться при запросе страницы контактов и в которой будет подключен наш шаблон. Для этого создадим файл index.php

В этом файле поместим следующий код:

<?php

// Запрещаем прямой запрос к файлу модуля без подключенного ядра
defined('_IN_JOHNCMS') || die('Error: restricted access');

// Инициализируем шаблонизатор
$view = di(Johncms\System\View\Render::class);

// Инициализируем хлебные крошки (цепочка навигации вверху всех страниц)
$nav_chain = di(Johncms\NavChain::class);

// Указываем шаблонизатору папку, из которой нужно загружать шаблоны нашего модуля
$view->addFolder('contacts', __DIR__ . '/templates/');

// Добавляем ссылку Контакты в хлебные крошки
$nav_chain->add('Контакты', '/contacts/');

// Собираем массив данных, который будет передан в шаблон
$data = [
    'title'      => 'Контакты',
    'page_title' => 'Наши контакты',
];

// Дополним массив $data нашими контактными данными, которые выведем дальше в шаблоне
$data['contacts'] = [
    [
        'name'  => 'E-mail', // Название контакта
        'value' => 'admin@example.com', // Значение, которое будет отображаться
    ],
    [
        'name'  => 'Номер телефона',
        'value' => '+7 (999) 121-12-21',
    ],
    [
        'name'  => 'Telegram',
        'value' => '@johncms_official',
    ],
];

// Подключаем шаблон index.phtml и передаем в него собранные выше данные
echo $view->render('contacts::index', ['data' => $data]);

В комментариях к каждой строке кода даны пояснения для чего она.

Далее давайте создадим наш шаблон. Шаблон будет располагаться в папке templates и т.к. это основная страница контактов, назовем шаблон index.phtml В этом файле разместим следующий код:

<?php

// Подключаем основной шаблон сайта
$this->layout(
    'system::layout/default',
    [
        'title'      => $data['title'], // Передаем заголовок страницы в тег title
        'page_title' => $data['page_title'], // Передаем заголовок страницы в тег h1
    ]
);
?>

<div>
    Вы можете связаться с нами по любому из нижеперечисленных контактов:
</div>

<ul>
    <!-- Тут мы перебираем наш массив контактов и выводим название контакта и значение, разделяя их двоеточием -->
    <?php foreach ($data['contacts'] as $contact): ?>
        <li><?= $contact['name'] ?>: <b><?= $contact['value'] ?></b></li>
    <?php endforeach; ?>
</ul>

Наш модуль готов, но пока ещё не доступен в браузере. Давайте это исправим. Чтобы модуль стал доступен, нужно сообщить системе, что у нас есть такой модуль и мы хотим чтобы он был доступен по определенному адресу. Для этого давайте перейдем в папку config и в ней создадим файл routes.local.php если его ещё нет. Если есть, то откроем его и добавим маршрут для нашего модуля.

<?php

/**
 * /contacts/ - Это адрес страницы по которому будет доступен наш модуль
 * modules/contacts/index.php - Это путь к точке входа в наш модуль
 */
$map->addRoute(['GET', 'POST'], '/contacts/', 'modules/contacts/index.php');

Теперь наш модуль доступен по адресу ваш.сайт/contacts/ Теперь давайте сообщим модулю online, что у нас появился модуль контактов и нужно в списке пользователей онлайн отображать тех, кто смотрит контакты. Для этого давайте перейдем в папку config и в ней создадим файл places.local.php если его ещё нет.

<?php

return [
    '/contacts' => '<a href="/contacts/">Смотрит контакты</a>',
];

Отлично, наш модуль теперь полностью работоспособен, вам останется только добавить на него ссылку в основном шаблоне или на любой другой странице на ваше усмотрение.

Валидация

Что такое валидатор и зачем он нужен?

Разработчики модулей создавая модули часто сталкиваются с задачей валидации форм, которые отправляет пользователь. Например, практически в любой форме есть поля, обязательные для заполнения. Так же есть поля, значения которых нужно проверить на наличие в базе данных, в некоторых полях может находиться файл, размер которого нам нужно проверить, ссылка, правильность которой тоже нужно проверить или же email адрес в котором, например, нужно проверить не только корректность текста до и после символа @, но и наличие MX записей для указанного домена.

Для избавления от частых рутинных операций и упрощения кода в JohnCMS встроены различные, часто используемые базовые валидаторы.

Что позволяет делать валидатор?

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

При просмотре документации по валидаторам вам может показаться, что это достаточно громоздко, но не спешите, работа с валидатором в JohnCMS сильно упрощена, к тому же реализованы некоторые дополнительные валидаторы, которые вам скорее всего пригодятся. Давайте рассмотрим пример и разберемся в некоторых деталях.

<?php

require 'system/bootstrap.php';

// Массив полей и значений
$data = [
    'test'   => '',
    'number' => 100,
    'email'  => 'email@example.ru',
    'model'  => 110,
];

// Настройки валидатора
$rules = [
    // Название поля => [ правила валидации и их параметры ]
    'test'   => [
        'NotEmpty',
        'StringLength' => [
            'min' => 6,
            'max' => 80,
        ],
    ],
    'number' => [
        'NotEmpty',
        'LessThan' => ['max' => 90],
    ],
    'email'  => [
        'EmailAddress' => [
            'useMxCheck' => true,
        ],
    ],
    'model'  => [
        'ModelExists' => [
            'model' => \Johncms\Users\User::class,
            'field' => 'id',
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

Здесь массив $data содержит набор данных, которые будут проверяться. Часто это данные из формы, полученные методом POST или GET.

Массив $rules содержит набор правил и их настройку. В качестве ключа указывается название поля из массива $data, а в качестве массива со значениями используется валидатор или набор валидаторов и их настройки. Например в первом правиле проверяется значение поля под названием test, к нему применяется валидатор NotEmpty и StringLength. Валидатор NotEmpty проверяет не пустое ли значение в поле test, а валидатор StringLength проверяет длину значения. В данном случае длина значения должна быть от 6 до 80 символов.

Как видите, валидатор может не иметь настроек, а может иметь настройки. Если валидатор не имеет настроек или же вам подходят настройки по умолчанию, то вы можете передать только название валидатора. Если вам нужно дополнительно настроить валидатор, просто передаете массив настроек.

Многие популярные валидаторы мы рассмотрим отдельно. Пока можете попробовать выполнить код выше. Для этого в корне вашего сайта создайте файл test.php и вставьте в него этот код. После этого откройте в браузере страницу site.ru/test.php. Вы увидите следующий результат:

Array
(
    [test] => Array
        (
            [isEmpty] => Поле является обязательным и не может быть пустым
        )

    [number] => Array
        (
            [notLessThan] => The input is not less than '90'
        )

    [email] => Array
        (
            [emailAddressInvalidMxRecord] => 'example.ru' Похоже, что записи MX или A для адреса электронной почты не действительны
        )

    [model] => Array
        (
            [modelNotFound] => Нет записей, соответствующих введенным данным
        )

)

Как видно из результата, массив $data не прошел проверку. Валидатор вернул массив полей и правила валидации, которые не прошли проверку. Вы можете изменить в нем значения и понаблюдать за результатом, а так же поэкспериментировать с другими правилами.

Работа с уведомлениями

Как вы наверное уже знаете, в JohnCMS начиная с версии 9.2 появились улучшенные уведомления. Давайте разберемся как они работают и научимся добавлять свои уведомления.

Для работы уведомлений существует таблица в базе данных, которая называется notifications. Она хранит все уведомления для всех пользователей сайта.

Рассмотрим поля, которые доступны в таблице уведомлений:

Наименование

Описание

id

Идентификатор уведомления

module

Наименование модуля, который добавил уведомление. (обязательное поле)

event_type

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

user_id

Пользователь, для которого предназначено уведомление. (обязательное поле)

sender_id

Идентификатор пользователя, который инициировал отправку уведомления. (не обязательно)

entity_id

Идентификатор сущности к которой привязано уведомление. (например сообщение на форуме из-за которого было отправлено уведомление). Не обязательное поле.

fields

Массив полей, которые будут доступны в шаблоне уведомления.

read_at

Время прочтения уведомления.

Принцип работы уведомлений:

  • Какой либо модуль добавляет уведомление в систему, привязывая его к модулю, типу события и пользователю, которому предназначено это уведомление.

  • Когда пользователь открывает сайт, для него выполняется выборка уведомлений у которых поле read_at = NULL. (т.е. не прочитанные).

  • После того как пользователь заходит на страницу уведомлений, ему формируется список в соответствии с заданным шаблоном, далее показанные на странице уведомления помечаются прочитанными.

Добавление уведомлений:

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

Рассмотрим пример добавления уведомления:

(new \Johncms\Notifications\Notification())->create(
    [
        'module'     => 'my_the_best_module',
        'event_type' => 'my_module_event1',
        'user_id'    => 1,
        'sender_id'  => 1,
        'entity_id'  => null,
        'fields'     => [
            'variable' => 'Привет! Это'
        ],
    ]
);

Этот код добавит уведомление для модуля my_the_best_module и события с типом my_module_event1.

Для чего же нам нужно название модуля и тип события? Это нужно для того, чтобы отображать уведомления в соответствии с заданным шаблоном.

Шаблоны уведомлений:

Шаблоны уведомлений настраиваются в файле config/notifications.local.php. Если у вас нет этого файла, переименуйте файл notifications.local.php.example в notifications.local.php

Файл с шаблонами должен иметь следующую структуру:

return [
    // Пример шаблонов уведомлений для модулей
    'my_the_best_module' => [
        'name'   => 'Мой лучший модуль!',
        'events' => [
            'my_module_event1' => [
                'name'    => 'Новое сообщение',
                'message' => 'Текст сообщения! #variable# дополнительный текст',
            ],
            'my_module_event2' => [
                'name'    => 'Новый пост',
                'message' => 'Текст уведомления! #variable# дополнительный текст',
            ],
        ],
    ],
];

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

Давайте посмотрим как выглядит наше уведомление, которое мы добавили выше.

Как видно на скриншоте, вывелось уведомление с типом my_module_event1. В тексте уведомления заменилась макропеременная #variable# на ту, которую мы подавали при создании уведомления в массиве fields.

ModelExists - Проверка существования записи в БД

Валидатор ModelExists позволяет проверить существование записи в базе данных. Это хорошо подходит для тех случаев, когда у вас в форме есть привязка к каким-то существующим записям в базе данных.

Поддерживаемые параметры

  • model: Класс модели, который будет использоваться для построения запроса к БД.

  • field: Столбец в БД по которому будет осуществляться поиск записи.

Примеры использования

// Массив полей и значений
$data = [
    'test' => 45,
];

// Настройки валидатора
$rules = [
    'test' => [
        'ModelExists'   => [
            'model' => \Johncms\Users\User::class,
            'field' => 'id',
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В указанном примере будет выполнена проверка наличия пользователя c идентификатором 45 в таблице users.

Запрос который будет выполнен:

SELECT * FROM `users` WHERE `id` = 45

В результате, если будет найдена запись с id = 45, то валидатор будет считать проверку успешной, если не найдет, то вернёт ошибку.

Рассмотрим ещё один пример:

// Массив полей и значений
$data = [
    'test' => 'admin',
];

// Настройки валидатора
$rules = [
    'test' => [
        'ModelExists'   => [
            'model' => \Johncms\Users\User::class,
            'field' => 'name',
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В этом примере будет выполнен поиск записи у которой поле name = admin.

Будет выполнен следующий запрос:

SELECT * FROM `users` WHERE `name` = 'admin'

Результат будет такой же как и в случае с id. Если будет найдена строка с полем name = admin, то валидация пройдет успешно, если нет, будет возвращена ошибка.

LessThan - Менее чем

Валидатор LessThan позволяет проверить число на предмет того, что оно меньше чем заданное в параметре. Обратите внимание, что данный валидатор работает только с числами. Строки или даты этот валидатор не позволяет проверять.

Поддерживаемые параметры

  • inclusive: Включая максимальное значение. Если задано true, то значение равное максимальное значение будет проходить валидацию. Если задано false, то значение равное максимальному значению не будет проходить валидацию.

  • max: Устанавливает максимальное значение.

Примеры использования

Этот пример выведет "OK", т.к. включен параметр inclusive и значение равно максимальному.

А этот пример выведет ошибку т.к. параметр inclusive имеет значение false т.к. этот параметр исключает максимальное значение.

ModelNotExists - Проверка отсутствия записи в БД

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

Поддерживаемые параметры

  • model: Класс модели, который будет использоваться для построения запроса к БД.

  • field: Столбец в БД по которому будет осуществляться поиск записи.

  • exclude: Параметры для задания условий исключения из выборки. Может содержать анонимную функцию или массив с полями field и value.

Примеры использования

В примере выше выполняется проверка наличия в таблице users пользователя с полем mail, содержащим admin@admin.ru. При этом из выборки исключаются строки с name = admin и id = 1. Для расширения запроса на выборку используется анонимная функция. Она позволяет дополнять запрос любыми условиями. Валидатор выполнит следующий запрос:

Рассмотрим более простой пример, где в параметр exclude передается массив:

Если вам не требуется сложное условие для исключения записей из выборки, то вы можете использовать такой вариант задания исключений. При таких настройках валидатор выполнит следующий запрос:

Ну и давайте рассмотрим минимальный вариант использования, вообще без исключений.

При таких настройках валидатор просто проверит наличие записи с mail = admin@admin.ru. Если запись будет найдена, то валидатор вернёт ошибку. Если нет, проверка пройдет успешно.

Запрос, который выполнит валидатор при этих настройках будет таким:

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

Для работы этого валидатора вам потребуется существующая .

Для работы этого валидатора вам потребуется существующая .

laminas-validator
модель
// Массив полей и значений
$data = [
    'test' => 60,
];

// Настройки валидатора
$rules = [
    'test' => [
        'LessThan' => [
            'max'       => 60,
            'inclusive' => true,
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}
// Массив полей и значений
$data = [
    'test' => 60,
];

// Настройки валидатора
$rules = [
    'test' => [
        'LessThan' => [
            'max'       => 60,
            'inclusive' => false,
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}
// Массив полей и значений
$data = [
    'test' => 'admin@admin.ru',
];

// Настройки валидатора
$rules = [
    'test' => [
        'ModelNotExists' => [
            'model'   => \Johncms\Users\User::class,
            'field'   => 'mail',
            'exclude' => static function ($query) {
                return $query->where('name', '!=', 'admin')->where('id', '!=', 1);
            },
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}
select * from `users` where (`name` != 'admin' and `id` != 1) and `mail` = 'admin@admin.ru' limit 1
// Массив полей и значений
$data = [
    'test' => 'admin@admin.ru',
];

// Настройки валидатора
$rules = [
    'test' => [
        'ModelNotExists' => [
            'model'   => \Johncms\Users\User::class,
            'field'   => 'mail',
            'exclude' => [
                'field' => 'name',
                'value' => 'admin',
            ],
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}
select * from `users` where `name` != 'admin' and `mail` = 'admin@admin.ru' limit 1
// Массив полей и значений
$data = [
    'test' => 'admin@admin.ru',
];

// Настройки валидатора
$rules = [
    'test' => [
        'ModelNotExists' => [
            'model'   => \Johncms\Users\User::class,
            'field'   => 'mail',
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}
select * from `users` where `mail` = 'admin@admin.ru' limit 1
модель

Удаление записей (delete)

Конструктор запросов так же позволяет удалять данные из таблиц в базе данных. Так же как и в остальных случаях работы с базой данных нам необходимо получить объект подключения к базе данных.

$connection = \Illuminate\Database\Capsule\Manager::connection();

Вы можете удалить все записи из таблицы следующим образом:

$connection->table('test_table')->delete();

Этот пример кода удалит все записи из таблицы test_table. Обратите внимание, значение автоинкремента не изменяется при таком подходе, по этому идентификаторы будут генерироваться не с нуля, а продолжат с того же номера на котором остановились.

Так же вы можете удалить запись с определенным идентификатором (если в таблице есть колонка id). Для этого в метод delete() передайте идентификатор строки, которую хотите удалить.

$connection->table('test_table')->delete(10);

Конструктор поддерживает установку дополнительных условий для удаления. В следующем примере удалятся все записи у которых идентификатор будет меньше чем 15

$connection->table('test_table')->where('id', '<', 15)->delete();

А этот пример удалит все записи с именем test

$connection->table('test_table')->where('name', '=', 'test')->delete();

Иногда нужно очистить таблицу полностью и сбросить значение автоинкремента. Сделать это можно следующим образом:

$connection->table('test_table')->truncate();

В примерах ниже мы так же будем работать с таблицей test_table, структуру которой вы можете посмотреть в статье

Вставка записей (insert)

Настройки подключения к базе данных

JohnCMS как и многие другие системы для работы использует базу данных. Когда вы устанавливаете систему, создается файл config/autoload/database.local.php в этом файле хранятся настройки подключения к базе данных.

На данный момент по умолчанию он выглядит так:

array (
    'db_host' => 'localhost',
    'db_name' => 'johncms',
    'db_user' => 'database_user',
    'db_pass' => 'password',
  ),
);

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

array (
    'db_driver' => 'mysql',
    'db_host' => 'localhost',
    'db_name' => 'johncms',
    'db_user' => 'database_user',
    'db_pass' => 'password',
    'db_port' => '3306',
  ),
);

В параметре db_port указывается порт, который используется для подключения к БД. В параметре db_driver указывается драйвер для работы с базой данных.

В настоящее время полностью поддерживается работа с MySQL 5.6.4 и выше.

Ban - Проверка банов

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

Поддерживаемые параметры

  • bans: Массив банов, наличие которых будет проверяться. Параметр не обязателен. По умолчанию проверяется бан "Полная блокировка".

Пример использования

// Массив полей и значений
$data = [
    'test' => 'token',
];

// Настройки валидатора
$rules = [
    'test' => [
        'Csrf',
        'Flood',
        'Ban' => [11, 13],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В указанном примере будет проверяться бан для форума (11) и гостевой (13). Если у пользователя есть хотя бы 1 из этих банов, проверка не пройдет.

Captcha - Проверка защитного кода

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

Поддерживаемые параметры

  • sessionField: Указывается ключ в сессии из которого валидатор будет использовать код. По умолчанию: code

Примеры использования

// Массив полей и значений
$data = [
    'test' => 'captcha_code',
];

// Настройки валидатора
$rules = [
    'test' => [
        'Captcha',
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В указанном выше примере код код будет использоваться из переменной по умолчанию $_SESSION['code']

// Массив полей и значений
$data = [
    'test' => 'captcha_code',
];

// Настройки валидатора
$rules = [
    'test' => [
        'Captcha' => [
            'sessionField' => 'captcha_code'
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

А в этом примере будет использован код из переменной $_SESSION['captcha_code']

Более подробно работу с формами и с капчей рассмотрим в отдельной статье.

Изменение стилей шаблона

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

Давайте разберемся где у нас подключаются стили и js и начнем делать свою тему на основе этого.

Откроем файл themes/default/templates/system/layout/default.phtml Как вы наверное догадались это основной шаблон нашего сайта.

Вверху найдем строчку:

<link rel="stylesheet" href="<?= $this->asset('css/app.css', true) ?>">

Эта строка у нас подключает css файл из папки themes/default/assets/css/app.css

Внизу строчку:

<script src="<?= $this->asset('js/app.js', true) ?>"></script>

Эта строчка подключает javascript из папки themes/default/assets/js/app.js

Если мы откроем эти файлы, то увидим там много кода в одну строку. Это нормально. Эти файлы собираются сборщиком и сжимаются для ускорения загрузки браузером пользователей. Как вы наверное уже догадались, эти файлы редактировать не нужно т.к. их собирает сборщик.

Давайте разберемся со сборщиком. Настройка сборщика производится в файле /webpack.mix.js (в корне сайта). Давайте откроем его и посмотрим что там есть. Найдем там 2 строчки которые там нужны:

mix.js('themes/default/src/js/app.js', 'themes/default/assets/js')
    .sass('themes/default/src/scss/app.scss', 'themes/default/assets/css')

Что-то знакомое тут, не правда ли? Давайте разберемся, что у нас тут для чего.

mix.js('themes/default/src/js/app.js', 'themes/default/assets/js')

Эта строчка говорит сборщику чтобы он взял файл по пути themes/default/src/js/app.js произвел все необходимые операции с ним и положил его в папку themes/default/assets/js. Т.к. во втором параметре мы явно не указали название файла, сборщик соберет файл и сохранит с таким же именем что и исходный файл т.е. app.js. В итоге получится так: themes/default/assets/js/app.js

Посмотрим на вторую строку

.sass('themes/default/src/scss/app.scss', 'themes/default/assets/css')

В этой строке мы говорим сборщику чтобы он взял файл themes/default/src/scss/app.scss, преобразовал его в пригодный для браузера вид, сжал и положил его в папку themes/default/assets/css. Т.к. название файла явно не указали, сборщик назовет файл так же как и исходный, но расширение укажет css. т.е. app.css. В итоге получится так: themes/default/assets/css/app.css

Теперь мы разобрались как у нас попадают файлы app.js и app.css в нужные папки.

Давайте теперь создадим свою тему и настроим сборщик так, чтобы он собирал ещё и стили и скрипты в нашей теме. Создаем в папке themes подпапку с нашей темой my_theme Из папки с темой default давайте скопируем 2 папки. src и assets На этом наша тема готова к сборке. Теперь давайте расскажем о ней сборщику и соберем наши стили и скрипты.

Открываем файл /webpack.mix.js Вставим после строки

mix.sourceMaps(true, 'source-map');

следующие 2 строки:

mix.js('themes/my_theme/src/js/app.js', 'themes/my_theme/assets/js')
    .sass('themes/my_theme/src/scss/app.scss', 'themes/my_theme/assets/css');

Мы видим тут те же самые пути, которые рассматривали выше, за исключением папки с темой. Это наша новая папка с темой, которую мы создали.

На этом сборщик настроен и уже будет работать.

Давайте откроем командную строку, перейдем в папку с установленным johncms для этого наберите cd и путь к папке в которой установлен johncms. После этого давайте установим зависимости и запустим сборщик. Выполните команду npm install Эта команда установит bootstrap и прочие библиотеки, необходимые для работы.

После этого выполните команду npm run watch

Эта команда соберет app.js и app.css и будет следить за изменением исходных файлов и пересобирать app.js и app.css когда вы изменяете исходные файлы. В результате её выполнения вы должны увидеть следующее:

        Asset                          Size                         Chunks                   Chunk Names
themes/default/assets/css/app.css      258 KiB  /themes/default/assets/js/app  [emitted]        /themes/default/assets/js/app
themes/default/assets/css/app.css.map  295 KiB  /themes/default/assets/js/app  [emitted] [dev]  /themes/default/assets/js/app
themes/my_theme/assets/css/app.css     258 KiB  /themes/default/assets/js/app  [emitted]        /themes/default/assets/js/app
themes/my_theme/assets/css/app.css.map 295 KiB  /themes/default/assets/js/app  [emitted] [dev]  /themes/default/assets/js/app
 + 4 hidden assets

Давайте теперь разбираться в структуре css и js. Откроем файл: themes/my_theme/src/js/app.js Этот файл является основным и в нем подключаются все дополнительные файлы. Все дополнительные файлы лежат в той же папке что и основной файл. Вы можете открывать их, редактировать или смотреть что в них находится.

Откроем файл: themes/my_theme/src/scss/app.scss так же как и app.js этот файл является основным файлом в котором подключаются все дочерние.

Давайте посмотрим файл и найдем наш сайдбар чтобы поменять цвет. Найдем строки

// Левое меню
@import "sidebar";

Эта строка подключает файл sidebar.scss из той же папки что и app.scss Давайте откроем файл sidebar.scss В этом файле мы видим практически привычный CSS код. Но он поддерживает вложенность селекторов и прочие возможности. Вы можете подробнее прочитать про SCSS (SASS) на просторах интернета или спросить у нас на форуме.

И так, давайте поменяем всё таки цвет нашего меню. Цвет меню задан прямо во второй строке:

background-color: #ffffff;

Меняем код цвета и сохраняем файл. После сохранения, сборщик пересоберет app.css и вы увидите изменения на сайте.

Обратите внимание, что команда npm run watch выполняет сборку, но не выполняет сжатие CSS и JS файлов для ускорения работы. Перед тем, как вы захотите выгрузить изменения на сайт, выполните команду npm run prod она соберет файлы и выполнить минификацию. После этого размер файлов будет меньше.

Примечание: После создания темы, не забудьте зайти в настройки и выбрать новую тему :)

Давайте разберемся как же нам теперь работать с нововведениями... Для работы сборщика нам понадобится Node.js. Вы можете скачать его с официального сайта Скачайте и установите Node.js на ваш компьютере. После установки перезагрузите компьютер. Установите JohnCMS на своем компьютере если ещё не установили.

https://nodejs.org/ru/

Перевод JohnCMS на другие языки

JohnCMS является мультиязычной CMS. К сожалению разработчики не знают всех языков, которые существуют на планете и для того чтобы система оставалась мультиязычной, необходимо чтобы люди, знающие другие языки, помогали с переводом. Мы постарались максимально упростить процесс перевода системы на другие языки. Для того, чтобы перевести систему на другой язык, нет необходимости обладать специальными навыками программирования. Перевод осуществляется непосредственно в браузере и может быть выполнен любым желающим.

Чтобы поучаствовать в переводе нужно выполнить некоторые действия. Давайте рассмотрим их по порядку.

Вам необходимо авторизоваться на сайте. Если у вас уже есть учетная запись на crowdin.com или вы зарегистрированы в Facebook, Google, Twitter, Github или Gitlab, то можете нажать на кнопку Log in. Перед вами появится окно авторизации в котором вы можете ввести логин и пароль от учетной записи или войти через описанные выше сервисы. Если учетной записи нет, то нажимаете на Sign up и регистрируетесь.

После авторизации вы можете приступать к переводу. Для этого в списке языков выберите тот язык, на который вы хотите перевести систему

После выбора языка перед вами появится эта страница:

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

Выбираете модуль, который хотите перевести. Попадаете на страницу со списком фраз:

В левой части отображается список фраз для перевода. В центре отображается сам перевод и информация о том, в каких файлах содержится фраза (context). Так же вы можете посмотреть как эта фраза переведена на другие языки, для этого разверните блок OTHER LANGUAGES. Так же есть уже автоматически переведенные варианты (TM and MT Suggestions), которые вы можете выбрать если там есть подходящий вариант. Если подходящего варианта в автоматических переводах нет, то нужно вписать перевод вручную в поле ввода и нажать Save (сохранить). После сохранения автоматически откроется следующая фраза для перевода в текущем модуле.

После завершения перевода модуля, вы можете выйти назад в список модулей. Для этого вверху слева нажимаете на меню и выбираете Quit Editor. После этого вы попадете обратно в список модулей и можете переводить другие модули аналогичным образом.

После того как Вы выполняете перевод, Ваши переводы проходят проверку разработчиками и загружаются в CMS, а потом с выходом обновлений становятся доступны всем.

Обращаем Ваше внимание, что для того, чтобы перевод был включен в дистрибутив, он должен охватывать как минимум 50% фраз.

Переходим по ссылке

Если нужного языка нет в списке, мы можем его добавить. Для этого свяжитесь с разработчиками любым удобным для вас способом (например: ) и напишите название языка, на который Вы хотите перевести систему.

translate.johncms.com
info@johncms.com

Csrf - Проверка токена

Валидатор Csrf предназначен для проверки токена csrf. Токен предназначен для защиты формы от подделки запроса. Данный валидатор работает в паре с генератором токенов \Johncms\Security\Csrf

Поддерживаемые параметры

  • tokenId: Идентификатор токена. Если не задан, используется токен по умолчанию для всего сайта.

Примеры использования

// Массив полей и значений
$data = [
    'test' => 'token',
];

// Настройки валидатора
$rules = [
    'test' => [
        'Csrf',
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

В указанном примере будет проверяться токен по умолчанию.

// Массив полей и значений
$data = [
    'test' => 'token',
];

// Настройки валидатора
$rules = [
    'test' => [
        'Csrf' => [
            'tokenId' => 'guestbook_form'
        ],
    ],
];

// Валидация
$validator = new \Johncms\Validator\Validator($data, $rules);
if ($validator->isValid()) {
    echo 'OK';
} else {
    d($validator->getErrors());
}

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

Более подробно работу с токенами мы рассмотрим в отдельной статье.

Маршрутизация (роутинг)

Для чего нужен роутер в JohnCMS?

Как и в других CMS и фреймворках роутер в JohnCMS обрабатывает запрошенный URL адрес и определяет какой модуль запустить для обработки этого запроса. В свою очередь модуль может получить от роутера различные параметры в зависимости от настроек маршрута и использовать для реализации своего функционала.

Перейдем к практической части.

Где хранятся настройки маршрутизации?

Настройки для системных модулей JohnCMS хранятся в файле /config/routes.php

Так же система позволяет задавать маршруты для сторонних модулей. Для этого предназначен файл /config/routes.local.php

Почему для маршрутов сторонних модулей используется отдельный файл? Дело в том, что при обновлениях JohnCMS файл /config/routes.php может меняться и при очередном обновлении все Ваши изменения в нем, будут утеряны. Чтобы решить эту проблему, используется файл /config/routes.local.php

Пример файла /config/routes.local.php

/config/routes.local.php
<?php

declare(strict_types=1);

/**
 * @var FastRoute\RouteCollector $map
 */

/*
 * /contacts/ - Это адрес страницы по которому будет доступен наш модуль
 * modules/contacts/index.php - Это путь к точке входа в наш модуль
 */

$map->addRoute(['GET', 'POST'], '/contacts/', 'modules/contacts/index.php');

Давайте теперь рассмотрим детально как работать с роутером и как использовать его в своих модулях?

Возьмём простой пример из примера выше. Маршрут у нас в нем задается такой строкой:

$map->addRoute(['GET', 'POST'], '/contacts/', 'modules/contacts/index.php');

Эта строка говорит роутеру следующее: Если запрос пришел методом GET или POST и он поступил на страницу site.ru/contacts/, то необходимо выполнить файл modules/contacts/index.php Таким образом, когда пользователь переходит по адресу site.ru/contacts/ он видит результат выполнения файла modules/contacts/index.php

Откроем файл /config/routes.local.php

Изменим нашу строку маршрута следующим образом:

$map->addRoute(['GET', 'POST'], '/contacts/[{action}/]', 'modules/contacts/index.php');

Мы добавили в неё дополнительный параметр [{action}/] Что это значит? Квадратные скобки говорят роутеру, что этот параметр у нас не обязателен (он может быть, а может и не быть). В фигурных скобках задается название параметра, чтобы модуль смог с ним работать. Слэш мы ставим чтобы ограничить выбор т.е. выбираться будет та часть адреса, которая расположена между /contacts/ и следующим слешем.

Чтобы было понятнее, давайте разберем на примерах. 1. site.ru/contacts/ - В таком варианте у нас параметр action будет игнорироваться т.к. роутер считает его необязательным и откроет нашу страницу контактов. 2. site.ru/contacts/moscow - В таком варианте роутер откроет страницу ошибки 404 т.к. URL у нас не заканчивается обратным слешем, а в настройках маршрута мы явно указали, что если после /contacts/ есть ещё что-то, то обрабатываем этот маршрут только если он заканчивается слешем (/). 3. site.ru/contacts/moscow/ - Такой вариант откроет нашу страницу контактов и в модуле будет доступен параметр action. В этом параметре будет содержаться слово "moscow". 4. site.ru/contacts/new_york/ - Тоже самое что и в варианте 3, только в параметре action будет "new_york" 5. site.ru/contacts/new_york/test1/ - Выдаст ошибку 404 т.к. роутер видит, что маршрут не подходит нам (содержит больше данных чем нужно для нашего маршрута).

Давайте теперь разберемся как в модуле нам получить параметры, которые мы указываем в роутере. Откроем файл modules/contacts/index.php В начале файла после строки defined('_IN_JOHNCMS') || die('Error: restricted access'); вставим следующий код:

modules/contacts/index.php
// Получаем массив параметров, которые вернул нам роутер

$route = di('route');
// Выведем их на экран
d($route);

// Прекратим выполнение скрипта
exit;

Перейдем по адресу: site.ru/contacts/moscow/

В браузере у вас отобразится следующий текст:

Array
(
    [action] => moscow
)

Как мы видим, параметр, который мы назвали в настройках маршрута action, появился у нас в массиве и содержит слово moscow.

В модуле мы можем обратиться к этому параметру и в зависимости от его содержимого управлять логикой работы модуля. Получить этот параметр можно, как вы наверное уже догадались, следующим образом: $route['action']

Давайте усложним маршрут. Откроем файл /config/routes.local.php Изменим нашу строку маршрута следующим образом:

$map->addRoute(['GET', 'POST'], '/contacts/[{action}/[{id:\d+}/]]', 'modules/contacts/index.php');

В этом параметре мы добавили ещё один необязательный параметр и назвали его id. Через двоеточие мы указали регулярное выражение по которому будем вызывать этот маршрут. Указанное регулярное выражение принимает только цифры. Теперь у нас модуль контактов открывается по адресам: site.ru/contacts/ site.ru/contacts/moscow/ site.ru/contacts/moscow/123456/

Вместо слова moscow может быть любое слово, а вместо 123456 может быть любое число. Перейдем по адресу site.ru/contacts/moscow/123456/ и посмотрим что у нас выведется.

Вывелось следующее:

Array
(
    [action] => moscow
    [id] => 123456
)

Как видим, пришел параметр action и id

Давайте добавим третий параметр и ещё усложним наш маршрут. Откроем файл /config/routes.local.php Изменим нашу строку маршрута следующим образом:

$map->addRoute(['GET', 'POST'], '/contacts/[{action}/[{id:\d+}/[{street}/]]]', 'modules/contacts/index.php');

В этом маршруте мы добавили параметр street, он не ограничен только цифрами и может принимать любую строку. Рассмотрим примеры адресов, которые будут доступны для такого маршрута: site.ru/contacts/ site.ru/contacts/moscow/ site.ru/contacts/moscow/123456/ site.ru/contacts/moscow/123456/sadovaya/

Перейдем по адресу: site.ru/contacts/moscow/123456/sadovaya/

Отобразилось следующее:

Array
(
    [action] => moscow
    [id] => 123456
    [street] => sadovaya
)

Давайте переименуем параметр action в city чтобы на различных примерах посмотреть на что влияет это название

$map->addRoute(['GET', 'POST'], '/contacts/[{city}/[{id:\d+}/[{street}/]]]', 'modules/contacts/index.php');

Перейдем по тому же адресу: site.ru/contacts/moscow/123456/sadovaya/

Получим результат:

Array
(
    [city] => moscow
    [id] => 123456
    [street] => sadovaya
)

Как видим в результате тоже поменялось название параметра.

Давайте рассмотрим более сложные примеры маршрутизации. Для этого давайте изменим наш простой модуль контактов, который мы создавали в предыдущей статье

Мы рассмотрели наиболее частые варианты использования маршрутизации и надеемся дальше вы сможете самостоятельно строить ещё более сложные маршруты. С другими примерами маршрутов, вы так же можете ознакомиться в документации к библиотеке , которая используется в JohnCMS для работы с маршрутами.

Создание модуля
https://github.com/nikic/FastRoute

Обновление записей (update)

Помимо вставки и выборки данных конструктор запросов так же позволяет и обновлять данные в таблицах. Так же как и в остальных случаях работы с базой данных нам необходимо получить объект подключения к базе данных.

$connection = \Illuminate\Database\Capsule\Manager::connection();

Обновление строки в БД

Рассмотрим пример обновления записи в БД. Так же как и метод insert метод update принимает пару название_колонки => значение.

$connection->table('test_table')
    ->where('id', '=', 1)
    ->update(
        [
            'name' => 'test name 1',
            'text' => 'text text text 1',
        ]
    );

Указанный пример обновит строку с идентификатором 1 в таблице test_table и установит значения столбцов, переданные в методе update. Обратите внимание, что мы ещё добавили вызов метода where, который устанавливает условие выборки. Для уточнения выборки может вызываться так же несколько методов where чтобы задать точное условие выборки записей, которые нужно обновить.

Обновление или вставка

Часто встречается ситуация, когда нам нужно обновить запись в базе данных если она уже есть или же вставить если её нет. Обычно это делается вручную. Проверяется наличие записи в БД, и в зависимости от этого вызываются методы на вставку или обновление записи. Это не всегда удобно и заставляет писать много кода. Конструктор позволяет упростить выполнение этой операции. По факту он делает то же самое, но для выполнения этих действий вам не нужно вручную писать выборку, проверку и вставку или обновление.

Рассмотрим на примере:

$connection->table('test_table')
    ->updateOrInsert(
        [
            'name' => 'test',
        ],
        [
            'text' => 'text text text 1',
        ]
    );

В этом примере будет выполнен поиск строки с полем name в котором содержится значение test и если эта запись уже существует, в ней будет обновлено поле text. Если такой строки в БД найдено не будет, то она будет вставлена с обоими значениями. Подытожим. Метод updateOrInsert принимает 2 массива. В первом аргументе принимается массив с условиями, которые будет выполнен поиск записи, а во втором будут значения, которые будут установлены. Если записи не существует, то будет вставлена новая запись со значениями из обоих массивов.

Обратите внимание, что вам не нужно заботиться о защите от SQL инъекций. При выполнении запросов в конструкторе используются подготовленные запросы, благодаря чему выполнение запросов становится безопасным. Но учтите, что это не избавляет вас от необходимости делать данные безопасными при выводе из базы данных там где это необходимо.

Выполнение запросов к базе данных

На данный момент в JohnCMS доступны несколько вариантов выполнения запросов к базе данных.

PDO

Этот вариант многим известен и применяется ещё с JohnCMS 7.0. Давайте рассмотрим особенности использования этого варианта. Чтобы получить объект PDO нам достаточно написать следующий код:

Далее используя объект $db вы можете выполнять запросы к базе данных. Рассмотрим пример, который получает записи из таблицы users:

Этот пример выведет список имен пользователей, которые есть в таблице users.

Обратите внимание При работе с этим вариантом вы должны самостоятельно заботиться о безопасности запросов.

Конструктор запросов (Query Builder)

Для выполнения запросов, сначала нам необходимо получить объект текущего подключения к БД:

Далее давайте выполним тот же запрос, который выполняли в обычном PDO варианте выше.

Этот запрос так же как и в предыдущем варианте выведет список имен пользователей, которые есть в таблице users. Метод get возвращает объект Illuminate\Support\Collection c результатами, в котором каждый результат — это экземпляр PHP-класса StdClass. Вы можете получить значение каждого столбца, обращаясь к столбцу как к свойству объекта. Давайте рассмотрим вариант получения одной строки из таблицы.

Этот запрос вернет пользователя, у которого поле name равно admin.

Рассмотрим вариант вывода записей из таблицы с разбивкой на страницы по 5 элементов:

При вызове метода paginate будет автоматически установлены ограничения для запроса и построен запрос количества элементов в таблице по указанному вами запросу. Т.е. при таком вызове вам не нужно заботиться об указании limit для запроса и не нужно строить запрос на количество записей, конструктор запросов сделает это за вас. При вызове метода render из нашего объекта, будет отрисована постраничная навигация. URL адреса будут построены исходя из текущей страницы. Вам так же не нужно заботиться об их формировании. Шаблон вывода постраничной навигации расположен тут: themes/default/templates/system/app/model_paginator.phtml

Выборка только необходимых столбцов

Иногда вам может понадобиться выбрать только определенные столбцы из таблицы в базе данных. Сделать это можно так:

Для выборки конкретных столбцов используется метод select(). Он принимает названия столбцов в виде массива или просто списком аргументов. Например: select('name', 'id')

Сортировка результата выборки

Часто есть необходимость отсортировать результат выборки по какому-либо столбцу.

В этом примере результат будет отсортирован по id и name. Метод orderBy вторым аргументом принимает направление сортировки asc или desc. По умолчанию asc. Метод orderByDesc это то же самое, что и orderBy('id', 'desc') Как видно из примера, сортировать можно по нескольким колонкам. Указанный выше пример выполнит следующий запрос к базе данных:

В примерах ниже мы так же будем работать с таблицей test_table, структуру которой вы можете посмотреть в предыдущей статье

В JohnCMS для работы с БД используется библиотека которая и предоставляет конструктор запросов и ORM. Рассмотрим несколько основных примеров чтобы понять особенности работы с библиотекой в JohnCMS.

Мы рассмотрели общий принцип построения запросов. Если вы хотите ознакомиться подробно с конструктором запросов, вы можете это сделать или на русском: Обратите внимание, что для выполнения запросов нужно использовать объект $connection, а не DB::. В остальном все возможности, которые описаны по ссылкам, будут работать и в JohnCMS.

Вставка записей (insert)
$db = di(PDO::class);
$db = di(PDO::class);
$req = $db->query('SELECT * FROM `users`');
while ($row = $req->fetch()) {
    echo $row['name'] .'
';
}
$connection = \Illuminate\Database\Capsule\Manager::connection();
$users = $connection->table('users')->get();
foreach ($users as $user) {
    echo $user->name . '<br>';
}
$user = $connection->table('users')->where('name', 'admin')->first();
echo $user->name;
$user = $connection->table('users')->paginate(5);
foreach ($user as $item) {
    echo $item->name;
}
echo $user->render(); 
$user = $connection->table('users')->select(['name', 'id'])->get();
foreach ($user as $item) {
    echo $item->id . ' - ' . $item->name;
}
$user = $connection->table('users')
    ->select('name', 'id')
    ->orderBy('id')
    ->orderByDesc('name')
    ->get();
foreach ($user as $item) {
    echo $item->id . ' - ' . $item->name;
}
select `name`, `id` from `users` order by `id` asc, `name` desc
illuminate/database
здесь
здесь

Вставка записей (insert)

Конструктор запросов позволяет вставлять записи в базу данных. При этом конструктор избавляет вас от необходимости писать SQL запросы самостоятельно. Вы просто используете объектно ориентированные возможности PHP. А если вы используете IDE, то это существенно упростит вам жизнь благодаря автодополнению кода.

Для работы с базой данных нужно получить объект подключения к базе данных. Это можно сделать следующим образом:

$connection = \Illuminate\Database\Capsule\Manager::connection();

Далее рассмотрим примеры вставки данных в таблицу в базе данных. В примере будет рассматриваться таблица со следующей структурой:

Вставка строки

Рассмотрим пример обычной вставки строки в таблицу test_table.

$connection->table('test_table')->insert(
    [
        'name' => 'test name',
        'text' => 'text text text',
    ]
);

Этот пример кода вставит строку в базу данных. Как видите всё достаточно просто. В метод table подается название таблицы с которой работаем, а далее вызывается метод insert в который подается ассоциативный массив в котором ключем является название колонки в таблице test_table, а значением является значение, которое будет вставлено.

Вставка строки и получение идентификатора вставленной записи

В примере выше мы рассмотрели обычную вставку строки в базу данных. Но часто нам нужно вдобавок к этому получить идентификатор вставленной записи. Давайте сделаем это.

$id = $connection->table('test_table')->insertGetId(
    [
        'name' => 'test name',
        'text' => 'text text text',
    ]
);

Как вы видите, вместо метода insert использовался метод insertGetId, а результат присваивается переменной $id. После выполнения этого кода в переменной $id будет содержаться идентификатор вставленной записи.

Вставка нескольких строк в таблицу

Иногда есть необходимость вставить сразу много строк в таблицу в базе данных. Конструктор запросов позволяет сделать и это.

$connection->table('test_table')->insert(
    [
        [
            'name' => 'test name 1',
            'text' => 'text text text 1',
        ],
        [
            'name' => 'test name 2',
            'text' => 'text text text 2',
        ],
        [
            'name' => 'test name 3',
            'text' => 'text text text 3',
        ],
    ]
);

Этот пример кода вставит в таблицу test_table сразу 3 строки. В массиве, который передается в метод insert должны передаваться массивы с записями, которые необходимо вставить.

Вставка с игнорированием ошибок

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

$connection->table('test_table')->insertOrIgnore(
    [
        [
            'id'   => 1,
            'name' => 'test name 1',
            'text' => 'text text text 1',
        ],
        [
            'id'   => 2,
            'name' => 'test name 2',
            'text' => 'text text text 2',
        ],
        [
            'id'   => 3,
            'name' => 'test name 3',
            'text' => 'text text text 3',
        ],
    ]
);

В таблице test_table есть колонка id. Это первичный ключ и он должен быть уникальным. Если мы попытаемся вставить строку с существующим id обычным методом insert, то мы получим ошибку. Метод insertOrIgnore вставит 3 строки в таблицу только в том случае, если в ней нет строк с такими же идентификаторами. Если в таблице есть строки с id = 1, но нет строк с идентификаторами 2 и 3, то вставятся только строки с идентификаторами 2 и 3, а первая строка будет проигнорирована.

Обратите внимание, что вам не нужно заботиться о защите от SQL инъекций. При выполнении запросов в конструкторе используются подготовленные запросы, благодаря чему выполнение запросов становится безопасным. Но учтите, что это не избавляет вас от необходимости делать данные безопасными при выводе из базы данных там где это необходимо.

Общие сведения и начало работы

Введение

Система объектно-реляционного отображения (ORM) Eloquent — простая реализация шаблона ActiveRecord для работы с базами данных. Каждая таблица имеет соответствующий класс-модель, который используется для работы с этой таблицей. Модели позволяют запрашивать данные из таблиц, а также вставлять, обновлять и удалять в них записи.

Определение моделей

$loader = new Aura\Autoload\Loader();
$loader->register();
$loader->addPrefix('Blog', __DIR__ . '/lib');

С помощью метода addPrefix первым параметром мы указываем пространство имен (namespace) Blog и указываем папку в которой располагаются классы для этого пространства имен. Создайте таблицу posts с примерно таким набором полей:

  • id

  • user_id

  • name

  • text

  • created_at

  • updated_at

Пример запроса на создание таблицы:

CREATE TABLE `posts`
(
    `id`         INT          NOT NULL AUTO_INCREMENT,
    `user_id`    INT          NOT NULL,
    `name`       VARCHAR(255) NOT NULL,
    `text`       LONGTEXT     NULL DEFAULT NULL,
    `created_at` TIMESTAMP    NULL DEFAULT NULL,
    `updated_at` TIMESTAMP    NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    INDEX `user_id` (`user_id`)
) ENGINE = InnoDB;

Теперь создадим модель. В папке lib/models создайте файл Post.php со следующим содержимым

lib/models/Post.php
<?php

namespace Blog\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * @mixin Builder
 */
class Post extends Model
{

}

На этом модель готова и она уже работоспособна.

Имена таблиц

Заметьте, что мы не указали, какую таблицу Eloquent должен привязать к нашей модели. Если это имя не указано явно, то в соответствии с принятым соглашением будет использовано имя класса в нижнем регистре (snake case) и во множественном числе. В нашем случае Eloquent предположит, что модель Post хранит свои данные в таблице posts. Вы можете указать произвольную таблицу, определив свойство table в классе модели:

<?php

namespace Blog\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * @mixin Builder
 */
class Post extends Model
{
    /**
     * Таблица, связанная с моделью.
     *
     * @var string
     */
    protected $table = 'my_table';

}

Первичные ключи

Eloquent также предполагает, что каждая таблица имеет первичный ключ с именем id. Вы можете определить свойство $primaryKey для указания другого имени. Вдобавок, Eloquent предполагает, что первичный ключ является инкрементным числом, и автоматически приведёт его к типу int. Если вы хотите использовать неинкрементный или нечисловой первичный ключ, задайте открытому свойству $incrementing вашей модели значение false.

Отметки времени

По умолчанию Eloquent ожидает наличия в ваших таблицах столбцов created_at и updated_at. Если вы не хотите, чтобы они автоматически обрабатывались в Eloquent, установите свойство $timestamps класса модели в false:

<?php

namespace Blog\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * @mixin Builder
 */
class Post extends Model
{
    /**
     * Определяет необходимость отметок времени для модели.
     *
     * @var bool
     */
    public $timestamps = false;

}

Если вы хотите изменить формат отметок времени, задайте свойство $dateFormat вашей модели. Это свойство определяет, как атрибуты времени будут храниться в базе данных, а также задаёт их формат при сериализации модели в массив или JSON:

<?php

namespace Blog\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * @mixin Builder
 */
class Post extends Model
{
    /**
     * Формат хранения отметок времени модели.
     *
     * @var string
     */
    protected $dateFormat = 'U';

}

Если вам надо изменить имена столбцов для хранения отметок времени, вы можете задать константы CREATED_AT и UPDATED_AT:

<?php

namespace Blog\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * @mixin Builder
 */
class Post extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'last_update';
}

Получение моделей

После создания модели и связанной с ней таблицы, вы можете начать получать данные из вашей БД. Каждая модель Eloquent представляет собой мощный конструктор запросов, позволяющий удобно выполнять запросы к связанной таблице. Например:

$post = new \Blog\Models\Post();
$all_posts = $post->all();

foreach ($all_posts as $post) {
    echo $post->name . '<br>';
}

Этот код выведет все записи из таблицы posts.

Добавление дополнительных ограничений

Метод all в Eloquent возвращает все результаты из таблицы модели. Поскольку модели Eloquent работают как конструктор запросов, вы можете также добавить ограничения в запрос, а затем использовать метод get для получения результатов:

$post = new \Blog\Models\Post();
$all_posts = $post->where('user_id', '=', 1)
    ->orderBy('name', 'desc')
    ->get();

foreach ($all_posts as $post) {
    echo $post->name . '<br>';
}

Все методы, доступные в конструкторе запросов, также доступны при работе с моделями Eloquent. Вы можете использовать любой из них в запросах Eloquent.

Для начала создадим модель Eloquent. Все модели Eloquent наследуют класс Illuminate\Database\Eloquent\Model. Допустим мы делаем модуль блогов. Создадим базовую структуру модуля как . Модуль назовём blog. Теперь давайте создадим в нем папку lib в которой будем хранить классы нашего модуля и в этой папке создадим подпапку models в которой уже будем размещать наши модели. В итоге должен получиться такой путь: lib/models Теперь настроим автозагрузку классов из папки lib. Для этого в файле index.php нашего модуля поместим следующий код:

описано здесь

Поля (свойства) пользователей

Для работы с пользователями в JohnCMS используется класс \Johncms\Users\User() У пользователя есть различные свойства (поля).

Основные свойства пользователя

Список основных свойств пользователя, которые есть в таблице users:

Название поля

Описание

name

Логин пользователя

name_lat

Логин, но в нижнем регистре, латиницей

password

Хэш пароля пользователя

rights

Права пользователя. Может содержать одно из следующих значений: 0 - Обычный пользователь 3 - Модератор форума 4 - Модератор загрузок 5 - Модератор библиотеки 6 - Супермодератор 7 - Администратор 9 - Супервизор

failed_login

Количество неудачных попыток авторизации

imname

Имя

sex

Пол пользователя. Содержит одно из следующих значений: m - Мужчина zh - Женщина

komm

Количество комментариев

postforum

Количество постов на форуме

postguest

Количество постов в гостевой

yearofbirth

Год рождения

datereg

Дата регистрации (timestamp)

lastdate

Дата последнего визита (timestamp)

mail

E-mail адрес

icq

ICQ (устаревшее)

skype

Skype

jabber

Jabber (устаревшее)

www

Сайт пользователя

about

О себе

live

Город, страна проживания

mibile

Номер телефона

status

Статус пользователя

ip

IP адрес В таблице хранится в преобразованном формате (ip2long). Если вы получаете и записываете данные с помощью класса \Johncms\Users\User(), вам не нужно заботиться о преобразовании. Вы будете видеть IP в обычном формате. Все преобразования выполняются автоматически.

ip_via_proxy

IP адрес за прокси (если удалось определить) В таблице хранится в преобразованном формате (ip2long). Если вы получаете и записываете данные с помощью класса \Johncms\Users\User(), вам не нужно заботиться о преобразовании. Вы будете видеть IP в обычном формате. Все преобразования выполняются автоматически.

browser

User Agent. Если используете модель \Johncms\Users\User(), то поле будет в безопасном для вывода виде. Дополнительно экранировать не требуется.

preg

Пометка подтвержденного пользователя. Если поле запрашивается из модели, то оно будет содержать boolean значение (true/false). В таблице хранится число 0 или 1

regadm

Логин администратора, который подтвердил регистрацию пользователя

mailvis

Пометка включенного отображения e-mail адреса в профиле. Если поле запрашивается из модели, то оно будет содержать boolean значение (true/false). В таблице хранится число 0 или 1

dayb

День рождения

monthb

Месяц рождения

sestime

Текущее время активности пользователя (время активности сессии)

total_on_site

Сколько провёл на сайте (устаревшее и не используется).

lastpost

Время последнего поста (timestamp)

rest_code

Код восстановления пароля

rest_time

Время восстановления пароля

movings

Количество переходов по страницам в рамках текущей сессии.

place

Местоположение пользователя

set_user

Настройки пользователя. При запросе этого поля из модели содержит объект класса Johncms\System\Users\UserConfig При записи через модель, принимает обычный массив и автоматически преобразует в нужный формат. В таблице данные хранятся в сериализованном виде. Поля доступные в объекте: directUrl - Прямые ссылки fieldHeight - Высота полей ввода kmess - Количество элементов на страницу lng - Выбранный язык timeshift - Сдвиг времени youtube - Youtube плеер

set_forum

Настройки форума. Массив с настройками форума. Может быть пустым, если пользователь не сохранял настройки.

set_mail

Настройки почты. Массив с настройками почты. Может быть пустым, если пользователь не сохранял настройки.

karma_plus

Количество положительных голосов в карме

karma_minus

Количество отрицательных голосов в карме

karma_time

Время голосования в карме

karma_off

Запрет кармы. Если поле запрашивается из модели, то оно будет содержать boolean значение (true/false). В таблице хранится число 0 или 1

comm_count

Количество комментариев

comm_old

Устаревшее, не используется

smileys

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

notification_settings

Настройки уведомлений. Массив с настройками уведомлений.

Модель \Johncms\Users\User() в дополнение к основным полям возвращает дополнительные вычисленные поля.

Дополнительные свойства

Список дополнительных свойств пользователя:

Название поля

Описание

is_online

Метка пользователя онлайн (true/false)

rights_name

Название прав доступа текущего пользователя (для обычных пользователей пустая строка)

profile_url

Ссылка на страницу просмотра профиля пользователя

search_ip_url

Ссылка на страницу поиска по ip

whois_ip_url

Ссылка на страницу whois ip

search_ip_via_proxy_url

Ссылка на страницу поиска по IP за прокси

whois_ip_via_proxy_url

Ссылка на страницу whois IP за прокси

ban

Массив активных банов пользователя

is_valid

Свойство используется при работе от текущего пользователя. true - если пользователь авторизован и подтвержден. false - если пользователь не авторизован или не подтвержден.

is_birthday

true - если у пользователя день рождения. false - если нет.

birthday_date

Т.к. дата рождения в таблице users хранится в отдельных полях, то при запросе этого свойства она собирается в одну строку.

display_place

Местоположение пользователя для отображения. Содержит html код ссылки на страницу.

formatted_about

Обработанное поле "О себе". bb-коды преобразованы в html код.

website

Обработанное поле "Сайт". bb-коды преобразованы в html код.

last_visit

Дата последнего визита в человекопонятном виде. Обратите внимание, если пользователь сейчас онлайн, это свойство будет пустым.

photo

Фотография пользователя. Если фотографии нет, возвращает пустой массив. Если фотография есть, возвращает массив со ссылками на фото: photo - Большая фотография. photo_preview - Маленькая фотография для предпросмотра.

Работа с текущим авторизованным пользователем

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

Для работы с ткущим пользователем необходимо получить объект этого пользователя. Сделать это можно следующим образом:

$user = di(\Johncms\Users\User::class);

Проверка авторизации пользователя

if ($user->is_valid) {
    echo 'Пользователь авторизован. Его логин: ' . $user->name;
} else {
    echo 'Пользователь не авторизован';
}

В этом примере если пользователь авторизован, выведется сообщение об этом и логин пользователя.

Проверка прав доступа

if ($user->rights === 9) {
    echo 'Пользователь супервизор!';
} else {
    echo 'Пользователь не супервизор';
}

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

страница авторизации
список языков
список переводов
список фраз
Список конфигурационных файлов в JohnCMS

После этого в переменной $user будут доступны все свойства, описанные в

В этом примере проверяем должность пользователя, и если пользователь супервизор, выведем ему сообщение об этом. Проверяется свойство rights и номер должности. Все номера должностей описаны в .

этом списке
списке свойств

Работа с пользователями в примерах

Модель пользователя уже имеет некоторые предустановленные условия для выборки (заготовки запросов). Например для получения подтвержденных пользователей, вы можете просто вызвать метод approved(), а для получения пользователей, которые сейчас находятся на сайте можно вызвать метод online().

Как это работает? В моделях можно создавать свои заготовки частей запросов. Например сейчас есть заготовка, которая вызывается методом approved(). Эта заготовка по своей сути равнозначна обычному вызову where('preg', '=', 1) Это достаточно простой вариант, но есть вариант немного сложнее. Например чтобы получить пользователей онлайн нам нужно ограничить выборку по времени. Чтобы каждый раз не писать where('lastdate', '>', (time() - 300)) мы можем вызвать заготовку online(). Теперь предположим, что у нас есть 10 страниц, на которых выводятся различные пользователи онлайн. Если бы мы не использовали заготовки запросов, нам бы пришлось везде писать условие для выборки where('lastdate', '>', (time() - 300)) и если бы мы захотели изменить время, в течение которого мы считаем пользователя онлайн, то нам бы пришлось менять его во всех 10 страницах. С заготовкой же нам достаточно изменить время в одном месте и это изменение применится для всех страниц.

А теперь перейдем к примерам:

Получим последних 10 зарегистрированных и подтвержденных пользователей и выведем их идентификаторы и логины:

$users = (new \Johncms\Users\User())->approved()->orderBy('id', 'desc')->limit(10)->get();
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . '<br>';
}

Получим 10 последних пользователей онлайн:

$users = (new \Johncms\Users\User())->online()->orderBy('lastdate', 'desc')->limit(10)->get();
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . '<br>';
}

Получим всех модераторов, администраторов, супервизоров и дополнительно выведем должность:

$users = (new \Johncms\Users\User())->online()->where('rights', '>', 0)->orderBy('lastdate', 'desc')->get();
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . ' -  ' . $user->rights_name . '<br>';
}

Получим 10 пользователей мужского пола:

$users = (new \Johncms\Users\User())->where('sex', '=', 'm')->orderBy('id')->limit(10)->get();
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . '<br>';
}

Получим 10 пользователей женского пола:

$users = (new \Johncms\Users\User())->where('sex', '=', 'zh')->orderBy('id')->limit(10)->get();
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . '<br>';
}

Получим 10 пользователей, у которых больше 100 постов на форуме:

$users = (new \Johncms\Users\User())->where('postforum', '>', 100)->orderBy('id')->limit(10)->get();
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . '<br>';
}

Усложним задачу и получим всех пользователей у которых больше 100 постов и разобьём выборку страницы (15 пользователей на страницу):

$users = (new \Johncms\Users\User())->where('postforum', '>', 100)->orderBy('id')->paginate(15);
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . '<br>';
}
echo $users->render();

Как видите, всё достаточно просто. Мы заменили get() на paginate() убрали limit(10) и в paginate передали количество пользователей, которое мы хотим видеть на одной странице. А дальше с помощью строки echo $users->render(); отрисовали список страниц.

Ну и давайте рассмотрим ещё 1 пример. Получим список пользователей, у которых поле статус не пустое и так же разобьём на страницы и выведем текст статуса.

$users = (new \Johncms\Users\User())->where('status', '!=', '')->orderBy('id')->paginate(15);
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->name . ' - ' . $user->status . '<br>';
}
echo $users->render();

На этом всё, если у вас остались вопросы, задайте их на форуме.

В предыдущей статье мы рассмотрели список Теперь давайте рассмотрим несколько примеров получения данных. Во всех примерах $user позволяет получить доступ ко всем полям, которые описаны в .

полей пользователя.
предыдущей статье
Пример сообщения о регистрации
Пример отображения уведомления
Структура таблицы test_table