Intellect Board Pro
Расширяемый движок форума с разделами разных типов
Объявление
Вышла версия 3.05 с фотогалереей и поддержкой PostgreSQL и SQLite.
Перейти к скачиванию
Привет, гость!

Пишем собственный модуль для IntB

Настройки отображения темы Показывать по сообщений с сортировкой .
Выводить , отправленные .
Одна страница
Распечатать
4X_Pro
Основатель проекта
Всего сообщений: 401
Зарегистрирован: 22 сент. 2014 г., 18:56
Откуда: Москва, Перово
Рейтинг пользователя: 15

0
. Редактировалось 3 раза, последний — #1
Написать собственный модуль для Intellect Board достаточно просто. Первое, с чем нужно определиться — это что мы хотим: модуль-раздел (то есть чтобы из АЦ можно было создавать множество разделов такого типа) или же вспомогательный модуль, у которого есть один или несколько фиксированных адресов (к таковым, например, относятся модуль профиля пользователя, модуль подписок и закладок или модуль поиска по сайту). Начнем со второго, так как это более простой случай.
Допустим, мы хотим сделать модуль hello, который будет выводить приветствие пользователю и количество его сообщений.

Шаг 1. Создание action.
Для этого в каталоге modules создаем файл hello.php, в котором определяем класс hello и делаем его наследником класса Application. Класс Application — это основной класс IntB, в котором собраны все наиболее часто используемые функции, например, получение информации о текущем пользователе, проверке прав доступа. Также в нем содержится класс db для работы с базой данных форума.
Класс модуля содержит несколько actions (для тех кто знает MVC, action можно считать аналогом controller). Каждый action выполняет некоторое завершенное с точки зрения пользователя (например, отправка ответа в тему, регистрация пользователя и т.п.) и выдает ответ — HTML-страницу, редирект на другой адрес или ответ в формате JSON. То, какой именно action будет вызван, определяется в методе process. По умолчанию этот метод наследуется из класса Application и вызывает метод, имя которого передано через параметр a в $_GET или $_POST, а если этот параметр отсутствует, то по умолчанию вызывается action_view. Если в модуле требуется какая-то достаточно сложная логика выбора actionов, метод process можно переопределить, но это решение только для тех, кто знает, что делает и зачем. Имя метода, реализующего действие, обязательно должно начинаться с action_, вызываются они без параметров. В нашем случае назовем его action_userhello и создадим соответствующую функцию:
class hello extends Application {
  function action_userhello() {
    // здесь будет код нашего действия
  }
}

Кроме того, внутри класса Application есть переменная out (обычный объект stdClass), в свойства которой в наших actions будем сохранять все то, что потребуется вывести в шаблоне. Для начала поместим в свойство name имя пользователя:
 class hello extends Application {
  function action_userhello() {
    $this->out->name = $this->get_username(); // функция get_username унаследована из Application
  }
}


Шаг 2. Создание шаблона
Шаблон — это то, что формирует HTML-код, который выдается в результате работы модуля (view в терминах MVC). По умолчанию шаблоны лежат в template/имя_стиля/имя_модуля/действие.tpl. При этом IntB устроен так, что если в используемом шаблоне нет нужного файла, то он берется из шаблона по умолчанию, который называется def. Поэтому при написании своих модулей шаблоны следует класть именно в template/def.
Итак, создаем файл template/def/hello/hellouser.tpl такого содержания:
{% extends 'main.tpl' %} {% block content %} <div id="hello_userhello"> <h1>Наш пробный модуль</h1> {% if is_guest() %} <p>Увы, ты всего лишь гость на этом форуме.</p> {% else %} <p>Привет, <strong>{{ name }}</strong>!</p> <p> У тебя {{ msg_count|incline("%d сообщение", "%d сообщения", "%d сообщений") }}!</p> {% endif %} </div> {% endblock %}
Intellect Board использует шаблонизатор Twig, в котором предусмотрено наследование шаблонов. Директива {% extends %} указывает на то, что шаблон наследуется от template/имя_стиля/main.tpl.
Каждый шаблон состоит из набора блоков (директива {% block %}). Блоки выводятся в том порядке, в котором они определены в родительском шаблоне, но если блок переопределен, то его содержимое заменяется на то, которое указано в дочернем шаблоне.
Основная часть сайта, которая выводится между навигационной строкой («хлебными крошками») и подвалом, выводится в блоке content, который мы и переопределяем второй строчкой.
Дальше идет обычный HTML-код. Переменные выводятся с помощью двойных фигурных скобок, то есть если в action мы записали что-то в $this->out->name, то при выводе указываем просто name. К свойствам хеш-массивов или объектов можно обращаться так же, как в JavaScript — либо указав имя свойства в квадратных скобках (data['proprety']), либо через точку (data.property). Также можно использовать конструкции {% if условие %} и {% for переменная in массив_объектов %}. Экранирование HTML в шаблонах IntB делается по умолчанию, каких-либо дополнительных действий принимать не надо. Если же наоборот, требуется вывести что-то без экранирования, после имени соответствующей переменной добавьте |raw. Но не забывайте о безопасности при таком выводе! Подробнее о синтаксисе Twig можно почитать в его официальной документации.
Кроме блока content вам может потребоваться переопределить блоки CSS (там пишем подключения внешних CSS-файлов или тег style), meta (располагаем meta-теги) и location (вывод «хлебных крошек»), header и footer.
Также можно сделать шаблон без наследования вообще, в этом случае вам придется написать в файле весь HTML-код страницы с <!DOCTYPE html> до </html>. Это может быть полезно, когда дизайн страницы, выдаваемой модулем, сильно отличается от основного сайта.

Шаг 3. Точка входа в модуль
Итак, у нас есть сам модуль и шаблон. Теперь нужно создать файл — точку входа для того, чтобы его запускать. Для этого создаем файл www/hello.php и в нем пишем следующее:
<?php
define
('BASEDIR','../');
require(
BASEDIR.'app/app.php');
require(
BASEDIR.'modules/hello.php');
require(
BASEDIR.'etc/ib_config.php');
global 
$app;
$app = new hello();
$app->main();

В этом файле подключается родительский класс Application, написанный нами модуль hello и файл конфигурации IntB, который лежит в /etc/ib_config.php. После этого создается экземпляр класса-модуля и запускается метод main, который выполняет подготовительные действия (подключение к БД, аутентификация пользователя и т.п., они все вынесены в метод init) и запускает метод process, который, в свою очередь, вызывает запрошенный action.

Шаг 4. Пробный вызов
Если на предыдущих шагах все было сделано правильно, и в коде нет никаких ошибок, то мы уже можем вызвать наш модуль. Для этого перейдем по адресу http://путь-к-форуму/hello.php?a=userhello. В результате должна вывестись страница, где будет написано Привет, Имя!
У тебя сообщений!
(Подсчет количества сообщений в переменную msg_count мы еще не сделали, поэтому там пусто.)

Шаг 5. Делаем URL для модуля
Адреса вида что-то.php?параметры в наше время выглядят устаревшими. Гораздо лучше, если модуль будет вызываться по более красивому и понятному адресу, например http://путь-к-форуму/hello/user.htm. Для этого нужно прописать правило редиректа для Web-сервера. Обычно это делается в файле .htaccess, но в IntB этот файл создается автоматически и при любых действиях с разделами будет переписан. Поэтому мы прописываем правило в шаблоне etc/htaccess.txt, поместив их перед строкой ## Правила разделов (это почти самый конец файла). Правило имеет такой вид:
RewriteRule ^hello/user.htm$ hello.php?a=userhello [L]
В версии IntB 3.02 также был добавлен файл правил редиректа, который используется для nginx или других Web-серверов. Он называется etc/routes.txt (именно .txt, не .cfg!), и в нем тоже нужно прописать это правило, но уже без директивы RewriteRule и модификатора [L]:
^hello/user.htm$ hello.php?a=userhello
После этого нужно зайти в Центр Администрированя и отредактировать любой из разделов, чтобы файлы www/.htaccess и etc/routes.cfg, где лежат актуальные правила редиректа, сгенерировались заново. Теперь заходим http://путь-к-форуму/hello/user.htm и смотрим результат. Он должен быть таким же, как на шаге 4.
Примечание: при прописывании маршрутов можно использовать регулярные выражения и обозначения $1, $2 … $9 точно так же, как и в обычном файле .htaccess.

Шаг 6. Работаем с базой данных
Для работы с базой данных в классе модуля используется объект $this->db, который наследуется из класса Application. На момент запуска action соединение с базой уже установлено (оно делается в функции init_db, которая в свою очередь вызывается из init, а та — из main до вызова process). Основные методы $this->db, которые нужны разработчику модуля — это query, insert, update, select_all, select_row, select_int, select_str. Все они принимают в качестве входного параметра строку с SQL-запросом. query false в случае ошибки, или количество измененных строк (affected rows). select_all возвращает массив, каждый элемент которого — это хеш, соответствующий строке из базы данных (ключи — имена полей), select_row — одну строку как хеш. select_str и select_int возвращают одно поле с приведением к соответствующему типу (соответственно, их имеет смысл вызывать только для запросов, извлекающих из базы всего один столбец). Важно, в запросах не должно быть LIMIT, а значения для него можно передать в select_all в качестве второго и третьего параметров.
Placeholderов IntB пока что нет, поэтому экранирование запросов осуществляется с помощью метода $this->slashes (или $this->db->slashes), в качестве параметра которому передается строка для экранирования. Важно: префикс таблиц IntB может отличаться на разных форумах, поэтому в запросе вместо него следует писать константу DB_prefix.

С учетом всего этого напишем код, который будет считать количество сообщений пользователя:

class hello extends Application {
  function action_userhello() {
  $this->out->name = $this->get_username(); // функция username унаследована из Application
    if (!$this->is_guest()) {
      $uid = $this->get_uid(); // получаем номер пользователя 
      $sql = "SELECT COUNT(*) FROM ".DB_prefix."post p WHERE p.uid=".intval($uid)." AND p.status=0";  
// выбираем все сообщения, у которых автор — пользователь с указанным uid, и которые не на премодерации/удалении
// $uid — всегда числовое значение, поэтому экранирование можно выполнить и с помощью intval
    $this->out->msg_count = $this->db->select_int($sql); // получаем количество сообщений и сразу же сохраняем его для вывода в msg_count
    }
  }
}

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

Критикуя — предлагай, предлагая — обосновывай!
4xpro.ru — мой личный сайт-мультиблог на Intellect Board.

Одна страница
Распечатать

У вас нет прав для отправки сообщений в эту тему.