Как конвертировать моды phpBB 3.0 в расширения phpBB 3.1
Это руководство даст общее представление для авторов модов о необходимых шагах для конвертации модов phpBB 3.0 в расширения phpBB 3.1 на примере мода NV Newspage
Структура расширений
Самым очевидным изменением должно быть место хранения модов/расширений в 3.1.
В phpBB 3.0 все файлы помещались в корневой папке конференции. В версии 3.1 создан специальный каталог для расширений
ext/
Каталог
Каждое расширение имеет свой собственный каталог. Однако вы можете (и должны) использовать дополнительный каталог поставщика (с вашим именем автора или названием группы авторов). В случае мода NW newspage файлы будут в каталоге
phpBB/ext/nickvergessen/newspage/
Нет необходимости размещать файлы за пределами этого каталога. Независимо от того, какие это файлы - это могут быть шаблоны, локализация или файлов администраторского раздела. Все они должны быть размещены в папке вашего расширения. Значение остальных каталогов, приведенных на рисунке будет описано ниже.
Фронтэнд, перенаправление и службы
В то время как в версии 3.0 вы только создавали новый файл в корневой директории
phpbb
, то теперь вы можете использовать новую систему контроллеров 3.1. Ваши ссылки изменят вид например с phpbb/newspage.php
на phpbb/app.php?controller=newspage
в обычном виде, но если добавить небольшое правило в .htaccess то ссылка может быть преобразована в phpbb/newspage
Чтобы связать конкретные правила перенаправления на ваше расширение, вам нужно определить перенаправление в ваших расширениях.
config/routing.yml
Для простого запуска newspages достаточно 2-х правил. Первое правило для основной страницы
newspage.php
, второе – для нумерации страниц, например newspage.php?start=5
. Первое правило устанавливает по умолчанию страницу 1, тогда как второе правило требует, чтобы второй аргумент в ссылке был целым числом.
Код: Выделить всё
newspage_base_controller:
pattern: /newspage/
defaults: { _controller: nickvergessen.newspage.controller:base, page: 1 }
newspage_page_controller:
pattern: /newspage/{page}/
defaults: { _controller: nickvergessen.newspage.controller:base }
requirements:
page: \d+
_controller
определяет службу (nickvergessen.newspage.controller
) и метод (base
) класса, который в этом случае вызывается. Службы определяются в вашем расширении в файле config/services.yml
. Службы являются экземплярами классов. Службы вызываются, так что существует только один экземпляр класса, который используется все время. Вы также можете определить аргументы для конструктора вашего класса. Пример определения службы контроллера newspage:
Код: Выделить всё
services:
nickvergessen.newspage.controller:
class: phpbb_ext_nickvergessen_newspage_controller_main
arguments:
- @auth
- @cache
- @config
- @dbal.conn
- @request
- @template
- @user
- @controller.helper
- %core.root_path%
- %core.php_ext%
phpbb/config/services.yml
) могут использоваться в качестве аргумента так же как и некоторые предодопределенные строки (как core.root_path
в примере)ПРИМЕЧАНИЕ: классы из
phpbb/ext/
автоматически загружаются по их именам, при этом знак подчеркивание (_) может обозначать подкаталоги. В этом случае класс phpbb_ext_nickvergessen_newspage_controller_main
будет находиться в файле phpbb/ext/nickvergessen/newspage /controller/main.php
За более подробной информацией о Перенаправлениях и Службах можете обратиться к документации по Symfony 2.1.
В этом примере мой
controller/main.php
должен выглядеть следующим образом:
Код: Выделить всё
<?php
/**
*
* @package NV Newspage Extension
* @copyright (c) 2013 nickvergessen
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
class phpbb_ext_nickvergessen_newspage_controller_main
{
/**
* Constructor
* NOTE: The parameters of this method must match in order and type with
* the dependencies defined in the services.yml file for this service.
*
* @param phpbb_auth $auth Auth object
* @param phpbb_cache_service $cache Cache object
* @param phpbb_config $config Config object
* @param phpbb_db_driver $db Database object
* @param phpbb_request $request Request object
* @param phpbb_template $template Template object
* @param phpbb_user $user User object
* @param phpbb_controller_helper $helper Controller helper object
* @param string $root_path phpBB root path
* @param string $php_ext phpEx
*/
public function __construct(phpbb_auth $auth, phpbb_cache_service $cache, phpbb_config $config, phpbb_db_driver $db, phpbb_request $request, phpbb_template $template, phpbb_user $user, phpbb_controller_helper $helper, $root_path, $php_ext)
{
$this->auth = $auth;
$this->cache = $cache;
$this->config = $config;
$this->db = $db;
$this->request = $request;
$this->template = $template;
$this->user = $user;
$this->helper = $helper;
$this->root_path = $root_path;
$this->php_ext = $php_ext;
if (!class_exists('bbcode'))
{
include($this->root_path . 'includes/bbcode.' . $this->php_ext);
}
if (!function_exists('get_user_rank'))
{
include($this->root_path . 'includes/functions_display.' . $this->php_ext);
}
}
/**
* Base controller to be accessed with the URL /newspage/{page}
* (where {page} is the placeholder for a value)
*
* @param int $page Page number taken from the URL
* @return Symfony\Component\HttpFoundation\Response A Symfony Response object
*/
public function base($page = 1)
{
/*
* Do some magic here,
* load your data and send it to the template.
*/
/*
* The render method takes up to three other arguments
* @param string Name of the template file to display
* Template files are searched for two places:
* - phpBB/styles/<style_name>/template/
* - phpBB/ext/<all_active_extensions>/styles/<style_name>/template/
* @param string Page title
* @param int Status code of the page (200 - OK [ default ], 403 - Unauthorized, 404 - Page not found, etc.)
*/
return $this->helper->render('newspage_body.html');
}
}
Если мы сейчас добавим запись о нашем расширении в таблицу
phpbb_ext
и пройдем по адресу example.tld/app.php?controller=newspage/
, то вы увидите ваш файл шаблона. Поздравляю! Вы только что закончили «Hello World» пример расширения для phpBB 3.1Модули администраторского раздела
Этот раздел также относится к модераторскому и личному разделу (делать по аналогии).
Как упоминалось ранее эти файлы также должны быть размещены в вашем каталоге расширений. Info-файла, в настоящее время находящийся в каталоге
phpbb/includes/acp/info/acp_newspage.php
, теперь будет в каталоге ext/nickvergessen/newspage/acp/main_info.php
и сам модуль перемещается из phpbb/includes/acp/acp_newspage.php
в каталог ext/nickvergessen/newspage/acp/main_module.php
. Для того, чтобы иметь возможность автоматически загружать файлы по именам классов мы должны сделать небольшую корректировку самих классов.Что касается
main_info.php
нужно привести имя класса из acp_newspage_info
к следующему виду phpbb_ext_nickvergessen_newspage_acp_main_info
а также изменить значение "filename" в возвращаемом массиве.
Код: Выделить всё
<?php
/**
*
* @package NV Newspage Extension
* @copyright (c) 2013 nickvergessen
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
class phpbb_ext_nickvergessen_newspage_acp_main_info
{
function module()
{
return array(
'filename' => 'phpbb_ext_nickvergessen_newspage_acp_main_module',
'title' => 'ACP_NEWSPAGE_TITLE',
'version' => '1.0.1',
'modes' => array(
'config_newspage' => array('title' => 'ACP_NEWSPAGE_CONFIG', 'auth' => 'acl_a_board', 'cat' => array('ACP_NEWSPAGE_TITLE')),
),
);
}
}
Код: Выделить всё
<?php
/**
*
* @package NV Newspage Extension
* @copyright (c) 2013 nickvergessen
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
class phpbb_ext_nickvergessen_newspage_acp_main_module
{
var $u_action;
function main($id, $mode)
{
// Your magic stuff here
}
}
Изменение в БД, UMIL заменен на Миграции
Wiki/Migrations
В общем, миграции это аналог UMIL-файлов в phpBB3.0. Они вносят изменения в базу данных от вашего мода / расширения. Самая большая разница между миграциями и UMIL в том, что в то время как у вас один файл с одним массивом в UMIL для всех ваших изменений, у вас будет по одному файлу на каждую версию миграции. Но давайте взглянем на newspage снова.
Код: Выделить всё
$versions = array(
'1.0.0' => array(
'config_add' => array(
array('news_number', 5),
array('news_forums', '0'),
array('news_char_limit', 500),
array('news_user_info', 1),
array('news_post_buttons', 1),
),
'module_add' => array(
array('acp', 'ACP_CAT_DOT_MODS', 'NEWS'),
array('acp', 'NEWS', array(
'module_basename' => 'newspage',
'module_langname' => 'NEWS_CONFIG',
'module_mode' => 'overview',
'module_auth' => 'acl_a_board',
),
),
),
),
'1.0.1' => array(
'config_add' => array(
array('news_pages', 1),
),
),
'1.0.2' => array(),
'1.0.3' => array(
'config_add' => array(
array('news_attach_show', 1),
array('news_cat_show', 1),
array('news_archive_per_year', 1),
),
),
);
Newspage не изменяет структуру БД, поэтому рассмотрим пример из Wiki.
В основном требуется два метода класса в вашем файле миграции:
Код: Выделить всё
public function update_schema()
Код: Выделить всё
public function revert_schema()
Код: Выделить всё
public function update_schema()
{
return array(
'add_columns' => array(
$this->table_prefix . 'groups' => array(
'group_teampage' => array('UINT', 0, 'after' => 'group_legend'),
),
$this->table_prefix . 'profile_fields' => array(
'field_show_on_pm' => array('BOOL', 0),
),
),
'change_columns' => array(
$this->table_prefix . 'groups' => array(
'group_legend' => array('UINT', 0),
),
),
);
}
public function revert_schema()
{
return array(
'drop_columns' => array(
$this->table_prefix . 'groups' => array(
'group_teampage',
),
$this->table_prefix . 'profile_fields' => array(
'field_show_on_pm',
),
),
'change_columns' => array(
$this->table_prefix . 'groups' => array(
'group_legend' => array('BOOL', 0),
),
),
);
}
revert_schema()
должен откатить все изменения, сделанные методом update_schema()
Изменение данных
Изменения данных, как добавление модулей, прав и настроек, обеспечиваются функцией
update_data ()
.Эта функция так же возвращает массив. Например для версии 1.0.0 обновление из newspage выглядит следующим образом:
Код: Выделить всё
public function update_data()
{
return array(
array('config.add', array('news_number', 5)),
array('config.add', array('news_forums', '0')),
array('config.add', array('news_char_limit', 500)),
array('config.add', array('news_user_info', 1)),
array('config.add', array('news_post_buttons', 1)),
array('module.add', array(
'acp',
'ACP_CAT_DOT_MODS',
'ACP_NEWSPAGE_TITLE'
)),
array('module.add', array(
'acp',
'ACP_NEWSPAGE_TITLE',
array(
'module_basename' => 'phpbb_ext_nickvergessen_newspage_acp_main_module',
'modes' => array('config_newspage'),
),
)),
array('config.add', array('newspage_mod_version', '1.0.0')),
);
}
Зависимости и окончание миграции
Ваш файл миграции нуждается еще в двух вещах. Первое, это проверка, которая позволяет phpBB увидеть установлена ли ранее эта миграция, хотя она и не запускалась еще (при обновлении с мода 3.0 в расширение 3.1).
Самый простой способ для проверки может быть версия мода, но когда вы добавляете столбцы в таблицы, вы также можете проверить, существуют ли они:
Код: Выделить всё
public function effectively_installed()
{
return isset($this->config['newspage_mod_version']) && version_compare($this->config['newspage_mod_version'], '1.0.0', '>=');
}
Код: Выделить всё
static public function depends_on()
{
return array('phpbb_db_migration_data_310_dev');
}
Полный файл может выглядеть следующим образом:
Код: Выделить всё
<?php
/**
*
* @package migration
* @copyright (c) 2013 phpBB Group
* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
*
*/
class phpbb_ext_nickvergessen_newspage_migrations_1_0_0 extends phpbb_db_migration
{
public function effectively_installed()
{
return isset($this->config['newspage_mod_version']) && version_compare($this->config['newspage_mod_version'], '1.0.0', '>=');
}
static public function depends_on()
{
return array('phpbb_db_migration_data_310_dev');
}
public function update_data()
{
return array(
array('config.add', array('news_number', 5)),
array('config.add', array('news_forums', '0')),
array('config.add', array('news_char_limit', 500)),
array('config.add', array('news_user_info', 1)),
array('config.add', array('news_post_buttons', 1)),
array('module.add', array(
'acp',
'ACP_CAT_DOT_MODS',
'ACP_NEWSPAGE_TITLE'
)),
array('module.add', array(
'acp',
'ACP_NEWSPAGE_TITLE',
array(
'module_basename' => 'phpbb_ext_nickvergessen_newspage_acp_main_module',
'modes' => array('config_newspage'),
),
)),
array('config.add', array('newspage_mod_version', '1.0.0')),
);
}
}
Т.к. файл локализации в вашем расширении не может быть добавлен функцией
$user->add_lang()
, вы должны использовать метод $user->add_lang_ext()
. Этот метод на вход принимает 2 аргумента: первый – полное имя расширения (включая имя поставщика), второй – имя файла или массив имен файлов. Таким образом для локализации newspages нужно вызвать
Код: Выделить всё
$user->add_lang_ext('nickvergessen/newspage', 'newspage');
phpbb/ext/nickvergessen/newspage/language/en/newspage.php
Редактирование файлов – лучше ничего не редактировать, а использовать События и Диспетчеры
Единственное чего не хватает для завершения установки мода newspage это ссылки в заголовке конференции, чтобы можно было начать просмотр newspage.
Для того, чтобы это сделать, я использовал определение переменной шаблона в
page_header ()
-функции PHPBB, а затем редактировал overall_header.html
. Но это 3.1, поэтому мы не хотели больше редактировать файлы и добавили взамен События. С событиями вы можете подключиться в нескольких местах и выполнить свой код, без редактирования файлов.События phpBB
Таким образом, вместо добавления
Код: Выделить всё
$template->assign_vars(array(
'U_NEWSPAGE' => append_sid($phpbb_root_path . 'app.' . $phpEx, 'controller=newspage/'),
));
page_header()
, мы вставим это в диспетчер событий, который затем вызовет, page_header()
всегда вызывается.Так мы добавляем файл
event/main_listener.php
в наше расширение, который наследует некий класс Symfony:Код: Выделить всё
<?php
/**
*
* @package NV Newspage Extension
* @copyright (c) 2013 nickvergessen
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* Event listener
*/
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class phpbb_ext_nickvergessen_newspage_event_main_listener implements EventSubscriberInterface
{
}
getSubscribedEvents()
мы говорим системе уведомления о каких событиях мы хотим получить и какая функция должна быть исполнена. В нашем случае мы хотим подписаться на событие core.page_header
(полный список событий вы можете найти по ссылке)Код: Выделить всё
static public function getSubscribedEvents()
{
return array(
'core.page_header' => 'add_page_header_link',
);
}
Код: Выделить всё
public function add_page_header_link($event)
{
global $user, $template, $phpbb_root_path, $phpEx;
// I use a second language file here, so I only load the strings global which are required globally.
// This includes the name of the link, aswell as the ACP module names.
$user->add_lang_ext('nickvergessen/newspage', 'newspage_global');
$template->assign_vars(array(
'U_NEWSPAGE' => append_sid($phpbb_root_path . 'app.' . $phpEx, 'controller=newspage/'),
));
}
События шаблонов
Теперь единственное, что осталось, это, добавление кода в HTML. Для шаблонов нужно по одному файлу на события.
В связи с этим имя файла содержит название события. Для того, чтобы добавить ссылку newspage после ссылки FAQ, мы должны использовать
overall_header_navigation_prepend
-событие (полный список событий вы можете найти по ссылке )Таким образом, мы добавим
styles/prosilver/template/events/overall_header_navigation_prepend_listener.html
в каталог расширений и добавить HTML код в него.
Код: Выделить всё
<li class="icon-newspage"><a href="{U_NEWSPAGE}">{L_NEWSPAGE}</a></li>
Добавление событий.
Вы также можете добавлять события в ваши php файлы и шаблоны расширения. Если вам не хватает событий из движка, пожалуйста, создайте тему в форуме [3.x] Event Requests - и мы включим его в следующем выпуске. Мы стараемся включать огромный набор событий по умолчанию, но, конечно, мы не можем охватить все места движка где вашим модам потребуется событие.
Основное завершено!
И это все, Модификация 3.0 была успешно преобразована в расширение 3.1.
Совместимость
По некоторым причинам совместимость функций и классов не может быть сохранена, при одновременном ускорении их работы. Список изменений Вы можете увидеть в вики-статье о PhpBB3.1
Нумерация страниц (пагинация)
Когда вы используете ваш старый код 3.0 вы получите ошибку на подобии следующей
Код: Выделить всё
Fatal error: Call to undefined function generate_pagination() in ...\phpBB3\ext\nickvergessen\newspage\controller\main.php on line 534
Старый код нумерации страниц был похож на:
Код: Выделить всё
$pagination = generate_pagination(append_sid("{$phpbb_root_path}app.$phpEx", 'controller=newspage/'), $total_paginated, $config['news_number'], $start);
$this->template->assign_vars(array(
'PAGINATION' => $pagination,
'PAGE_NUMBER' => on_page($total_paginated, $config['news_number'], $start),
'TOTAL_NEWS' => $this->user->lang('VIEW_TOPIC_POSTS', $total_paginated),
));
Код: Выделить всё
$base_url = append_sid("{$phpbb_root_path}app.$phpEx", 'controller=newspage/');
phpbb_generate_template_pagination($this->template, $base_url, 'pagination', 'start', $total_paginated, $this->config['news_number'], $start);
$this->template->assign_vars(array(
'PAGE_NUMBER' => phpbb_on_page($this->template, $this->user, $base_url, $total_paginated, $this->config['news_number'], $start),
'TOTAL_NEWS' => $this->user->lang('VIEW_TOPIC_POSTS', $total_paginated),
));