diff options
Diffstat (limited to 'library/Director/DirectorObject/ObjectPurgeHelper.php')
-rw-r--r-- | library/Director/DirectorObject/ObjectPurgeHelper.php | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/library/Director/DirectorObject/ObjectPurgeHelper.php b/library/Director/DirectorObject/ObjectPurgeHelper.php new file mode 100644 index 0000000..a043965 --- /dev/null +++ b/library/Director/DirectorObject/ObjectPurgeHelper.php @@ -0,0 +1,149 @@ +<?php + +namespace Icinga\Module\Director\DirectorObject; + +use Icinga\Module\Director\Db; +use Icinga\Module\Director\Objects\IcingaObject; +use InvalidArgumentException; + +class ObjectPurgeHelper +{ + protected $db; + + protected $force = false; + + public function __construct(Db $db) + { + $this->db = $db; + } + + public function force($force = true) + { + $this->force = $force; + return $this; + } + + public function purge(array $keep, $class, $objectType = null) + { + if (empty($keep) && ! $this->force) { + throw new InvalidArgumentException('I will NOT purge all object unless being forced to do so'); + } + $db = $this->db->getDbAdapter(); + /** @var IcingaObject $class cheating, it's a class name, not an object */ + $dummy = $class::create(); + assert($dummy instanceof IcingaObject); + $keyCols = (array) $dummy->getKeyName(); + if ($objectType !== null) { + $keyCols[] = 'object_type'; + } + + $keepKeys = []; + foreach ($keep as $object) { + if ($object instanceof \stdClass) { + $properties = (array) $object; + // TODO: this is object-specific and to be found in the ::import() function! + unset($properties['fields']); + $object = $class::fromPlainObject($properties); + } elseif (\get_class($object) !== $class) { + throw new InvalidArgumentException( + 'Can keep only matching objects, expected "%s", got "%s', + $class, + \get_class($keep) + ); + } + $key = []; + foreach ($keyCols as $col) { + $key[$col] = $object->get($col); + } + $keepKeys[$this->makeRowKey($key)] = true; + } + + $query = $db->select()->from(['o' => $dummy->getTableName()], $keyCols); + if ($objectType !== null) { + $query->where('object_type = ?', $objectType); + } + $allExisting = []; + foreach ($db->fetchAll($query) as $row) { + $allExisting[$this->makeRowKey($row)] = $row; + } + $remove = []; + foreach ($allExisting as $key => $keyProperties) { + if (! isset($keepKeys[$key])) { + $remove[] = $keyProperties; + } + } + $db->beginTransaction(); + foreach ($remove as $keyProperties) { + $keyColumn = $class::getKeyColumnName(); + if (is_array($keyColumn)) { + $object = $class::load((array) $keyProperties, $this->db); + } else { + $object = $class::load($keyProperties->$keyColumn, $this->db); + } + $object->delete(); + } + $db->commit(); + } + + public static function listObjectTypesAvailableForPurge() + { + return [ + 'Basket', + 'Command', + 'CommandTemplate', + 'Dependency', + 'DirectorJob', + 'ExternalCommand', + 'HostGroup', + 'HostTemplate', + 'IcingaTemplateChoiceHost', + 'IcingaTemplateChoiceService', + 'ImportSource', + 'Notification', + 'NotificationTemplate', + 'ServiceGroup', + 'ServiceSet', + 'ServiceTemplate', + 'SyncRule', + 'TimePeriod', + ]; + } + + public static function objectTypeIsEligibleForPurge($type) + { + return in_array($type, static::listObjectTypesAvailableForPurge(), true); + } + + public static function assertObjectTypesAreEligibleForPurge($types) + { + $invalid = []; + foreach ($types as $type) { + if (! static::objectTypeIsEligibleForPurge($type)) { + $invalid[] = $type; + } + } + + if (empty($invalid)) { + return; + } + + if (count($invalid) === 1) { + $message = sprintf('"%s" is not eligible for purge', $invalid[0]); + } else { + $message = 'The following types are not eligible for purge: ' + . implode(', ', $invalid); + } + + throw new InvalidArgumentException( + "$message. Valid types: " + . implode(', ', static::listObjectTypesAvailableForPurge()) + ); + } + + protected function makeRowKey($row) + { + $row = (array) $row; + ksort($row); + return json_encode($row, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } +} |