User Tools

Site Tools

This is an old revision of the document!


Back Office Menu Entries

Best practice for modules adding services in back office is to not offer these services on their configuration page, but to add an entry to one of the back office menus. This strategy may well become mandatory one day.

Going this route isn't particularly difficult. One big advantage: one doesn't have to go through getContent() in the module main class and build up everything from there. One can use 'real' controllers, just like all the controllers and classes coming with thirty bees core.

Code snippets here were written while starting with the Git Updater module. You can find complete files and module snapshots in the early commits there.

Install the Tab / Menu Item

Note: while entries in a menu are usually called menu item or similar, thirty bees source code calls them Tabs. Base class Tabs, controller AdminTabsController, and so on.

Define a Controller

As written above, Tabs run a controller. First step to define the name of this controller. Using a class constant is a good idea.

class GitUpdater extends Module
{
    const MAIN_CONTROLLER = 'AdminGitUpdater';
 
    // ...
}

Note that the controller name is defined to just AdminGitUpdater, not AdminGitUpdaterController. The Controller part gets added by thirty bees core automatically.

Installing the Tab

Installation code obviously goes into install() of the module main class. Here is how it can be done:

public function install()
{
    $success = parent::install();
 
    if ($success) {
        try {
            $tab = new Tab();
 
            $tab->module      = $this->name;
            $tab->class_name  = static::MAIN_CONTROLLER;
            $tab->id_parent   = Tab::getIdFromClassName('AdminPreferences');
 
            $langs = Language::getLanguages();
            foreach ($langs as $lang) {
                $tab->name[$lang['id_lang']] = $this->l('Updater');
            }
 
            $success = $tab->save();
        } catch (Exception $e) {
            $success = false;
        }
    }
 
    return $success;
}
$tab->module

That's the module which created the Tab. Always $this->name.

$tab->class_name

This defines the controller class for the Tab. Without the trailing Controller, see previous section.

$tab->id_parent

Tab ID of the parent Tab. If NULL, the new Tab gets appended to the menu top level. Else it gets appended to the submenu of this parent.

There are multiple ways to find the parent ID. Hardcoding this ID isn't a good idea, it might change in the future.

$tab->name

This is the user visible name of the Tab. As thirty bees supports multiple languages, one has to set each language.

$tab->save()

This saves the Tab into the database. Should be repeated after each change of the Tab. And yes, Tabs defined by modules are visible everywhere, not just from code inside the defining module.

Uninstalling the Tab

Being nice code writers, we uninstall Tabs on module uninstallation, of course. Nobody wants to be responsible for useless clutter in the database.

Nice enough, that's pretty simple:

public function uninstall()
{
    $success = true;
 
    $tabs = Tab::getCollectionFromModule($this->name);
    foreach ($tabs as $tab) {
        $success = $success && $tab->delete();
    }
 
    return $success && parent::uninstall();
}

Enabling and Disabling

One might wonder what happens with module defined Tabs when the module gets disabled, but not uninstalled.

Nice feature of such Tabs is, they automatically get disabled together with disabling the module. No need for the module developer to take care of this. A disabled Tab is still recorded in the database, nevertheless it disappears from the back office menu.

Creating a Controller

Back office controllers go into controllers/admin/ inside the module directory. A bare minimum controller looks like this:

AdminGitUpdaterController.php
<?php
/**
 * Copyright ...
 */
 
if (!defined('_TB_VERSION_')) {
    exit;
}
 
/**
 * Class AdminGitUpdaterController
 *
 * @since 1.0.0
 */
class AdminGitUpdaterController extends ModuleAdminController
{
    /**
     * @since 1.0.0
     */
    public function __construct()
    {
        $this->bootstrap = true;
 
        parent::__construct();
    }
 
    /**
     * @since 1.0.0
     */
    public function initContent()
    {
        $this->page_header_toolbar_title = 'Git Updater';
 
        parent::initContent();
    }
}

A few notes:

  • Subclassing ModuleAdminController instead of AdminController. Former is a thin wrapper around the latter, loading the module as needed and bending template search paths into the module directory.
  • Methods __construct() and initContent() just added to show how it works. Don't forget to call parents!

This class isn't useful on its own, so far.

back_office_menu_entries.1532472717.txt.gz ยท Last modified: 2018/07/25 00:51 by Traumflug