150 lines
4.4 KiB
PHP
150 lines
4.4 KiB
PHP
<?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);
|
|
}
|
|
}
|