Good day.
In this article I will try to briefly describe the architecture of the new XenForo forum engine, the new competitor VBulletin and IPB, as far as I can after a couple of hours of acquaintance with the source. About XenForo, designed by former authors of VBulletin3, Cyrus and Mike, I already
wrote a little .

')
Dimensions
The size of the main part of the code XenForo 3.24 MB (3 405 312 bytes). Another 8.31 MB (8,724,429 bytes) is occupied by the Zend Framework, which comes with the XenForo code.
MVC
XenForo is completely based on MVC architecture. There are separate classes for models, types and controllers. The root index.php has a size of 467 bytes and ends, as it should be in such cases
$fc = new XenForo_FrontController(new XenForo_Dependencies_Public()); $fc->run();
Of course, in the course of the autoloader classes. Class naming system as in ZF.
MVC itself is still using the Zend classes internally, but the fact that XenForo_Controller is not inherited from the corresponding ZF classes suggests that this part will be rewritten.
All controllers are inherited in about the same way: class XenForo_ControllerPublic_Forum extends XenForo_ControllerPublic_Abstract. After symfony with its actions, this approach is somewhat unusual, but you quickly get used to it.
The routing system is designed extensible. Expansion occurs by binding URL prefixes to handler classes. SEO out of the box, of course. No plugins required.
Content model
The XenForo architecture was built for a long time :) In any case, for the first time in the forum engine I met a more or less intelligible content architecture, slightly reminiscent of Drupal (“Everything is a node”, remember?). While in XenForo there are four types of content: category, forum section, page and link (normal redirect). Everyone is also called Node. Moreover, each instance of a node can be an ancestor / descendant of an instance of another type. I do not know yet how this explosive mixture, for example, from the page and its affiliate section of the forum, will be displayed, did not try :). Moreover, some types of content can be slightly expanded right out of the box. For example, for a page besides, in fact, its HTML content, you can specify a PHP handler, which will receive additional data from the database, change the page design, insert information into it, or spit out an error to the user. PHP handlers are indicated everywhere not by PHP code, as might be expected, but by class and method names. When the hook is activated, the class will be loaded by the autoloader (accordingly, it must be correctly located in the file system).
Content types are hard-coded for now, you won't be able to add them yourself. For some reason, even their names are not localized in the admin panel.
Using third-party libraries
XenForo uses
Saber and Zend Framework. Moreover, the presence in the code of places like
............ spl_autoload_register(array($this, 'autoload'));
Most likely, it means that they will continue to get rid of unnecessary dependencies throughout development, replacing them with something more lightweight and more specialized.
From ZF very few classes are used. Among them, Zend_Registry (as a registry for singleton-like objects like XenForo_Db instance), Zend_Config, Zend_Cache (caches a lot of things, in particular, in the base class of models XenForo_Model).
To work with the database, the Zend_DB bundle part (Zend_Db_Adapater_Abstract and Co.) is used, wrapped in the XenForo_DB class, which again indicates that this part will be later rewritten.
The query designer is not used, they are built right into the code, as usual (which, of course, makes it difficult to support several databases. But on the other hand, queries are concentrated within the model, so ...)
Addons architecture
For the expansion of the forum there are several events where handlers can be hung. Handlers are specified, as already mentioned, through the name of the class and method, which allows the use of accelerators like APC for add-on caching. A list of handlers along with basic information about the plugin is placed in a * .xml file. Writing it with your hands is not necessary. It is enough to activate the debug mode on the forum and additional features will appear in the admin area. PHP add-on files, of course, will first need to be unpacked into the appropriate folder. The XenForo classes are in / library / XenForo, so yours will be in / library / VasyaCorp. I was pleased, because quite often I searched for remnants of a plugin in the file system when it was deleted from VBulletin.
Since virtually every addon must have settings, you can create them directly in the admin panel and export them to the * .xml plugin, along with information about hooks. They are located in the same place where the settings of the XenForo itself. You can embed them in arbitrary places in the general XenForo settings section. Arranged everything about as well as it was in VBulletin. Very convenient and virtually no need to write code to support them.
I was a little surprised by the number of hooks. I suppose everyone remembers the deafening number of hooks in VBulletin, which even in the head could not be kept? In XenForo, only 17 hooks! This number is due to their purpose. Here are their names:
- 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
A small code inspection showed that the load_class_ * family of hooks is intended to dynamically extend the XenForo class system. Here is the key piece of code:
public static function resolveDynamicClass($class, $type, $fakeBase = false) { if (!XenForo_Application::autoload($class)) { if ($fakeBase) { $fakeNeeded = true; } else { return false; } } else { $fakeNeeded = false; } if (!empty(self::$_classCache[$class])) { return self::$_classCache[$class]; } $createClass = $class; $extend = array(); XenForo_CodeEvent::fire('load_class_' . $type, array($class, &$extend)); if ($fakeNeeded) { if (!$extend) { return false; } eval('class ' . $class . ' extends ' . $fakeBase . ' {}'); } if ($extend) { try { foreach ($extend AS $dynamicClass) {
A somewhat unexpected use of the visitor_setup hook to change everything on the page is shown
here . Practically through any hook you can climb into the heart of the system
and make a deal .
In general, a small number of hooks seem to be quite compensated by their power.
Template System
As with all modern forums in XenForo there are a bunch of patterns. The syntax is quite powerful (see the passages below), however, this will not surprise anyone. Spetstagi written as in PHPTAL ("neympasirovannyy" XML / HTML). One template can contain multiple files. For example, the template forum_list contains forum_list, node_list (it is inserted into forum_list), node_list.css, sidebar.css, sidebar_online_users. CSS in the template is connected via xen: require, which allows you to cache all CSS files as you like.
<xen:require css="node_list.css" /> <xen:if hascontent="true"> <fieldset> <ol class="nodeList sectionMain" id="forums"> <xen:contentcheck> <xen:foreach loop="$renderedNodes" value="$node">{xen:raw $node}</xen:foreach> </xen:contentcheck> </ol> </fieldset> </xen:if> ------------------------------------- <xen:edithint template="node_link.css" /> ------------------------------------- <xen:contentcheck> <xen:foreach loop="$onlineUsers.records" value="$user"> <xen:if is="{$user.is_moderator} OR {$user.is_admin}"> <li> <xen:avatar user="$user" size="s" img="true" /> <a href="{xen:link members, $user}" class="username">{xen:helper richUserName, $user}</a> <div class="muted">{xen:helper userTitle, $user}</div> </li> </xen:if> </xen:foreach> </xen:contentcheck>
Note the use of helpers in the templates. A helper, as in symfony, is just a class method. For example, here's helperUserLink helper code:
public static function helperUserLink(array $user) { return '<a href="' . XenForo_Link::buildPublicLink('members', $user) . '" class="username">' . htmlspecialchars($user['username']) . '</a>'; }
Search engine
The search engine in XenForo is implemented as a separate class (as opposed to the implementation I hate in VB, in which, in my opinion, the developers themselves have long been confused, they simply do not recognize it) inherited from XenForo_Search_SourceHandler_Abstract. Currently, there is only one implementation - MySqlFt.php (class XenForo_Search_SourceHandler_MySqlFt extends XenForo_Search_SourceHandler_Abstract), but Sphinx should appear in the near future. Fashion is now :) Forums are not the same as before. Growing like yeast ...
In the admin there is no option to activate another search engine, but do not forget that it is still Beta.
Localization system
The localization system almost completely repeats its counterpart from VBulletin with the exception that there are no phrase groups at all. Here is the beginning of the English phrase file:
<?xml version="1.0" encoding="utf-8"?> <phrases> <phrase title="1_more_message" global_cache="0" version_id="1000017" version_string="1.0.0 Alpha 7"><![CDATA[1 more message]]></phrase> <phrase title="about" global_cache="0" version_id="1000015" version_string="1.0.0 Alpha 5"><![CDATA[About]]></phrase>
Each addon can have its own phrases. Languages ​​can be exported. Addons can be translated directly in the admin panel.
By the way, the Russian localization of XenForo
is almost ready .
Style system
I'm not a designer, and generally I have a bad taste. Everything related to design and its development scares me. But in XenForo we see a tree-like style system, similar to VB, in which we can take some style as a basis and change some of its settings or patterns. Only Cyrus and Mike implemented the coolest CSS editor that I had ever seen in my life. Dreamweaver is resting :). In XenForo, everything is configured and configured quite visually. Forget about editing CSS directly, about a sheet with two thousand variables that some bad guy implemented a bad guy in VB. Here everything is very well grouped so that 99% of the sections fit on one screen. If you are not as fuzzy in terms of design as I have artistic taste, you can probably dismiss your designer, since you can make the style yourself (in a couple of months, as you play around with the editor).
Authentication system
Do you have a database, say from WordPress? Import users from WP into the XenForo database and save their passwords! In order for it to work, you just have to expand the XenForo_Authentication_Abstract class to tell XenForo how to verify the password. User data with your authentication systems is linked to the xf_user_authenticate table.
Communication services
Already for a long time on the forums allowed to indicate your contacts in various communication systems such as ICQ. XenForo has an easily expandable contact service system. Services can be added to the control panel. The service support class looks like this:
<?php class XenForo_Model_IdentityService_Icq extends XenForo_Model_IdentityService_Abstract { protected function _getIdentityServiceId() { return 'icq'; } static public function verifyAccountName(&$accountName, &$error) { if (!preg_match('/^\d+$/', $accountName)) { $error = new XenForo_Phrase('please_enter_valid_icq_uin_using_numeric_characters_only'); return false; } return true; } }
Now no one will be able to enter the line “Selling wool socks” in the ICQ field of your profile :)
The system of rights and privileges
Each user group of the system has permissions by default. Plus, the rights of each group can be further configured in any type of node. Of course, privileges are inherited.
There are four types of permissions. Inherit, Allow, Revoke, Deny. So far I have not managed to understand how Revoke differs from Deny. Moreover, Revoke is absent in the rights of the group by default, which suggests that this type is associated with the inheritance of rights.
After switching the forum to debug mode, you can add new types of privileges to the system (add-ons can also add them). In the code, they are checked like this:
$users[$userId]['canCleanSpam'] = (XenForo_Permission::hasPermission($visitor['permissions'], 'general', 'cleanSpam') && $this->getModelFromCache('XenForo_Model_User')->couldBeSpammer($users[$userId]));
General impressions
In general, the XenForo code made a good impression on me. It is beautiful, clear, harmonious, full of comments and PLO. At first, looking at the number of classes, I was going to get scared and postpone the article until better times, but now, getting to the end, I can say that already almost everything is OK, I moved a little, how it all worked. I hope you have a little too.
By the way, I was really looking forward to the release of PHPBB3, I wanted to take them seriously. But its architecture for me looks much less clear and logical than the XenForo architecture. Honestly, I never entered PHPBB3. Let's wait for the four on Symfony2 ...
Here, perhaps, that's all. Questions on plugins for XenForo can be asked
here . And on the
official forum there are already a few (18 at the moment), you can download and watch. I myself have not bought a license for the engine, there was no reason. Therefore, for the code provided for study, I thank my friends who have already bought the official version.
I apologize if this article seems to someone to be incomplete or incorrectly constructed. This is my first review of the architecture of something, so I’m happy to accept any criticism in the comments. Part of the criticism, I suppose, I will immediately see on my karma and rating :) If you are still interested in knowing something, let us know in the comments, if I can figure it out quickly - I’ll add an article.