Base class to encapsulate a request to the component, instantiated by the MidCOM component interface.

It provides an automatic mechanism for URL processing and validation, minimizing the required work to get a new component running.

Request switch configuration

The class uses an array which aids in URL-to-function mapping. Handlers are distinguished by the "URL-space" they handle. For each handler three functions are needed, one for the request handle decision ("Can Handle Phase"), one for the request handling ("Handle Phase") and one for output ("Output Phase"). These handlers can either be contained in this class or refer to another class which gets instantiated, if necessary.

All request handlers are contained in a single array, whose keys identify the various switch configurations. These identifiers are only for informational purposes (they appear in the debug log), so you could just resort to automatic array index numbering using the [] operator.

Each request handler definition in the switch must contain these key/value pairs:

  • mixed fixed_args: This is either a string or an array and defines the fixed arguments that have to be present at the beginning of the URL to be handled. A string denotes a single argument, an array is used if more then one fixed argument is needed. If you do not have any fixed arguments, set this parameter to null, which is the default.
  • int variable_args: Usually, there are a number of variables in the URL, like article IDs, or article names. This can be 0, indicating that no variable arguments are required, which is the default. For an unlimited number of variable_args set it to -1.

  • boolean no_cache: For those cases where you want to prevent a certain "type" of request being cached. Set to false by default.

  • int expires: Set the default expiration time of a given type of request. The default -1 is used to indicate no expiration setting. Any positive integer will cause its value to be passed to the caching engine, indicating the expiration time in seconds.
  • mixed handler: This is a definition of what method should be invoked to handle the request. You have two options here. First you can refer to a method of this request handler class, in that case you just supply the name of the method. Alternatively, you can refer to an external class for request processing using an array syntax. The first array member must either contain the name of an existing class or a reference to an already instantiated class. This value has no default and must be set. The actual methods called will have either an handle or show prefixed to the exec_handler value, respectively. See below for automatic handler instances, the preferred way to set things up.

Example:

$this->_request_switch[] = Array
(
    'fixed_args' => Array ('registrations', 'view'),
    'variable_args' => 1,
    'no_cache' => false,
    'expires' => -1,
    'handler' => 'view_registration'
    //
    // Alternative, use a class with automatic instantiation:
    // 'handler' => Array('net_nemein_registrations_regadmin', 'view')
    //
    // Alternative, use existing class (first parameter must be a reference):
    // 'handler' => Array($regadmin, 'view')
);

This definition is usually located in either in the _on_initialize event handler (preferred) or the subclass' constructor (discouraged, as you can't use references to $this safely there).

The handlers are processed in the order which they have been added to the array. This has several implications:

First, if you have two handlers with similar signatures, the latter might be hidden by the former, for example the handler 'view' with two variable arguments includes the urls that could match 'view', 'registration' with a single variable argument if processed in this order. In these cases you have to add the most specific handlers first.

Second, for performance reasons, you should try to add the handler which will be accessed most of the time first (unless it conflicts with the first rule above), as this will speed up average request processing.

Subclasses may add additional configuration data to the handler declarations, this is done, for example by the config_dm handler defined in the request_admin subclass. They must only be used to configure predefined requests, you should refer to the documentation of these handlers for details.

It is recommended that you add string-based identifiers to your handlers. This makes debugging of URL parsing much easier, as MidCOM logs which request handlers are checked in debug mode. The above example could use something like $this->_request_switch['registrations-view'] to do so. Just never prefix one of your handlers with one underscores, this namespace is reserved for MidCOM usage.

Callback method signatures

/**
 * can_handle example, with Docblock:
 * @param mixed $handler_id The ID of the handler.
 * @param array $args The argument list.
 * @param array &$data The local request data.
 * @return boolean True if the request can be handled, false otherwise.
 {@*}
function _can_handle_xxx ($handler_id, array $args, array &$data) {}

/**
 * Exec handler example, with Docblock:
 * @param mixed $handler_id The ID of the handler.
 * @param array $args The argument list.
 * @param array &$data The local request data.
 {@*}
function _handler_xxx ($handler_id, array $args, array &$data) {}

/**
 * Show handler example, with Docblock:
 * @param mixed $handler_id The ID of the handler.
 * @param array &$data The local request data.
 {@*}
function _show_xxx ($handler_id, array &$data) {}

The three callbacks match the regular processing sequence of MidCOM.

_can_handle_xxx notes: For ease of use, the _can_handle_xxx callback is optional, it will only be called if the method actually exists. Normally you want to override this only if you request handler can hide stuff which is not under the control of your topic. A prominent example is a hander definition which has only a single variable argument. It would hide all subtopics if you don't check what objects actually belong to you, and what not.

The main callbacks _handle_xxx and _show_xxx are mandatory.

As you can see, the system provides you with an easy way to keep track of the data of your request, without having dozens of members for trivial flags. This data array is automatically registered in the custom component context under the name 'request_data', making it easily available within style elements as $data

The data array can also be accessed by using the $_request_data member of this class, which is the original data storage location for the request data.

Note, that the request data, for ease of use, already contains references to the L10n Databases of the Component and MidCOM itself located in this class. They are stored as 'l10n' and 'l10n_midcom'. Also available as 'config' is the current component configuration and 'topic' will hold the current content topic.

Automatic handler class instantiation

If you specify a class name instead of a class instance as an exec handler, MidCOM will automatically create an instance of that class type and initialize it. These so-called handler classes must be a subclass of midcom_baseclasses_components_handler.

The subclasses you create should look about this:

class my_handler extends midcom_baseclasses_components_handler
{
    function _on_initialize()
    {
        // Add class initialization code here, all members have
        // been prepared, and the instance is already stable, so
        // you can safely work with references to $this here.
    }
}

The two methods for each handler have the same signature as if they were in the same class.

Plugin Interface

This class includes a plugin system which can be used to flexibly enhance the functionality of the request classes by external sources. Your component does not have to worry about this, you just have to provide a way to register plugins to site authors.

Plugins always come in "packages", which are assigned to a namespace. The namespace is used to separate various plugins from each other, it is prepended before any URL. Within a plugin you can register one or more handler classes. Each of this classes can of course define more then one request handler.

A plugin class must be a descendant of midcom_baseclasses_components_handler or at least support its full interface.

It must define an additional function, called get_plugin_handlers(). It has to return an array of standard request handler declarations. Both handler identifiers and argument lists are relative to the base URL of the plugin (see below), not to the component running the problem. You are thus completely location independent. The handler callback must be statically callable.

Example: Plugin handler callback

function get_plugin_handlers()
{
    return Array
    (
         'metadata' => array
         (
             'handler' => array('midcom_admin_folder_handler_metadata', 'metadata'),
             'fixed_args' => array ('metadata'),
             'variable_args' => 1,
         ),
        // ...
    );
}

As outlined above, plugins are managed in a two-level hierarchy. First, there is the plugin identifier, second the class identifier. When registering a plugin, these two are specified. The request handlers obtained by the above callback are automatically expanded to match the plugin namespace.

Example: Plugin registration

$this->register_plugin_namespace
(
    '__ais',
    Array
    (
        'folder' => Array
        (
            'class' => 'midcom_admin_folder_management',
            'src' => 'file:/midcom/admin/folder/management.php',
            'name' => 'Folder administration',
            'config' => null,
        ),
    )
);

The first argument of this call identifies the plugin namespace, the second the list of classes associated with this plugin. Each class gets its own identifier. The namespace and class identifier is used to construct the final plugin URL: {$anchor_prefix}/{$namespace}/{$class_identifier}/... This gives fully unique URL namespaces to all registered plugins.

Plugin handlers always last in queue, so they won't override component handlers. Their name is prefixed with __{$namespace}-{$class_identifier} to ensure uniqueness.

Each class must have these options:

  • class: The name of the class to use
  • src: The source URL of the plugin class. This can be either a file:/... URL which is relative to MIDCOM_ROOT, snippet:/... which identifies an arbitrary snippet loaded with mgd_include_snippet or, finally, component:... which will load the component specified. This is only used if the class is not yet available.
  • name: This is the clear-text name of the plugin.
  • config: This is an optional configuration argument, allows for customization. May be omitted, in which case it defaults to null.

Once a plugin has been successfully initialized, its configuration is put into the request data:

  • mixed plugin_config: The configuration passed to the plugin as outlined above.
  • string plugin_name: The name of the plugin as defined in its config
  • string plugin_namespace: The plugin namespace defined when registering.
  • string plugin_anchorprefix: A plugin-aware version of MIDCOM_CONTEXT_ANCHORPREFIX pointing to the root URL of the plugin.
package midcom.baseclasses

 Methods

__construct (\midgard_topic $topic, \midcom_helper_configuration $config)

Initializes the class, only basic variable assignment.

Put all further initialization work into the _on_initialize event handler.

Parameters

$topic

\midgard_topicThe topic we are working on

$config

\midcom_helper_configurationThe currently active configuration.

_load_plugin (string $namespace, string $plugin)

This helper loads the specified namespace/plugin combo.

Any problem to load a plugin will be logged accordingly and false will be returned. Critical errors will trigger midcom_error.

todo Allow for lazy plugin namespace configuration loading (using a callback)! This will make things more performant and integration with other components much easier.

Parameters

$namespace

stringThe plugin namespace to use.

$plugin

stringThe plugin to load from the namespace.

Returns

booleanIndicating success

_load_plugin_class (string $namespace, string $plugin)

Loads the file/snippet necessary for a given plugin, according to its configuration.

Parameters

$namespace

stringThe plugin namespace to use.

$plugin

stringThe plugin to load from the namespace.

_on_can_handle (int $argc, array $argv)

Component specific initialization code for the can_handle phase.

This is run before the actual evaluation of the request switch. Components can use this phase to load plugins that need registering in the request switch on demand.

The advantage of this is that it is not necessary to load all plugins completely, you just have to know the "root" URL space (f.x. "/plugins/$name/").

If you discover that you cannot handle the request already at this stage, return false The remainder of the can_handle phase is skipped then, returning the URL processing back to MidCOM.

Parameters

$argc

intThe argument count as passed by the Core.

$argv

arrayThe argument list.

Returns

booleanReturn false to abort the handle phase, true to continue normally.

_on_handle (mixed $handler, array $args)

Component specific initialization code for the handle phase.

The name of the request handler is passed as an argument to the event handler.

Note, that while you have the complete information around the request (handler id, args and request data) available, it is strongly discouraged to handle everything here. Instead, stay with the specific request handler methods as far as sensible.

Parameters

$handler

mixedThe ID (array key) of the handler that is responsible to handle the request.

$args

arrayThe argument list.

Returns

booleanReturn false to abort the handle phase, true to continue normally.

_on_handled ($handler, $args)

Parameters

$handler

$args

_on_initialize ()

Initialization event handler, called at the end of the initialization process immediately before the request handler configuration is read.

Use this function instead of the constructor for all initialization work, as it makes your life much easier with references to $this being available. You can safely populate the request switch from here.

You should not do anything else then general startup work, as this callback executes before the can_handle phase. You don't know at this point whether you are even able to handle the request. Thus, anything that is specific to your request (like HTML HEAD tag adds) must not be done here. Use _on_handle instead.

_on_show (mixed $handler)

Generic output initialization code.

The return value lets you control whether the output method associated with the handler declaration is called, return false to override this automatism, true, the default, will call the output handler normally.

Parameters

$handler

mixedThe ID (array key) of the handler that is responsible to handle the request.

Returns

booleanReturn false to override the regular component output.

_on_shown ($handler)

Parameters

$handler

_prepare_handler ()

Helper function, which prepares the handler callback for execution.

This will create the handler class instance if required.

_prepare_plugin (string $namespace, string $plugin)

Prepares the actual plugin by adding all necessary information to the request switch.

Parameters

$namespace

stringThe plugin namespace to use.

$plugin

stringThe plugin to load from the namespace.

Returns

booleanIndicating Success

_prepare_request_switch ()

This public helper post-processes the initial information as set by the constructor.

It fills all missing fields with sensible defaults, see the class introduction for details.

can_handle (int $argc, array $argv)

CAN_HANDLE Phase interface, checks against all registered handlers if a valid one can be found.

You should not need to override this, instead, use the HANDLE Phase for further checks.

If available, the function calls the _can_handle callback of the event handlers which potentially match the argument declaration.

Parameters

$argc

intThe argument count

$argv

arrayThe argument list

Returns

booleanIndicating whether the request can be handled by the class, or not.

handle ()

This method handles the request using the handler determined by the can_handle check.

Before doing anything, it will call the _on_handle event handler to allow for generic request preparation.

see \_on_handle()

Returns

booleanIndicating whether the request was handled successfully.

initialize (string $component)

Initializes the request handler class, called by the component interface after instantiation.

Required to allow safe $this references during startup.

Parameters

$component

stringThe name of the component.

register_plugin_namespace (string $namespace, array $config)

This function creates a new plugin namespace and maps the configuration to it.

It allows flexible, user-configurable extension of components.

Only very basic testing is done to keep runtime up, currently the system only checks to prevent duplicate namespace registrations. In such a case, midcom_error will be thrown. Any further validation won't be done before can_handle determines that a plugin is actually in use.

Parameters

$namespace

stringThe plugin namespace, checked against $args[0] during URL parsing.

$config

arrayThe configuration of the plugin namespace as outlined in the class introduction

show ()

Display the content, it uses the handler as determined by can_handle.

Before doing anything, it will call the _on_showent handler to allow for generic preparation. If this function returns false, the regular output handler will not be called.

see \_on_show()

_register_core_plugin_namespaces ()

This helper function registers the plugin namespaces provided from the MidCOM core.

_validate_route (array $request, $argc, array $argv)

Parameters

$request

$argc

$argv

 Properties

 

\midcom_helper_configuration $_config

The current configuration.
 

Array $_handler

This is a reference to the handler which declared to be able to handle the request.

The array will contain the original index of the handler in the 'id' member for backtracking purposes. The variable argument list will be placed into 'args' for performance reasons.

 

\midcom_helper_toolbar $_node_toolbar

The node toolbar for the current request context.

Not available during the can_handle phase.

see \midcom_services_toolbars
 

array $_request_data

Request specific data storage area.

Registered in the component context as ''.

 

array $_request_switch

Request execution switch configuration.

The main request switch data. You need to set this during construction, it will be post-processed afterwards during initialize to provide a unified set of data. Therefore you must not modify this switch after construction.

 

\midcom_db_topic $_topic

The topic for which we are handling a request.
 

\midcom_helper_toolbar $_view_toolbar

The view toolbar for the current request context.

Not available during the can_handle phase.

see \midcom_services_toolbars
 

\midcom_baseclasses_components_plugin $_active_plugin

The controlling class for the active plugin, if any
 

array $_plugin_namespace_config

This variable keeps track of the registered plugin namespaces.

It maps namespace identifiers against plugin config lists. This is used during can_handle startup to determine whether the request has to be relayed to a plugin.

You have to use the register_plugin_namespace() member function during the _on_initialize event to register plugin namespaces.