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 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:
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
}
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);
}
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
}
}
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
}
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'
);
}
}
(int), (bool), etc.) before using them.??) to handle missing options.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'
);
}
}