How to make a custom module for Humhub (a certain interpretation on the official page) (2)

Sep 5, 2020 PHP yii2 HumHub

#Introduction Last timedescribedhowtomakeacustommoduleforHumhub,aboutthepartthatcanbesaidtobethemoduleformwork,andoneinterpretationabouttheofficialpage.Thistime,myunclewantstotalkabouttheinterpretationofthedescriptionofeventsinthecustommodule.(Unclewantstousethiswordingasahomagewhenheseestheanime"InterviewswithMonsterGirls”).

When using the custom module, there will be a state condition that “I want this module to come out like this during this operation”. If you say that describing this state condition and module activation condition is a description of events, will it be transmitted? Is there an expression to write a callback trigger?

The target of this interpretation is this official page. https://docs.humhub.org/docs/develop/modules-event-handler/

Although there are some overlaps with the previous content, I would like to talk about the mechanism of the menu display of the custom_page module in the latter half while tracing the explanation of the official page for the description of events. Please forgive me for not covering all of the above targets this time. This time, I would like to talk only about the simplest interpretation of “performing a callback in response to an event”.

#Custom module Events settings The Humhub system has a mechanism to fire an event when there is a module. This is in line with the Yii2 framework, and of course custom module developers can also implement firing events in their modules. However, what I want to mention here is a mechanism that starts operation in response to an event that ignites in another module of the system, not on the firing side.

Although it will be a review of the last time, let’s first check the description location of the Events settings. I would like to talk while quoting the description on the official page.

First, arrange the files of your own module. Last time I mentioned that a custom module creates a folder that stores the three files config.php, module.json, and Module.php. This time, it is assumed that the custom module used as a sample has the following file arrangement. Also keep in mind that this time around, the Events.php file is growing.

example example
├── config.php
├── module.json
├── Module.php
└── Events.php

The Humhub event handler is described in the events section of the config.php file. On the official page, the items to be described are explained with the following sample.

// config.php
use my \ example \ Events;
use my \ example \ modules \ Example;

return [
    //...
    'events' => [
        [
            'class' => Example :: class,
            'event' => Example :: EVENT_SOME_EVENT,
            'callback' => [Events :: class,'onSomeEvent']
        ],,
        //...
    ]
]

For the setting items in the events section, Previous commentary (interpretation), I will add an interpretation again.

Key item name Explanation
class Describe the module class name (of the event firing source) with a namespace.
(Previously, “Describe the class name of the class that triggers the event with a namespace”.)
event Event name (of the event firing source module).
(Similarly, “Event name. The event name is managed by the class that issues the event.")
callback Callback function name (of your own custom module). Specify the class that describes the function.
(Similarly, “Enter the description file of the function you want to operate in the callback and the function name in a list.))

Interpreting the sample description, it can be said that this sample custom module is designed with the following behavior in mind.

If the (existing) Example class fires an event called EVENT_SOME_EVENT
  → Of the Events class (defined in the my \ example \ Events namespace) of this custom module
       Execute a function called onSomeEvent

An example of the Events class on the official page is as follows.

// example / Events.php
public static function onSomeEvent ($ event)
{
    $ exampleModel = $ event-> sender;
    //...
}

There is no explanation on the official page, but you can read something important from this sample. In the function to be called back, \ $ event is described as an argument and a \ $ evnet object is received. I don’t know the member variables of this $ event object! Doihi

The Yii2 Event Handler page has the following description. https://www.yiiframework.com/doc/guide/2.0/ja/concept-events#event-handlers

The event handler signature looks like this:

function ($ event) {
    // $ event is an object of yii \ base \ Event or its child class
}
Through the $ event parameter, the event handler can get the following information about the event that occurred:

·event name
-Event source: The object for which the trigger () method was called
· Custom data: The data provided when attaching the event handler
// ···· Continue

Furthermore, the event class explanation of Yii2 is as follows. https://www.yiiframework.com/doc/api/2.0/yii-base-event#$name-detail

A level formula that encourages beginners to try to understand by following crappy links. Kuu … Do you mean that you should understand the Yii2 framework before using it? It’s tight.

From my uncle’s experience, I think that if you hold down the following two things for the time being, you will manage to move on to the next.

Information Property name How to write
Event name name $ event-> name
Event Source sender $ event-> sender

Since the yii \ base \ Event class inherits from yii \ base \ BaseObject, if you are worried, you may want to check the existence of the property with the hasProperty () method and use it. For the time being, if it is a core module of humhub, it seems that it has name and sender properly.

#Practical example of how to write event settings Let’s check the interpretation by referring to some custom modules (open source ones).

(Practical interpretation example Custom_page module (AdminMenu class EVENT_INIT in config.php of Ver. (Ver. 1.0.9))

I would like to reprint the custom_page module config.php and talk about its interpretation.

<? php

use humhub \ modules \ space \ widgets \ Menu;
use humhub \ modules \ user \ widgets \ AccountMenu;
use humhub \ modules \ admin \ widgets \ AdminMenu;
use humhub \ widgets \ BaseMenu;
use humhub \ widgets \ TopMenu;

return [
    'id' =>'custom_pages',
    'class' =>'humhub \ modules \ custom_pages \ Module',
    'modules' => [
        'template' => [
            'class' =>' humhub \ modules \ custom_pages \ modules \ template \ Module'
        ],,
    ],,
    'urlManagerRules' => [
        ['class' =>'humhub \ modules \ custom_pages \ components \ PageUrlRule']
    ],,
    'namespace' =>'humhub \ modules \ custom_pages',
    'events' => [
        ['class' => AdminMenu :: class,'event' => AdminMenu :: EVENT_INIT,'callback' => ['humhub \ modules \ custom_pages \ Events','onAdminMenuInit']],
        ['class' => TopMenu :: class,'event' => TopMenu :: EVENT_INIT,'callback' => ['humhub \ modules \ custom_pages \ Events','onTopMenuInit']],
        ['class' => AccountMenu :: class,'event' => AccountMenu :: EVENT_INIT,'callback' => ['humhub \ modules \ custom_pages \ Events','onAccountMenuInit']],['class' => Menu::class, 'event' => Menu::EVENT_INIT, 'callback' => ['humhub\modules\custom_pages\Events', 'onSpaceMenuInit']],

        ['class' => 'humhub\modules\space\widgets\HeaderControlsMenu', 'event' => BaseMenu::EVENT_INIT, 'callback' => ['humhub\modules\custom_pages\Events', 'onSpaceAdminMenuInit']],
        ['class' => 'humhub\modules\directory\widgets\Menu', 'event' => BaseMenu::EVENT_INIT, 'callback' => ['humhub\modules\custom_pages\Events', 'onDirectoryMenuInit']],

        ['class' => 'humhub\modules\dashboard\widgets\Sidebar', 'event' => BaseMenu::EVENT_INIT, 'callback' => ['humhub\modules\custom_pages\Events', 'onDashboardSidebarInit']],
        ['class' => 'humhub\modules\directory\widgets\Sidebar', 'event' => BaseMenu::EVENT_INIT, 'callback' => ['humhub\modules\custom_pages\Events', 'onDirectorySidebarInit']],
        ['class' => 'humhub\modules\space\widgets\Sidebar', 'event' => BaseMenu::EVENT_INIT, 'callback' => ['humhub\modules\custom_pages\Events', 'onSpaceSidebarInit']],
    ],
];
?>

初めのuse節で、spaceモジュールのMenuウィジェット、userモジュールのAccountMenuウィジェット、adminモジュールのAdminMenuウィジェットの参照と、BaseMenuウィジェット、TopMenuウィジェットの参照を行なっている。returnする配列として、id, classなどの記述を行うことについては前回述べた。今回のテーマに従い、evnetsセクションに注目する。

eventsセクションの冒頭を抜粋し、改行で区切って表してみた。

'events' => [
    [
        'class' => AdminMenu::class,
        'event' => AdminMenu::EVENT_INIT,
        'callback' => [
            'humhub\modules\custom_pages\Events',
            'onAdminMenuInit'
        ]
    ],
// ・・・ 続く

まず、イベントはArrayにして複数記述することが可能であることがわかる。最初の要素は、イベント発火元クラスをAdminMenu::classと指定し、eventをEVENT_INITと指定している。・・・はい、初心者のみなさん、これってhumhubのどういうイベント状況を指しているかわかりますか?おじさんももちろん、わかりませんでした。公式のドキュメントにも「もちろん」そのままズバリの記述はありません。

とりあえず、コードを追ってみよう。

use節の解釈から、AdminMenuクラスは、「humhub\modules\admin\widgets\AdminMenu」の記述を参照することになる。このクラスには init()ファンクションが公開(public属性)されている。

さて、ここで公式ページの次の部分に着目。 https://docs.humhub.org/docs/develop/modules-event-handler#widget-events

なぜこの部分に着目するかというと、「humhub\modules\admin\widgets」にあるクラスを参照することになった現状において情報を分析するに、前回のモジュールの書き方の最後に言及したモジュールのファイル構成から読み取ると、widgetsフォルダに入っているこのクラスは、「Widgets class」のものであろうと推察されるからだ。この推察から、AdminMenuクラスは、widgetsクラスを継承しているだろう、と、ひとまずは予想する。

より厳密にコードを追うと、 class AdminMenu は、extends LeftNavigation と宣言されており、LeftNavigationクラスは、\humhub\modules\ui\menu\widgets\Menuクラスの extends であり、 \humhub\modules\ui\menu\widgets\Menu クラスは、 JsWidget クラスの extends であって、JsWidget(\humhub\widgets\JsWidget)は、Widgetクラス(\humhub\components\Widget)の extends と宣言されています。\humhub\components\Widget は、 \yii\base\Widgetの extends なので、これで、AdminMenu が Widgetクラスを継承していることが確かめられた。

先ほどのwidget-eventsに関する公式ページに着目、widget-eventsが表にまとめられているので和訳解釈してみる。

イベント クラス 解説
Widget::EVENT_INIT yii\base\Event init()によって初期化されたときに発火する
Widget::EVENT_BEFORE_RUN yii\base\WidgetEvent Widgetが実行される直前に発火する
Widget::EVENT_AFTER_RUN yii\base\WidgetEvent Widgetが実行された直後に発火する
humhub\components\Widget::EVENT_CREATE humhub\libs\WidgetCreateEvent Yii::createObject()の前に発火する

さてさて、EVENT_INIT は、init()によって初期化されたときに発火することがわかった。だが、それってhumhubの画面のどこで何をして初期化が呼ばれてるのだろうか?はい、おじさん、またこれもわかりませんでした。これ、どうやって調べたと思います?試行錯誤して実際の動作をみながら推察確認ですよ。時間がかかってしょうがない・・・。

ヒントはある。先ほど、コードを追った中で、LeftNavigationをextendsしていた。また、名前がAdminMenuだ。管理メニューっぽくて左メニューに表示されるAdminMenuを探してみた。・・・ありました。 screenshot2020-09-05 22.06.12.png

AdminMenuクラスは、このメニューを表示しているものと推察される。このメニューが初期化される時、すなわち管理者メニューが表示されようとするその時にcallbackファンクションを呼びたい、というのが、このイベントの記述の意図のようだ。

では、このイベントで発生させようとしているcallbackファンクションを見てみよう。callbackファンクションのクラスは、humhub\modules\custom_pages\Eventsを指定している。そのクラスには、次のような記述がなされている。

<?php

namespace humhub\modules\custom_pages;

use humhub\modules\custom_pages\models\TemplateType;
use Yii;
use yii\helpers\Html;
use humhub\modules\custom_pages\helpers\Url;

// ・・・ (中略) ・・・ //

/**
 * CustomPagesEvents
 *
 * @author luke
 */
class Events
{

 public static function onAdminMenuInit($event)
 {
    try {
        Yii::$app->moduleManager->getModule('custom_pages')->checkOldGlobalContent();

        if (!Yii::$app->user->isAdmin()) {
            return;
        }

        $event->sender->addItem([
            'label' => Yii::t('CustomPagesModule.base', 'Custom Pages'),
            'url' => Url::toPageOverview(),
            'group' => 'manage',
            'icon' => '<i class="fa fa-file-text-o"></i>',
            'isActive' => (Yii::$app->controller->module
                && Yii::$app->controller->module->id === 'custom_pages'
                && (Yii::$app->controller->id === 'page' || Yii::$app->controller->id === 'config')),'sortOrder' => 300,
        ]);
    } catch (\ Throwable $ e) {
        Yii :: error ($ e);
    }
  }
// ・ ・ ・ (Hereafter, omitted)

The onAdminMenuInint (\ $ evnet) function is described. As mentioned in the previous explanation, $ event is used as an argument. There seems to be something you want to display in the menu by calling $ event-> sender, that is, the AdminMenu class, and then-> addItem ().

As a test, let’s actually enable the custom_page module on the humhub system and take a look at the Admin Menu. screenshot2020-09-05 22.21.02.png

After the custom_page module is enabled, you can see that the Admin Menu has more “Custom Pages” menus. The custom_page module’s config.php was interpreted, the Events function was executed, and the menu was displayed.

Please understand that the custom module is inserted according to the event occurrence scene in the above condition. When the TopMenu is initialized, when the account menu is initialized, when the (space) menu is initialized, and so on. If you can get an image that when you create a custom module, you should search for the target widget you want to generate, the target widget you want to add a display to, and STRUCT, it can be said that what I wanted to say was generally conveyed. ..


#Event description So, when you actually create a custom module, what do you do with the event description once you decide where you want it to occur? The best way to do this is to refer to the existing module that is displaying at that time, look at config.php, and copy it. When transcribing, it can be said that it is necessary to consider what kind of event is picked up by the referenced module as in the above interpretation example.

I’m sorry, but this time, I was exhausted just by explaining EVENT_INIT in AdminMenu of custom_module.

The official does not provide a list of what kind of event is occurring on which screen and what name is occurring in which module. It seems that module developers can make it to their satisfaction by self-help, or that they do not have the capacity to explain it to that extent. There is no choice but to gain experience and get used to it. It’s a penance for a terrible uncle who forgets things, but I interpret that he can manage to start from there with the intuition that “By the way, that module is displayed in such a scene.”


I have described one interpretation of the basic information on making humhub custom modules and the official page information. It’s just an interpretation information, so I think it was only known information to those who are used to it, but I hope that it will be recorded as a memorandum of my own and will be a reference for those who are going to step into making humhub custom modules. I believe.

I cannot thank those who read it. You may have noticed that it is not recommended for people who just want to touch humhub for a while, and that even if they learn more deeply, it cannot be diverted (it does not work). If there are many users like Wordpress, there will be many correspondence projects that make use of the acquired technology, but humhub development projects are not so popular (at least around me). Development of a custom module on humhub requires more time and effort than Wordpress, etc., and it can be said that the development cost is high because there are few application scenes. With that in mind, I hope that the information about the description and interpretation of humhub’s custom modules, such as this time and last time, will be useful to my colleagues who are struggling with humhub development.

From the next time onward, I would like to continue to provide information that can be used as a reference for how to create custom modules. For example, I am considering delving into the description example of Widget.