diff --git a/application/forms/DirectorDatafieldForm.php b/application/forms/DirectorDatafieldForm.php index f813a719..6ffdd829 100644 --- a/application/forms/DirectorDatafieldForm.php +++ b/application/forms/DirectorDatafieldForm.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Forms; use Icinga\Exception\ConfigurationError; +use Icinga\Module\Director\CustomVariable\CustomVariables; use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Application\Hook; use Exception; @@ -11,6 +12,65 @@ class DirectorDatafieldForm extends DirectorObjectForm { protected $objectName = 'Data field'; + protected function onRequest() + { + if ($this->hasBeenSent()) { + + if ($this->shouldBeDeleted()) { + $varname = $this->getSentValue('varname'); + if ($cnt = CustomVariables::countAll($varname, $this->getDb())) { + $this->askForVariableDeletion($varname, $cnt); + } + + } + } + + return parent::onRequest(); + } + + protected function askForVariableDeletion($varname, $cnt) + { + $msg = $this->translate( + 'Leaving custom variables in place while removing the related field is' + . ' perfectly legal and might be a desired operation. This way you can' + . ' no longer modify related custom variables in the Director GUI, but' + . ' the variables themselves will stay there and continue to be deployed.' + . ' When you re-add a field for the same variable later on, everything' + . ' will continue to work as before' + ); + + $this->addBoolean('wipe_vars', array( + 'label' => $this->translate('Wipe related vars'), + 'description' => sprintf($msg, $this->getSentValue('varname')), + 'required' => true, + )); + + if ($wipe = $this->getSentValue('wipe_vars')) { + if ($wipe === 'y') { + CustomVariables::deleteAll($varname, $this->getDb()); + } + } else { + $this->abortDeletion(); + $this->addError( + sprintf( + $this->translate('Also wipe all "%s" custom variables from %d objects?'), + $varname, + $cnt + ) + ); + $this->getElement('wipe_vars')->addError( + sprintf( + $this->translate( + 'There are %d objects with a related property. Should I also' + . ' remove the "%s" property from them?' + ), + $cnt, + $varname + ) + ); + } + } + public function setup() { $this->addHtmlHint( diff --git a/library/Director/CustomVariable/CustomVariables.php b/library/Director/CustomVariable/CustomVariables.php index 311310ba..3ce0bb00 100644 --- a/library/Director/CustomVariable/CustomVariables.php +++ b/library/Director/CustomVariable/CustomVariables.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\CustomVariable; +use Icinga\Module\Director\Db; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer; use Icinga\Module\Director\Objects\IcingaObject; @@ -20,6 +21,41 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer protected $idx = array(); + protected static $allTables = array( + 'icinga_command_var', + 'icinga_host_var', + 'icinga_notification_var', + 'icinga_service_var', + 'icinga_user_var', + ); + + public static function countAll($varname, Db $connection) + { + $db = $connection->getDbAdapter(); + $parts = array(); + $where = $db->quoteInto('varname = ?', $varname); + foreach (static::$allTables as $table) { + $parts[] = sprintf( + 'SELECT COUNT(*) as cnt FROM icinga_host_var WHERE %s', + $where + ); + } + + $query = 'SELECT SUM(cnt) AS cnt FROM (' + . implode(' UNION ALL ', $parts) + . ') sub'; + return (int) $db->fetchOne($query); + } + + public static function deleteAll($varname, Db $connection) + { + $db = $connection->getDbAdapter(); + $where = $db->quoteInto('varname = ?', $varname); + foreach (static::$allTables as $table) { + $db->delete($table, $where); + } + } + public function count() { $count = 0; diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index d6478d64..5627ad07 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -943,6 +943,13 @@ abstract class DirectorObjectForm extends QuickForm return $this->getSentValue($name) === $this->getElement($name)->getLabel(); } + protected function abortDeletion() + { + if ($this->hasDeleteButton()) { + $this->setSentValue($this->deleteButtonName, 'ABORTED'); + } + } + public function getSentOrResolvedObjectValue($name, $default = null) { return $this->getSentOrObjectValue($name, $default, true);