Новости

Краткий обзор архитектуры XenForo

08.10.2010 | FractalizeR

Размеры

Размер основной части кода XenForo 3,24 МБ (3 405 312 байт). Еще 8,31 МБ (8 724 429 байт) занимает Zend Framework, который поставляется вместе с кодом XenForo.

MVC

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

  1. $fc = new XenForo_FrontController(new XenForo_Dependencies_Public());
  2. $fc->run();

Разумеется, в ходу автозагрузчик классов. Система именования классов как в ZF.

Сама MVC пока внутри использует классы Zend, но то, что XenForo_Controller не унаследован от соответствующих классов ZF, говорит о том, что эта часть будет переписана.

Все контроллеры унаследованы примерно одинаково: class XenForo_ControllerPublic_Forum extends XenForo_ControllerPublic_Abstract. После Symfony с ее actions такой подход несколько непривычен, но к нему быстро привыкаешь.

Система роутинга спроектирована расширяемой. Расширение происходит через привязку префиксов URL к классам-обработчикам. SEO из коробки, разумеется. Никаких плагинов не требуется.

Модель контента

Архитектура XenForo закладывалась надолго :) Во всяком случае, в первый раз в форумном движке я встретил более-менее внятную архитектуру контента, слегка напоминающую Drupal ("Everything is a node", помните?). Пока в XenForo типов контента четыре: категория, раздел форума, страница и ссылка (обычный редирект). Каждый тоже называется Node. Причем, каждый экземпляр узла может быть предком/потомком экземпляра другого типа. Пока не знаю, как эта гремучая смесь, например, из страницы и дочернего ей раздела форума, будет отображаться, не пробовал :). Причем, некоторые типы контента можно слегка расширять прямо из коробки. Так, например, для страницы помимо, собственно, ее HTML содержимого можно указать PHP обработчик, который получит из БД дополнительные данные, изменит дизайн страницы, вставит в нее информацию или вообще плюнет в пользователя ошибкой. PHP обработчики везде указываются не кодом на PHP, как этого можно было ожидать, а именами класса и метода. При активации хука класс будет загружен автолоадером (соответственно, должен быть правильно расположен в файловой системе).

Типы контента пока заданы жестко, самому добавить их не получится. Даже их названия в админке почему-то не локализованы.

Использование сторонних библиотек

XenForo использует Sabre и Zend Framework. Причем, наличие в коде мест, подобных

  1. /*require_once('Zend/Loader/Autoloader.php');
  2.  
  3. $autoloader = Zend_Loader_Autoloader::getInstance();
  4. $autoloader->pushAutoloader(array($this, 'autoload'));*/
  5. spl_autoload_register(array($this, 'autoload'));

скорее всего, означает, что от лишних зависимостей на протяжении разработки продолжат избавляться, заменяя их на что-то свое более легковесное и более специализированное.

Из ZF используется совсем немного классов. В их числе Zend_Registry (в качестве реестра для синглтон-подобных объектов вроде экземпляра XenForo_Db), Zend_Config, Zend_Cache (много чего кеширует, в частности используется в базовом классе моделей XenForo_Model), Zend_Service_ReCaptcha, Zend_Http_Client, Zend_Mail, Zend_Validate и некоторые другие.

Для работы с базой данных используется часть бандла Zend_DB (Zend_Db_Adapater_Abstract и Ко), завернутая в классе XenForo_DB, что опять говорит о том, что и эту часть в последствии перепишут.

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

Архитектура аддонов

Для расширения форума предназначено несколько событий, на которые можно повесить обработчики. Обработчики указываются, как уже было сказано, через имя класса и метода, что позволяет использовать акселераторы вроде APC для кеширования аддонов. Список обработчиков вместе с базовой информацией о плагине помещается в *.xml файл. Писать его руками не обязательно. Достаточно активировать отладочный режим на форуме и в админке появятся дополнительные возможности. PHP файлы аддона, разумеется, надо будет сначала распаковать в соответствующую папку. Классы XenForo лежат в /library/XenForo, стало быть ваши будут лежать в /library/VasyaCorp. Меня это порадовало, поскольку довольно часто я занимался поиском остатков плагина в файловой системе при его удалении из vBulletin.

Поскольку практически каждый аддон должен иметь настройки, их можно создавать прямо в админке и экспортировать в *.xml плагина вместе с информацией о хуках. Располагаются они там же, где и настройки самого XenForo. Встраивать их можно в произвольные места раздела общих настроек XenForo. Устроено все примерно также, как это было в vBulletin. Очень удобно и практически нет необходимости писать код для их поддержки.

Меня немного удивило количество хуков. Я полагаю, все помнят оглушительное количество хуков в vBulletin, которое даже в голове нельзя было удержать? В XenForo хуков всего... 17! Такое количество объясняется их назначением. Вот их имена:

  • container_admin_params
  • container_public_params
  • controller_pre_dispatch
  • front_controller_post_view
  • front_controller_pre_dispatch
  • front_controller_pre_route
  • front_controller_pre_view
  • init_dependencies
  • load_class_bb_code
  • load_class_controller
  • load_class_datawriter
  • load_class_model
  • load_class_route_prefix
  • load_class_search_data
  • load_class_view
  • navigation_tabs
  • visitor_setup

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

  1. public static function resolveDynamicClass($class, $type, $fakeBase = false)
  2. {
  3. if (!XenForo_Application::autoload($class))
  4. {
  5.     if ($fakeBase)
  6.     {
  7.         $fakeNeeded = true;
  8.     }
  9.     else
  10.     {
  11.         return false;
  12.     }
  13. }
  14. else
  15. {
  16.     $fakeNeeded = false;
  17. }
  18.  
  19. if (!empty(self::$_classCache[$class]))
  20. {
  21.     return self::$_classCache[$class];
  22. }
  23.  
  24. $createClass = $class;
  25.  
  26. $extend = array();
  27. XenForo_CodeEvent::fire('load_class_' . $type, array($class, &$extend));
  28.  
  29. if ($fakeNeeded)
  30. {
  31.     if (!$extend)
  32.     {
  33.         return false;
  34.     }
  35.  
  36.     eval('class ' . $class . ' extends ' . $fakeBase . ' {}');
  37. }
  38.  
  39. if ($extend)
  40. {
  41.     try
  42.     {
  43.         foreach ($extend AS $dynamicClass)
  44.         {
  45.             // XenForo Class Proxy, in case you're wondering
  46.             $proxyClass = 'XFCP_' . $dynamicClass;
  47.             eval('class ' . $proxyClass . ' extends ' . $createClass . ' {}');
  48.             XenForo_Application::autoload($dynamicClass);
  49.             $createClass = $dynamicClass;
  50.         }
  51.     }
  52.     catch (Exception $e)
  53.     {
  54.         self::$_classCache[$class] = $class;
  55.         throw $e;
  56.     }
  57. }
  58.  
  59. self::$_classCache[$class] = $createClass;
  60. return $createClass;
  61. }

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

В общем, малое число хуков, похоже, вполне себе компенсируется их мощью.

Система шаблонов

Как и во всех современных форумах в XenForo есть КУЧА шаблонов. Синтаксис довольно мощный (см. отрывки внизу), впрочем, этим уже никого не удивишь. Спецтеги пишутся как в PHPTAL ("неймспейсированный" XML/HTML). Один шаблон может содержать несколько файлов. Например, шаблон forum_list содержит forum_list, node_list (он вставляется в forum_list), node_list.css, sidebar.css, sidebar_online_users. CSS в шаблоне подключается через xen:require, что позволяет кешировать все CSS файлы как угодно.

  1. <xen:require css="node_list.css" />
  2.  
  3. <xen:if hascontent="true">
  4.     <fieldset>
  5.         <ol class="nodeList sectionMain" id="forums">
  6.         <xen:contentcheck>
  7.             <xen:foreach loop="$renderedNodes" value="$node">{xen:raw $node}</xen:foreach>
  8.         </xen:contentcheck>
  9.         </ol>
  10.     </fieldset>
  11. </xen:if>
  12. -------------------------------------
  13. <xen:edithint template="node_link.css" />
  14. -------------------------------------
  15. <xen:contentcheck>
  16.     <xen:foreach loop="$onlineUsers.records" value="$user">
  17.         <xen:if is="{$user.is_moderator} OR {$user.is_admin}">
  18.             <li>
  19.                 <xen:avatar user="$user" size="s" img="true" />
  20.                 <a href="{xen:link members, $user}" class="username">{xen:helper richUserName, $user}</a>
  21.                 <div class="muted">{xen:helper userTitle, $user}</div>
  22.             </li>
  23.         </xen:if>
  24.     </xen:foreach>
  25. </xen:contentcheck>

Обратите внимание на использование хелперов в шаблонах. Хелпер, как и в Symfony, это просто метод класса. Например, вот код хелпера helperUserLink:

  1. public static function helperUserLink(array $user)
  2.     {
  3.         return '<a href="'
  4.             . XenForo_Link::buildPublicLink('members', $user)
  5.             . '" class="username">'
  6.             . htmlspecialchars($user['username'])
  7.             . '</a>';
  8.     }

Поисковая машина

Поисковая машина в XenForo реализована в виде отдельного класса (в отличие от ненавидимой мною реализации в vB, в которой, по-моему, сами разработчики давно уже запутались, просто не сознаются в этом), унаследованного от XenForo_Search_SourceHandler_Abstract. В настоящий момент реализация только одна - MySqlFt.php (class XenForo_Search_SourceHandler_MySqlFt extends XenForo_Search_SourceHandler_Abstract), но в ближайшее время должен появиться Sphinx. Мода такая нынче :) Форумы уже не те, что раньше. Растут, как на дрожжах...

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

Система локализации

Система локализации практически полностью повторяет свой аналог из vBulletin с тем исключением, что фразовые группы отсутствуют вообще. Вот начало файла фраз английского языка:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <phrases>
  3.   <phrase title="1_more_message" global_cache="0" version_id="1000017" version_string="1.0.0 Alpha 7"><![CDATA[1 more message]]></phrase>
  4.   <phrase title="about" global_cache="0" version_id="1000015" version_string="1.0.0 Alpha 5"><![CDATA[About]]></phrase>

Каждый аддон может иметь собственные фразы. Языки можно экспортировать. Переводить аддоны можно прямо в админке.

Система стилей

Я не дизайнер и вообще у меня плохой вкус. Все, что касается дизайна и его разработки меня пугает. Но в XenForo мы видим древовидную систему стилей, аналогичную vB, в которой мы можем взять какой-то стиль за основу и изменить часть его настроек или шаблонов. Только Кир с Майком реализовали самый крутой редактор CSS, который мне приходилось вообще доводилось в жизни видеть. Dreamweaver отдыхает :). В XenForo настраивается все и настраивается вполне себе визуально. Забудьте о редактировании CSS напрямую, о листе с двумя тысячами переменных, который какой-то мудак нехороший человек реализовал в vB. Здесь все очень грамотно сгруппировано так, что 99% секций помещаются на одном экране. Если вы не такой лох в плане дизайна, как я и имеете художественный вкус, наверное, вы можете уволить своего дизайнера, поскольку стиль вы сможете сделать и сами (через пару месяцев, как наиграетесь с редактором).

Система аутентификации

У вас есть база данных, скажем, от WordPress? Импортируйте пользователей из WP в базу XenForo с сохранением их паролей! Для того, чтобы потом все заработало, вам придется всего лишь расширить класс XenForo_Authentication_Abstract чтобы подсказать XenForo каким образом проверять пароль. Данные пользователей с вашими системами аутентификации связывает таблица xf_user_authenticate.

Службы связи

Уже достаточно давно на форумах позволяется указывать свои контакты в различных системах коммуникации типа ICQ. В XenForo существует легко расширяемая система контактных служб. Службы можно добавлять в панели управления. Класс поддержки службы выглядит примерно так:

  1. class XenForo_Model_IdentityService_Icq extends XenForo_Model_IdentityService_Abstract
  2. {
  3.     protected function _getIdentityServiceId()
  4.     {
  5.         return 'icq';
  6.     }
  7.  
  8.     static public function verifyAccountName(&$accountName, &$error)
  9.     {
  10.         if (!preg_match('/^\d+$/', $accountName))
  11.         {
  12.             $error = new XenForo_Phrase('please_enter_valid_icq_uin_using_numeric_characters_only');
  13.             return false;
  14.         }
  15.  
  16.         return true;
  17.     }
  18. }

Теперь уже никто не сможет ввести в поле ICQ своего профиля строчку "Продам носки шерстяные" :)

Система прав и привилегий

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

Типов разрешений четыре. Inherit, Allow, Revoke, Deny. Пока мне не удалось понять, чем Revoke отличается от Deny. Причем, Revoke отсутствует в правах группы по умолчанию, что наталкивает на мысль, что этот тип связан с наследованием прав.

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

  1. $users[$userId]['canCleanSpam'] = (XenForo_Permission::hasPermission($visitor['permissions'], 'general', 'cleanSpam') && $this->getModelFromCache('XenForo_Model_User')->couldBeSpammer($users[$userId]));

Общие впечатления

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

Кстати, я очень ждал выхода phpBB 3, хотел им заняться серьезно. Но его архитектура для меня выглядит гораздо менее четкой и логичной, чем архитектура XenForo. Честно признаться, я так и не въехал в phpBB 3. Будем ждать четверку на Symfony2...

Вот, пожалуй, и все. Вопросы по плагинам для XenForo можно задавать тут. А на официальном форуме уже есть несколько (18 на текущий момент), можно скачать и посмотреть. Сам я пока лицензию на движок не покупал, не было повода. Поэтому за предоставленный для изучения код благодарю моих друзей, уже купивших официальную версию.

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

Обсудить статью можно здесь.