Event Handler

One commonly used technique for manipulating existing processes or adding features in a custom module is the implementation of event handlers.

The most common core events used to manipulate existing features are described in the following guide.

info

Please refer to the Yii Events Guide for general information about the usage of events. Also check the Events Concept section for information about implementing own events.

Event handler configuration

Event handlers in HumHub modules are registered within the events section of the config.php file. It is recommended to implement the handler functions within a dedicated Events.php file in the module root. Some modules may use the Module.php class for event handler implementations, this should only be considered for simple and few event handlers in order to keep a clean module structure.

Example handler configuration

// config.php
use my\example\Events;
use my\example\modles\Example;
return [
//...
'events' => [
[
'class' => Example::class,
'event' => Example::EVENT_SOME_EVENT,
'callback' => [Event::class, 'onSomeEvent']
],
//...
]
]
KeyDescription
classThe namespaced class string of the class responsible for triggering the event.
eventThe event name, usually available as class const
callbackEvent handler callback class and function name
caution

When listening to a non core class event, use an actual string definition instead of an import with usage of ::class to prevent errors when the required module is not enabled.

Example handler implementation

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

Event classes

Depending on the triggered event, there are different types of events provided as event handler argument. Some of the most common event classes are listed in the following table.

KeyDescription
yii\base\EventBase event class of Yii
yii\base\ModelEventSupports additional $isValid flag
yii\db\AfterSaveEventEvent used for some ActiveRecord Events
yii\base\ActionEventController/Action related events
yii\base\WidgetEventWidget related events
yii\web\UserEventUser identity related events
humhub\components\EventHumHub base event with additional $result property
humhub\modules\user\events\UserEventUsed for user related events with additional $user property
humhub\modules\user\events\FollowEventEvents related to user following
humhub\modules\friendship\FriendshipEventEvents related to user friendship
humhub\modules\space\MemberEventEvents related to space memberships
humhub\components\ModuleEventModule related event with getModule() function
humhub\events\ActiveQueryEventActiveQuery related events with additional $query property
customCustom modules may implement own event types

Application Events

Application events can be used to globally intercept requests and actions.

yii\base\Application provides the following events:

EventClassDescription
Application::EVENT_BEFORE_ACTIONyii\base\ActionEventRaised before executing a controller action
Application::EVENT_AFTER_ACTIONyii\base\ActionEventRaised after executing a controller action
Application::EVENT_BEFORE_REQUEST yii\base\EventRaised before the application starts to handle a request
Application::EVENT_AFTER_REQUEST yii\base\EventRaised after the application successfully handles a request (before the response is sent out)

humhub\components\console\Application additionally triggers the following event

EventClassDescription
Application::EVENT_ON_INITyii\base\ActionEventRaised at the end of init()

Module Events

ModuleManager

humhub\components\ModuleManager events can be used to listen for enable and disable events of modules. This can be useful in order to listen and react to lifecycle events of dependent modules.

EventClassDescription
ModuleManager::EVENT_BEFORE_MODULE_ENABLEDhumhub\components\ModuleEventRaised before a module is enabled
ModuleManager::EVENT_AFTER_MODULE_ENABLEDhumhub\components\ModuleEventRaised after a module is enabled
ModuleManager::EVENT_BEFORE_MODULE_DISABLEDhumhub\components\ModuleEventRaised before a module is disabled
ModuleManager::EVENT_AFTER_MODULE_DISABLEDhumhub\components\ModuleEventRaised after a module is disabled

The humhub\components\ModuleEvent class provides the following additional properties and functions:

  • $moduleId: The moduleId of the module -getModule(): Can be used to return a module instance

In the following example we use the ModuleManager::EVENT_AFTER_MODULE_ENABLED to set a module setting of another module right after the module is enabled.

// config.php
use humhub\components\ModuleManager;
return [
//..
'events' => [
[
'class' => ModuleManager::class,
'event' => ModuleManager::EVENT_AFTER_MODULE_ENABLED,
'callback' => [Event::class, 'onAfterModuleEnabled']
]
]
]
// Event.php
public static function onAfterModuleEnabled(ModuleEvent $event)
{
if($event->moduleId === 'specialModle') {
$event->getModule()->settings->set('someSetting', 'someSpecificValue');
}
}

OnlineModuleManager

humhub\modules\marketplace\components\OnlineModuleManager provides events triggered before and after a module was updated by the marketplace.

EventClassDescription
OnlineModuleManager::EVENT_BEFORE_UPDATEhumhub\components\ModuleEventRaised before a module is updated
OnlineModuleManager::EVENT_AFTER_UPDATEhumhub\components\ModuleEventRaised after a module is updated

Controller Events

Controller events can be used to intercept requests of web or console controller actions and manipulate the controller result.

EventClassDescription
Controller::EVENT_AFTER_ACTIONyii\base\ActionEventRaised right after executing a controller action
Controller::EVENT_BEFORE_ACTIONyii\base\ActionEventRaised right before executing a controller action

In the following example we listen to all web controller requests and redirect to a custom action in case some special condition is not met.

// config.php
use my\example\Events;
use humhub\components\Controller;
return [
//...
'events' => [
['class' => Controller::class, 'event' => Controller::EVENT_BEFORE_ACTION, 'callback' => [Events::class, 'onBeforeControllerAction']]
]
]
// Event.php
public static function onBeforeControllerAction(ActionEvent $event)
{
if(!static::checkSomeSpecialCondition($event)) {
// Do not continue running the action.
$event->isValid = false;
// Manipulate action result
$event->result = Yii::$app->response->redirect(['/example/special-condition/index']);
}
}
info

See Yii Controller Events for more information about the usage of Controller events.

CronController Events

Events of the humhub\commands\CronController can be handled in order to implement scheduled tasks.

EventClassDescription
CronController::EVENT_ON_HOURLY_RUNyii\base\EventRaised hourly
CronController::EVENT_ON_DAILY_RUNyii\base\EventRaised daily
info

Use the CronController::EVENT_BEFORE_ACTION in case you want to implement a custom scheduling interval.

Response Events

Response events can be used to manipulate the server response.

EventClassDescription
Response::EVENT_AFTER_PREPAREyii\base\EventRaised right after prepare() is called in send()
Response::EVENT_AFTER_SENDyii\base\EventRaised at the end of send()
Response::EVENT_BEFORE_SENDyii\base\Eventat the beginning of send()

::info See Yii Response Events for more information. :::

Model validation

The base Model class supports events useful to intercepting the validation of a model.

EventClassDescription
Model::EVENT_BEFORE_VALIDATEyii\base\EventRaised at the beginning of validate()
Model::EVENT_AFTER_VALIDATEyii\base\ModelEventRaised at the end of validate()

In the following example we implement a handler for the EVENT_BEFORE_VALIDATE of the humhub\modules\user\models\Invite model in order to intercept the registration process.

// config.php
use humhub\modules\user\models\Invite;
return [
//..
'events' => [
[
'class' => Invite::class,
'event' => Invite::EVENT_BEFORE_VALIDATE,
'callback' => [Event::class, 'onInviteBeforeValidate']
]
]
]
// Event.php
public static function onInviteBeforeValidate($event)
{
$registrationForm = $event->sender;
$user = $registrationForm->models['User'];
if (self::autoEnable($user->email) {
$user->status = User::STATUS_ENABLED;
$registrationForm->enableUserApproval = false;
} else if (!self::isAllowed($user->email)) {
$user->status = User::STATUS_DISABLED;
$user->addError('email', Yii::t('EnterpriseModule.emailwhitelist', 'The given email address is not allowed for registration!'));
}
}

ActiveRecord (CRUD) Events

The ActiveRecord class supports additional events for intercepting CRUD related events. Those events are useful for manipulating model properties or synchronizing the creation/deletion of custom models with models of other modules.

EventClassDescription
ActiveRecord::EVENT_AFTER_DELETEyii\base\EventRaised after a record is deleted
ActiveRecord::EVENT_AFTER_FINDyii\base\ModelEventRaised after the record is created and populated with query result
ActiveRecord::EVENT_AFTER_INSERTyii\db\AfterSaveEventRaised after a record is inserted
ActiveRecord::EVENT_AFTER_REFRESHyii\base\EventRaised after a record is refreshed
ActiveRecord::EVENT_AFTER_UPDATEyii\db\AfterSaveEventRaised after a record is updated
ActiveRecord::EVENT_BEFORE_INSERTyii\base\ModelEventRaised before inserting a record
ActiveRecord::EVENT_BEFORE_UPDATEyii\base\ModelEventRaised before updating a record
ActiveRecord::EVENT_INITyii\base\EventRaised when the record is initialized via init()

Example use cases:

  • Listen for EVENT_AFTER_INSERT and EVENT_BEFORE_DELETE events of a specific record type in order to synchronize the creation or deletion of custom model relations
  • Listen for EVENT_BEFORE_SAVE to manipulate the properties of a model prior to persisting it to the database
  • Listen for EVENT_AFTER_FIND to manipulate model properties right after model queries.
info

See Yii ActiveRecord Events for more information about the usage of ActiveRecord events.

User Events

User Model

The humhub\modules\user\model\User model provides the following additional events:

EventClassDescription
User::EVENT_CHECK_VISIBILITYhumhub\modules\user\events\UserEventCan be used to add conditions to User::isVisible()
User::EVENT_BEFORE_SOFT_DELETEhumhub\modules\user\events\UserEventRaised after a soft deletion of a user model

The following example adds an user visibility condition:

// config.php
use my\example\Events;
use humhub\modules\user\model\Use;
return [
//...
'events' => [
[
'class' => Use::class,
'event' => Use::EVENT_CHECK_VISIBILITY,
'callback' => [Events::class, 'onUserIsVisible']
]
]
]
// Event.php
public static function onUserIsVisible(UserEvent $event)
{
if($event->user->username === 'secretUser') {
$event->result['isVisible'] = false;
}
}

ActiveQueryUser Events

The humhub\modules\user\components\ActiveQueryUser events may be used to add conditions ActiveQueryUser::visible() (in addition to Use::EVENT_CHECK_VISIBILITY) and ActiveQueryUser::active(). This will manipulate the results of queries like:

User::find()->active()->visible()->all();
EventClassDescription
ActiveQueryUser::EVENT_CHECK_VISIBILITYhumhub\events\ActiveQueryEventRaised within visible() user query
ActiveQueryUser::EVENT_CHECK_ACTIVEhumhub\events\ActiveQueryEventRaised within active() user query

In the following example we add an additional check to ActiveQueryUser::visible() by checking a custom user table field. In this example the user.is_visible_in_crm was added to the user table by our custom module.

// config.php
use my\example\Events;
use humhub\modules\user\components\ActiveQueryUser;
return [
//...
'events' => [
[
'class' => ActiveQueryUser::class,
'event' => ActiveQueryUser::EVENT_CHECK_VISIBILITY,
'callback' => [Events::class, 'onUserQueryVisible']
]
]
]
// Event.php
public static function onUserQueryVisible(ActiveQueryEvent $event)
{
$event->query->andWhere(['user.is_visible_in_crm' => 1]);
}

Registration Events

The humhub\modules\user\models\forms\Registration class provides events raised within the registration process:

EventClassDescription
Registration::EVENT_AFTER_REGISTRATIONyii\web\UserEventRaised after successful registration

The following example shows how to synchronize the registration process with an external crm service.

// config.php
use my\example\Events;
use humhub\modules\user\models\forms\Registration;
return [
//...
'events' => [
[
'class' => Registration::class,
'event' => Registration::EVENT_AFTER_REGISTRATION,
'callback' => [Events::class, 'onUserRegistration']
]
]
]
// Event.php
public static function onUserRegistration(UserEvent $event)
{
try {
$service = new CrmService();
$result = $service->createOrUpdateSubscriber($evt->identity);
// Check for errors or log result etc...
static::handleCrmServiceResult($result);
} catch(\Exception $e) {
Yii::error($e);
}
}

User Follow Events

User follow events are triggered once a user follows or unfollows a content, space or another user by the humhub\modules\user\models\Follow class.

EventClassDescription
Follow::EVENT_FOLLOWING_CREATEDhumhub\modules\user\events\FollowEventRaised when a user follows a content/space/user
Follow::EVENT_FOLLOWING_REMOVEDhumhub\modules\user\events\FollowEventRaised when a user unfollows a content/space/user

The following example sends out a custom FollowAchievementNotification notification once the user reaches a certain amount of followers. The notification is removed in case the follower decreases to lower thant 5.

// config.php
use my\example\Events;
use humhub\modules\user\models\Follow;
return [
//...
'events' => [
[
'class' => Follow::class,
'event' => Follow::EVENT_FOLLOWING_CREATED,
'callback' => [Events::class, 'onUserFollow']
],
[
'class' => Follow::class,
'event' => Follow::EVENT_FOLLOWING_REMOVED,
'callback' => [Events::class, 'onUserUnfollow']
],
]
]
// Event.php
public static function onUserFollow(FollowEvent $event)
{
if($event->target instanceof User) {
if($event->target->getFollowerCount() === 5) {
FollowAchievementNotification::instance()->send($event->target);
}
}
}
public static function onUserUnfollow(FollowEvent $event)
{
if($event->target instanceof User) {
if($event->target->getFollowerCount() < 5) {
FollowAchievementNotification::instance()->delete($event->target);
}
}
}

User Friendship Events

Similar to the follow events, the friendship module triggers an events once a user friendship relation is created or removed. The events are triggered by the humhub\modules\friendship\models\Friendship model.

EventClassDescription
Friendship::EVENT_FRIENDSHIP_CREATEDhumhub\modules\friendship\FriendshipEventRaised when a user makes a new friend
Friendship::EVENT_FRIENDSHIP_REMOVEDhumhub\modules\friendship\FriendshipEventRaised when a user removes a friendship

The humhub\modules\friendship\FriendshipEvent class provides the following additional properties:

  • $user1: The user initiating the friendship -$user2: The user who received the friendship request

Space Membership

Space membership events are triggered by the humhub\modules\space\model\Membership model and can be used to trace the creation or removal of space membership relations.

EventClassDescription
Membership::EVENT_MEMBER_ADDEDhumhub\modules\space\MemberEventRaised when a user joins a space or was added
Membership::EVENT_MEMBER_REMOVEDhumhub\modules\space\MemberEventRaised when a user leaves a space or was removed

The humhub\modules\space\model\Membership class provides the following additional properties:

  • $space: The humhub\modules\space\models\Space model of the space -$user: The respective user model of the membership relation

Widget Events

Widget events can be used to extend the output of a widget or even overwrite widget classes.

EventClassDescription
Widget::EVENT_INITyii\base\EventRaised when the widget is initialized via init()
Widget::EVENT_BEFORE_RUNyii\base\WidgetEventRaised right before executing a widget
Widget::EVENT_AFTER_RUNyii\base\WidgetEventRaised right after executing a widget
humhub\components\Widget::EVENT_CREATEhumhub\libs\WidgetCreateEventRaised before Yii::createObject()

Extend widget output

The Widget::EVENT_AFTER_RUN can be used to extend the output of a widget, as in the following example:

// config.php
use my\example\Events;
use humhub\modules\content\widgets\richtext\ProsemirrorRichTextEditor;
return [
//...
'events' => [
[
'class' => ProsemirrorRichTextEditor::class,
'event' => ProsemirrorRichTextEditor::EVENT_AFTER_RUN,
'callback' => [Events::class, 'onRichTextEditorFieldCreate']
]
]
]
// Event.php
public static function onRichTextEditorFieldCreate(WidgetEvent $event)
{
$event->result .= '<div>Powered by example Module</div>';
}

Prevent widget from rendering

The Widget::EVENT_BEFORE_RUN can be used prevent widgets from rendering:

// config.php
use my\example\Events;
use humhub\components\Widget;
return [
//...
'events' => [
[
'class' => 'some\module\widget\SpecialWidget',
'event' => Widget::EVENT_ON_BEVORE_RUN,
'callback' => [Events::class, 'onSpecialWidgetBeforeRun']]
]
]
// Event.php
public static function onSpecialWidgetBeforeRun(WidgetEvent $event)
{
if(static::someSpecialCondition($event)) {
$event->isValid = false;
}
}

Overwrite a widget class

The humhub\components\Widget::EVENT_CREATE can be used to overwrite the widget class.

// config.php
use my\example\Events;
use humhub\components\Widget;
return [
//...
'events' => [
[
'class' => 'some\module\widget\SpecialWidget',
'event' => Widget::EVENT_CREATE,
'callback' => [Events::class, 'onSpecialWidgetBeforeRun']]
]
]
// Event.php
public static function onSpecialWidgetBeforeRun(WidgetCreateEvent $event)
{
$event->config['class'] = MyCustomSpecialWidget::class;
}
caution

Since the widget is created by a call to Yii::createObject() the new widget class has to be compatible with the overwritten one, which means it has to support all possible properties of the original widget class. This could be achieved by extending the original widget.