Some add-ons warrant having their own controllers, but others provide little snippets of functionality that don't really need to have their own route prefix and controller. For these, it can be useful to add their actions to an existing controller.
For example, you might want to have a new member action that simply displays a member's username and user title, and have it respond to requests for /members/{username}.{user_id}/title. The XenForo code event listener system makes this easy to do, without having to go and edit the existing controller code. Let's see how we can go about adding an additional action to the XenForo_ControllerPublic_Member class to achieve our goal.
We will start by creating our extended controller class. This will act as though it has extended the member controller, inheriting all of XenForo_ControllerPublic_Member's methods and properties. Normally, a class like this would be declared as follows:
But for a dynamic system where there might be dozens of classes attempting to extend the member controller, this is unworkable.
Instead, we must make use of the XenForo Class Proxy system, which allows the system to effectively have multiple inheritance capabilities. To use it, we must declare the class as ClassName, and have it extend XFCP_ClassName, like this:
Don't worry that the declaration does not mention XenForo_ControllerPublic_Member, we'll handle that later.
We now need to define our action and our extended controller is done.
Next, we need to tell XenForo that you intend for Dev_ControllerPublic_Member to extend XenForo_ControllerPublic_Member. In the Development tab of the XenForo Admin Control Panel, create a new Code Event Listener. Tell it to listen to load_class_controller and give it the name of a class and method that you will create next in order to do specify the extension. When you're done, save the event listener.
Finally, we need to create Dev_Listener_LoadClassController::extendMemberController() as specified in the code event listener. This will be a very simple class with a single method that simply sets an entry in an array if the class name passed to it matches the one we want.
With that class and method created, we can now request /title as an action from the members route prefix and have it perform our actionTitle() controller action. Hooray!
It is worth noting that the principles described here can apply to many of XenForo's important classes. You can extend Controller, DataWriter, Model, View, RoutePrefix and several other types of class using the very same methods as were used to add more methods to the controller in this tutorial.
For example, you might want to have a new member action that simply displays a member's username and user title, and have it respond to requests for /members/{username}.{user_id}/title. The XenForo code event listener system makes this easy to do, without having to go and edit the existing controller code. Let's see how we can go about adding an additional action to the XenForo_ControllerPublic_Member class to achieve our goal.
We will start by creating our extended controller class. This will act as though it has extended the member controller, inheriting all of XenForo_ControllerPublic_Member's methods and properties. Normally, a class like this would be declared as follows:
PHP:
class Dev_ControllerPublic_Member extends XenForo_ControllerPublic_Member
Instead, we must make use of the XenForo Class Proxy system, which allows the system to effectively have multiple inheritance capabilities. To use it, we must declare the class as ClassName, and have it extend XFCP_ClassName, like this:
PHP:
class Dev_ControllerPublic_Member extends XFCP_Dev_ControllerPublic_Member
We now need to define our action and our extended controller is done.
PHP:
<?php
class Dev_ControllerPublic_Member extends XFCP_Dev_ControllerPublic_Member
{
public function actionTitle()
{
$userId = $this->_input->filterSingle('user_id', XenForo_Input::UINT);
$user = $this->getHelper('UserProfile')->assertUserProfileValidAndViewable($userId);
return $this->responseView(
'Dev_ViewPublic_Member_Title', 'dev_member_title',
array('user' => $user)
);
}
}
Finally, we need to create Dev_Listener_LoadClassController::extendMemberController() as specified in the code event listener. This will be a very simple class with a single method that simply sets an entry in an array if the class name passed to it matches the one we want.
PHP:
<?php
class Dev_Listener_LoadClassController
{
/**
* Instruct the system that XenForo_ControllerPublic_Member
* should be extended by Dev_ControllerPublic_Member
*
* @param string $class
* @param array $extend
*/
public static function extendMemberController($class, array &$extend)
{
if ($class == 'XenForo_ControllerPublic_Member')
{
$extend[] = 'Dev_ControllerPublic_Member';
}
}
}
It is worth noting that the principles described here can apply to many of XenForo's important classes. You can extend Controller, DataWriter, Model, View, RoutePrefix and several other types of class using the very same methods as were used to add more methods to the controller in this tutorial.