Convenience method for saving system settings
everettg_99 created Redmine issue ID 4494
It'd make life much easier for nubes and pros alike if there were a convenience method for updating a system setting.
$modx->getOption('my_setting');
Only gets a cached version, and confusingly, the setOption method does not persist the value beyond the page request.
I'd recommend something as simple to use as WordPress' get_option() and update_option() functions. The MODx equivalent of update_option() might look like this:
/**
* Convenience function to update or create system settings.
*
* @param string unique key identifying the system setting to be updated or created
* @param string optional string value
*/
public function getOption($key, $value='') {
$Setting = $this->getObject('modSystemSetting', $key);
if ( empty($Setting) ) {
$Setting = $this->newObject('modSystemSetting');
}
$Setting->set('value') = $value;
$is_success = $Setting->save();
// clear settings cache
return $is_success;
}
Once I wrap my head around GIT and figure out the best place to put functions like this, I might be able to do this and send pull requests...
everettg_99 submitted:
dammit... the function name should be updateOption
bobray submitted:
This could also be done with another argument to setOption() that would trigger a permanent change to the DB.
everettg_99 submitted:
Good call. The setOption() function is just begging for third option:
/**
* Sets an xPDO configuration option value.
*
* @param string $key The option key.
* @param mixed $value A value to set for the given option key.
*/
public function setOption($key, $value) {
$this->config[$key]= $value;
}
Actually, it's not so easy as seems. Because settings also stored in contexts, user groups, and individual users and it's difficult to get a correct place for saving the current setting value. It does in both variants: with separated method and with third parameter for setOption()
There could be one more argument to updateSetting(): settingType. It could be set to modSystemSetting, modContextSetting, modUserSetting, or modUserGroupSetting.
With that, it would look something like this:
`
/**
* Convenience function to update or create system settings.
*
* @param string unique key identifying the setting to be updated or created (e.g., 'modUserSetting')
* @param string optional string value
*/
public function updateSetting($key, $value='', $settingType = 'modSystemSetting') {
$setting = $this->getObject($settingType, $key);
if (! $setting) {
$setting = $this->newObject($settingType);
}
$success = false;
if ($setting) {
$setting->set('value', $value);
$success = $setting->save();
} else {
$this->log(modX::LOG_LEVEL_ERROR, 'Unable to save or create ' . $settingType);
}
// clear settings cache
return $success;
}
`
Seem like a nice method. Want to prepare a PR for it @BobRay ?
If I can find the time. ;)
What do you think about adding cacheFlag as a final argument, and if that's a good idea, should it default to true, false, or null?
Without the argument, it would default to null. The code (xPDOObject->save()) is not clear to me, so I'm not sure if having it set to null means the cache for the setting would be updated or not.
This line:
$setting->set('value') = $value;
should be
$setting->set('value',$value);
modContextSetting, modUserSetting, and modUserGroupSetting has field for relation to objects:
- modContextSetting -
context_key - modUserSetting -
user - modUserGroupSetting -
group
User can be a member of several groups. Which group should we select for default value?
I think, each object have to update its own setting. Like this:
$modx->context->updateSetting($key, $value);
// ...
$modx->user->updateSetting($key, $value);
// ...
$user_group->updateSetting($key, $value);
Does update really translate to "update the value of this object and persist it"? Introducing another way to modify and save values will only introduce more complexity into the codebase.
Does
updatereally translate to "update the value of this object and persist it"? Introducing another way to modify and save values will only introduce more complexity into the codebase.
I agree. I don't understand purpose of this issue. Is it actual?
First, I think ilyautkin's idea (putting the methods in the MODX objects) is by far the best one (as long as the methods call the appropriate processor). It's not only intuitive, it's more convenient, and it makes the calls simpler and more uniform. It also helps bulletproof the process, since it cuts out the possibility of updating the wrong kind of setting. It's much better than my suggestion above.
The main point of convenience methods (besides convenience) is to avoid complexity, imo. They prevent new users from making mistakes (e.g., creating a new user in code without creating a user profile). It's very easy to create a MODX object in code that doesn't appear in the manager, won't work, and/or doesn't have the appropriate intersects objects set. These can crap up the database and cause very frustrating errors.
Users can call the appropriate update processor to make sure things get done right (and my code above should definitely have done that), but the processor paths are not easy to guess and the documentation is difficult to find:
$modx->runProcesssor('security/group/setting/update', $fields);
$modx->runProcesssor('security/user/setting/update', $fields);
$modx->runProcesssor('system/settings/update', $fields);
$modx->runProcessor('context/setting/update', $fields);