User Tools

Site Tools


optionchanges:handlingchanges

Component Options Handler Documentation

Handler Method Parameters

When component options are changed, your handler method receives four parameters:

Parameter Type Description
$component string Name of the component (e.g., 'com_yourcomponent')
$changes array Associative array of changed options
$oldOptions object Complete set of component options before changes
$newOptions object Complete set of component options after changes

The $changes Array Structure

The $changes array provides a detailed look at which options have been modified. Each key in the array corresponds to an option name, and the value is an associative array containing both the old and new values.

$changes = [
    'option_name' => [
        'old' => 'previous_value',
        'new' => 'new_value'
    ],
    // Additional changed options follow the same pattern
];

This structure makes it easy to:

  • Check if a specific option has changed
  • Access both the previous and new values for comparison
  • Process only the options that have actually changed

Handling Option Changes

1. Basic Option Check

The simplest approach is to check if a specific option exists in the changes array:

if (isset($changes['cache_lifetime'])) {
    // The cache_lifetime option has changed
    $newLifetime = $changes['cache_lifetime']['new'];
    $oldLifetime = $changes['cache_lifetime']['old'];
 
    // Take appropriate action based on the change
}

2. Type-Specific Handling

Options can be of various types, and you may need different handling for each:

// Boolean option (checkbox)
if (isset($changes['enable_feature'])) {
    $isEnabled = (bool) $changes['enable_feature']['new'];
 
    if ($isEnabled) {
        // Feature was enabled - initialize required resources
    } else {
        // Feature was disabled - clean up resources
    }
}
 
// Numeric option
if (isset($changes['items_per_page'])) {
    $newValue = (int) $changes['items_per_page']['new'];
 
    // Validate the new value
    if ($newValue < 1) {
        // Log invalid setting
    } else {
        // Apply the new setting
    }
}
 
// Text option
if (isset($changes['api_key'])) {
    $newApiKey = $changes['api_key']['new'];
 
    if (empty($newApiKey)) {
        // API key was removed - disable API functionality
    } else {
        // New API key - validate and initialize API connection
    }
}

Sometimes multiple related options change together and should be handled as a group:

// Check for any changes to email settings
$emailSettingsChanged = false;
$emailSettings = ['email_from', 'email_sender_name', 'email_template'];
 
foreach ($emailSettings as $setting) {
    if (isset($changes[$setting])) {
        $emailSettingsChanged = true;
        break;
    }
}
 
if ($emailSettingsChanged) {
    // Get the complete set of current email settings from $newOptions
    $currentEmailFrom = $newOptions->email_from ?? '';
    $currentSenderName = $newOptions->email_sender_name ?? '';
    $currentTemplate = $newOptions->email_template ?? 'default';
 
    // Reinitialize email system with new settings
    $this->initializeEmailSystem($currentEmailFrom, $currentSenderName, $currentTemplate);
}

4. Working with Complex Options

For more complex options stored as JSON or serialized data:

if (isset($changes['advanced_settings'])) {
    $newSettings = $changes['advanced_settings']['new'];
 
    // If the setting is stored as JSON string, decode it
    if (is_string($newSettings)) {
        $newSettings = json_decode($newSettings);
    }
 
    // Now you can access individual properties
    if (isset($newSettings->timeout)) {
        // Handle timeout setting change
    }
}

5. Checking for Option Removal

The $changes array also tracks options that have been completely removed:

if (isset($changes['legacy_feature']) && $changes['legacy_feature']['new'] === null) {
    // The option has been completely removed
    // Perform any cleanup necessary
}

Using the Complete Options Objects

While the $changes array focuses only on what's changed, the $oldOptions and $newOptions parameters provide the full context:

// Check if a critical dependency setting has changed
if (isset($changes['external_service'])) {
    // The external service setting changed
    $newService = $changes['external_service']['new'];
 
    // Check related settings that might need to be adjusted
    $serviceUrl = $newOptions->service_url ?? '';
    $serviceKey = $newOptions->service_key ?? '';
 
    // Validate the combination of settings
    if ($newService === 'enabled' && (empty($serviceUrl) || empty($serviceKey))) {
        // Log warning - service enabled but required settings are missing
        Log::add(
            'External service enabled but URL or API key is missing',
            Log::WARNING,
            'com_yourcomponent'
        );
    }
}

Best Practices

  • Validate New Values: Always validate the new option values before using them.
  • Type Casting: Cast values to the appropriate type ((int), (bool), etc.) before using them.
  • Handle Gracefully: Use default values and null coalescing (??) to handle missing options.
  • Limit Side Effects: Keep handlers focused on processing only what's needed for the changed options.
  • Error Handling: Wrap operations in try/catch blocks to prevent failures from affecting the user experience.
  • Logging: Log significant changes and any issues that arise.
  • Performance: For performance-critical components, consider using the changes array to process only what's changed rather than reinitializing everything.

Example Implementation

public static function handleOptionsChange($component, $changes, $oldOptions, $newOptions)
{
    // Verify this is our component
    if ($component !== 'com_yourcomponent') {
        return;
    }
 
    try {
        // Process configuration sections based on what changed
 
        // 1. Cache settings
        if (isset($changes['cache_enabled']) || isset($changes['cache_lifetime'])) {
            self::handleCacheChanges($newOptions);
        }
 
        // 2. API settings
        if (isset($changes['api_key']) || isset($changes['api_endpoint'])) {
            self::handleApiChanges($changes, $newOptions);
        }
 
        // 3. General settings that require full refresh
        $refreshTriggers = ['items_per_page', 'sort_direction', 'default_view'];
        $needsRefresh = false;
 
        foreach ($refreshTriggers as $option) {
            if (isset($changes[$option])) {
                $needsRefresh = true;
                break;
            }
        }
 
        if ($needsRefresh) {
            self::refreshComponentState($newOptions);
        }
 
        // Log successful processing
        Log::add(
            sprintf('Successfully processed %d option changes', count($changes)),
            Log::INFO,
            'com_yourcomponent'
        );
    } catch (\Exception $e) {
        // Log error but don't prevent options from being saved
        Log::add(
            sprintf('Error processing option changes: %s', $e->getMessage()),
            Log::ERROR,
            'com_yourcomponent'
        );
    }
}
optionchanges/handlingchanges.txt · Last modified: 2025/02/25 15:59 by admin