Core Dual Render ‐ Admin - xoopscube/legacy GitHub Wiki

XCL's Admin Render System Initialization

The XCL framework uses a sophisticated rendering system with different render systems for public and admin areas.
Let's keep refering to "core dual render" as a clear and descriptive term that gets the essential concept across
without relying on potentially fleeting JavaScript-centric buzzwords. It emphasizes the fundamental idea of having
a central rendering capability that operates in two key environments (server and client) for distinct advantages.
So, how the render system initialization works, particularly on the admin side where the magic operates.

Render System Architecture

XCL has two primary render systems:

  1. Legacy_RenderSystem - Used for public-frontend pages
  2. Legacy_AdminRenderSystem - Used for admin control panel

These render systems are defined in the site configuration (site_default.ini):

[RenderSystems]
Legacy_RenderSystem=Legacy_RenderSystem
Legacy_AdminRenderSystem=Legacy_AdminRenderSystem

[!NOTE] Certain bundle distributions feature or provide support for customized renders.

Render System Initialization Process

The initialization process follows these steps:

  1. The controller (Legacy_Controller) determines which render system to use based on the context
  2. It loads the appropriate render system class
  3. The render system creates render targets for different parts of the page (blocks, main, etc.)
  4. Preloads like AdminDashboard hook into this process to modify or extend functionality

Admin Render System Specifics

For the admin area, the process is:

  1. Legacy_Controller detects an admin request and sets Legacy_AdminRenderSystem as the base render system
  2. Legacy_AdminControllerStrategy is initialized to handle admin-specific rendering
  3. The strategy sets up admin blocks through its mSetupBlock delegate
  4. Preloads like AdminDashboard hook into this process via delegates

The AdminDashboard Preload

Looking at the AdminDashboard.class.php preload:

public function preBlockFilter()
{
    $root=&XCube_Root::getSingleton();

    // Add a delegate to the SystemCheck event
    $root->mDelegateManager->add("Legacypage.Admin.SystemCheck", 
                                "Legacy_AdminDashboard::AdminDashboardSystem", 
                                XCUBE_DELEGATE_PRIORITY_1);

    // Hook into the admin block setup process
    if ($root->mController->_mStrategy && 
        get_class($root->mController->_mStrategy) === 'Legacy_AdminControllerStrategy') {
        $this->mController->_mStrategy->mSetupBlock->add([$this, 'AdminSetupBlock']);
    }
}

This preload does two important things:

  1. It hooks into the Legacypage.Admin.SystemCheck delegate to add dashboard content
  2. It hooks into the admin controller strategy's block setup process to add admin blocks

The Delegate System

The line that does the magic:

$root->mDelegateManager->add("Legacypage.Admin.SystemCheck", "Legacy_AdminDashboard::AdminDashboardSystem", XCUBE_DELEGATE_PRIORITY_1);

This registers the AdminDashboardSystem static method to be called when the Legacypage.Admin.SystemCheck event is triggered.
The priority (1) ensures it runs before other handlers.

Render Target Creation

When the AdminDashboardSystem method is called, it creates content for the admin dashboard:

public static function AdminDashboardSystem()
{
    $root =& XCube_Root::getSingleton();

    if(XC_ADMINDASHBOARD_INFO) {
        // Dashboard content creation logic...
        
        // Create and render content using the render system
        $attributes = [];
        $attributes['title'] = $title1;
        $attributes['content'] = $content1;
        $template = XOOPS_LEGACY_PATH. '/admin/templates/dashboard.html';
        self::display_message(false, $attributes, $template);
    }
}

The Rendering Process

The actual rendering happens in the display_message method:

public static function display_message(bool $return, array $attributes = [], string $template= '')
{
    $root =& XCube_Root::getSingleton();
    
    // Get the current render system
    $renderSystem =& $root->getRenderSystem($root->mContext->mBaseRenderSystemName);
    
    // Create a render target for the main content area
    $renderTarget =& $renderSystem->createRenderTarget('main');
    
    // Set module attribute
    $renderTarget->setAttribute('legacy_module', 'legacy');
    
    // Set template name
    $renderTarget->setTemplateName($template);
    
    // Add all attributes to the render target
    foreach (array_keys($attributes) as $attribute) {
        $renderTarget->setAttribute($attribute, $attributes[$attribute]);
    }
    
    // Render the content
    $renderSystem->render($renderTarget);
    
    // Return or print the result
    if ($return == true) {
        return $renderTarget->getResult();
    }
    print $renderTarget->getResult();
}

This method:

  1. Gets the current render system (in this case, Legacy_AdminRenderSystem)
  2. Creates a render target for the main content area
  3. Sets the template and attributes
  4. Renders the content
  5. Outputs the result

Admin Blocks Setup

The AdminSetupBlock method adds blocks to the admin interface:

public function AdminSetupBlock() {
    if (XC_ADMIN_BLOCK_MENU) {
        require_once XOOPS_LEGACY_PATH . '/admin/blocks/AdminBlockMenu.class.php';
        $this->mController->_mBlockChain[] = new Legacy_AdminBlockMenu();
    }
    
    // More blocks...
}

Each block is added to the controller's block chain, which is processed by the render system to create the final admin interface.

The Complete Flow

  1. Request comes in for an admin page
  2. Legacy_Controller initializes with Legacy_AdminControllerStrategy
  3. Preloads like AdminDashboard hook into the process
  4. The controller processes the request and prepares data
  5. The Legacy_AdminRenderSystem creates render targets for different parts of the page
  6. Delegates like Legacypage.Admin.SystemCheck are triggered
  7. Preloads add content and blocks to the render targets
  8. The render system processes templates with Smarty
  9. The final HTML is output

This architecture allows for a highly modular and extensible admin interface where components like the dashboard
can be easily customized through preloads (single file comonent) without modifying core files.