Notifications extended context

Extended contexts were implemented in order to allow an extension of the normal, "natural" core context system, without requiring the introduction of additional context "levels" or adding additional nodes/records to the context table.

Extended contexts are based on natural contexts. A non-natural extended context includes a natural context, as well as "component", "area" and "item_id". Either all of these properties are defined, or they are all undefined (constants are provided for these when defining a natural extended context). Every natural context is also an extended context, but with component, area and item_id set to the default constants.

Example: Report builder reports do not belong to any existing context, such as tenant or course category, so can be thought of as belonging to the system context. We could define an extended context for each report as:

  • Context: System context
  • Component: totara_reportbuilder
  • Area: report (the table which the item_id refers to)
  • Item ID: the ID of a report

This would then allow us to define things, such as notifications, in the "context" of the report.


Extended contexts allow one additional level of contexts to be defined below each natural context. Each natural context can have any number of child extended contexts, of any number of types, where each type is distinguished by the component and area.

Example: Seminar events belong to seminars. Seminars are activities, and thus have a natural context. We can define a context for seminar events, so that we can define things, such as  notifications, in the context of the individual events:

  • Context: The specific activity context of the seminar that the event belongs to
  • Component: mod_facetoface
  • Area: event (the item ID belongs to an event)
  • Item ID: the ID of an event

The parent context of an event extended context would be the seminar activity context.

Concepts

  • To support separate notification overrides within same context, centralised notifications introduces extended contexts. This can be useful for creating overrides of separate notifications within the same parent object based on the parent object's internal logic.
  • Extended contexts contain a natural context (a standard, core context) and may optionally contain a component (to allow isolation between components), area (to allow extension from the parent context in more than one way, usually something that identifies what the item_id represents), and item_id (usually an ID of an object which has a type described by the "area").
  • The parent for a non-natural extended context is just the natural context, which means the component, area, and item_id information are dropped. After that standard context tree rules apply.
  • During the event processing, the event observer will save extended context to the notification event queue that will be processed by the next cron run.

Database

There are four database fields associated with extended context for three different tables (notifiable_event_queue, notification_queue,  and notification_preference).

NameTypeDefaultNote
context_idINT(none)The natural context, required
componentCHAR(255)''The component of the extended context
areaCHAR(255)''The area of the component of the extended context
item_idINT0The item id of the component of the extended context

These fields are used to uniquely identify any item within the Totara system and follows the same principles as file storage, Totara comments, or Totara Engage shares.

GraphQL

There is a new Graphql type for extended context that maps into the extended context class:

"""
A type to hold extended context.
"""
type totara_notification_extended_context {
  """
  The context ID of the notification.
  """
  context_id: Int!
  """
  In a non-natural context, the component to which the context relates
  """
  component: String!
  """
  The area of component
  """
  area: String!
  """
  The item id of component
  """
  item_id: Int!
}

Notifiable events include component, area, and item_id as optional query parameters to fetch notifiable events from the server and three optional parameters will be passed through the preferences query to get the correct notification preference.

totara_notification_notification_preferences(
    """
    Extended context MUST be provided, in order to create the notification preference
    within that context. Note that the context's id for this extended_context can be fallback
    to the context system if none is provided.
    """
    extended_context: totara_notification_extended_context_input!
    
    """
    If this parameter is provided, we are fetching only the notification preferences that are listening to
    this event only.
    """
    resolver_class_name: param_text
    """
    Whether we want the list of notification preferences at the specific context only,
    or the list that is a mix of overridden and non-overridden (higher context).
    """
    at_context_only: param_boolean!
  ): [totara_notification_notification_preference!]!

Classes/interfaces

This table outlines classes, interfaces, and methods most relevant in extended context processing.

Class, interface, or method

Notes

\totara_core\identifier\instance_identifierA metadata class that holds a specific item instance, where an item is a database record made up of a context, component, area, and ID.
\totara_core\identifier\component_area

A data holder class for merging the component and area into the same place. This class is for helping to short the function(s) that require parameters such as component and area together. With this class, those function(s) can shorten into just declaring the need of component_area instance.
\totara_core\extended_contextWrapper class to handle extended context related data (context itself, component, area, and item ID) 

Extended context implementation

Extended context are embedded in notifiable event resolvers and must implement method support_context()

<?php
namespace your_component\totara_notification\resolver;
 
use totara_notification\resolver\notifiable_event_resolver;
use totara_core\extended_context;
 
 
class your_resolver extends notifiable_event_resolver {
    // ...

    /**
     * Indicates whether the resolver supports the given context.
     * By default, resolvers support the system context.
     * Override this function to support other contexts.
     *
     * @param extended_context $extend_context
     * @return bool
     */
    public static function supports_context(extended_context $extended_context): bool {
        $context = $extended_context->get_context();

        if ($extended_context->is_natural_context()) {
            return in_array($context->contextlevel, [CONTEXT_SYSTEM, CONTEXT_COURSECAT, CONTEXT_COURSE]);
        }

        return $context->contextlevel === CONTEXT_COURSE && $extended_context->get_component() === 'your_component';
    }

	// ...	
 
}