Thêm Actions vào một Controller có sẵn trong Xenforo

Tiếng Việt
Một vài add-ons có controllers riêng, nhưng một vài add-ons có những hàm nhỏ (hàm xử lí không quá dài và phức tạp) thì không thực sự cần phải có route prefix và controller riêng. Bài viết này sẽ hướng dẫn thêm các actions vào một Controller có sẵn.

Ví dụ, bạn muốn có 1 action với member (thành viên) chỉ đơn giản là hiển thị username của member  và title user. Và nó phải thỏa mãn yêu cầu :/members/{username}.{user_id}/title. 

Hệ thống code event listener của Xenforo (The XenForo code event listener system) thực hiện điều này 1 cách dễ dàng mà không cần phải chỉnh sửa code của controller sẵn có. Chúng ta sẽ thêm một action bổ sung vào class XenForo_ControllerPublic_Member để làm điều trên.

Ta sẽ tạo ra một class controller mở rộng. Nó sẽ hành động như một controller member đã được mở rộng, thừa kế tất cả phương thức (methods) và thuộc tính (properties) của XenForo_ControllerPublic_Member.
Thông thường, class đó sẽ được khai báo như sau :

class Dev_ControllerPublic_Member extends XenForo_ControllerPublic_Member

Nhưng đối với một hệ thống năng động, nơi có thể có hàng chục class cố gắng để mở rộng controller member, điều này là không khả thi.

Thay vào đó, chúng ta phải sử dụng hệ thống XenForo Class Proxy. Để sử dụng nó, chúng ta phải khai báo các lớp như ClassName, và nó có mở rộng là XFCP_ClassName, như thế này:

class Dev_ControllerPublic_Member extends XFCP_Dev_ControllerPublic_Member

Đừng lo rằng việc khai báo không đề cập đến XenForo_ControllerPublic_Member, chúng tôi sẽ xử lí nó sau.

Bây giờ ta cần phải định nghĩa action, và controller mở rộng của ta được hoàn thành.

<?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)
        );
    }
}

Tiếp theo, chúng ta khai báo cho XenForo rằng bạn muốn Dev_ControllerPublic_Member là một class mở rộng của XenForo_ControllerPublic_Member. Trong tab Development của XenForo Admin Control Panel, ta tạo một Code Event Listener.

Listen to Event chọn load_class_controller và điền tên class (lớp) và phương thức (method) mà bạn sẽ tạo ra tiếp theo để làm rõ phần mở rộng.

Sau đó ấn Save Event Listener. (Xem hình minh họa)

Screen shot 2011-01-27 at 13.57.12Cuối cùng, chúng ta cần tạo Dev_Listener_LoadClassController::extendMemberController() như những gì chúng ta đã tạo ở code event listener.

<?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';
        }
    }
}

Với class (lớp) và metho (phương thức) vừa tạo tạo, chúng ta có thể yêu cầu /title như một action (hành động) từ router prefix members và nó đã thực hiện actionTitle().

Screen shot 2011-01-27 at 14.11.44
Cần lưu ý rằng các nguyên tắc được mô tả ở đây có thể áp dụng cho nhiều lớp quan trọng của XenForo. Bạn có thể mở rộng cho Controller, DataWriter, Model, View, RoutePrefix.

English Version
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 theXenForo_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’smethods and properties. Normally, a class like this would be declared as follows:

class Dev_ControllerPublic_Member extends XenForo_ControllerPublic_Member

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:

class Dev_ControllerPublic_Member extends XFCP_Dev_ControllerPublic_Member

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.

<?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)
        );
    }
}

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 toload_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.

Screen shot 2011-01-27 at 13.57.12
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

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';
        }
    }
}

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!

Screen shot 2011-01-27 at 14.11.44
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.
Nguồn : http://xenforo.com

Leave a Reply

Your email address will not be published. Required fields are marked *