mytinytodo/src/ext/backup/class.check.php
2023-09-10 23:31:40 +03:00

126 lines
4.4 KiB
PHP

<?php declare(strict_types=1);
/*
This file is a part of myTinyTodo.
(C) Copyright 2023 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
namespace BackupExtension;
use DBConnection;
class Check
{
public $lastErrorString = null;
public $report = '';
function check(): bool
{
$db = DBConnection::instance();
$msg = [];
// Task without list
$count = $db->sq("SELECT COUNT(*) FROM {$db->prefix}todolist WHERE list_id NOT IN (SELECT id FROM {$db->prefix}lists)");
if ($count) {
$msg[] = "Tasks without list: $count";
}
// Tag without task (not a broblem)
$count = $db->sq("SELECT COUNT(*) FROM {$db->prefix}tags WHERE id NOT IN (SELECT tag_id FROM {$db->prefix}tag2task)");
if ($count) {
$msg[] = "Tags without task: $count";
}
// tag2task no list
$count = $db->sq("SELECT COUNT(*) FROM {$db->prefix}tag2task WHERE list_id NOT IN (SELECT id FROM {$db->prefix}lists)");
if ($count) {
$msg[] = "tag2task no list: $count";
}
// tag2task no tag
$count = $db->sq("SELECT COUNT(*) FROM {$db->prefix}tag2task WHERE tag_id NOT IN (SELECT id FROM {$db->prefix}tags)");
if ($count) {
$msg[] = "tag2task no tag: $count";
}
// tag2task no task
$count = $db->sq("SELECT COUNT(*) FROM {$db->prefix}tag2task WHERE task_id NOT IN (SELECT id FROM {$db->prefix}todolist)");
if ($count) {
$msg[] = "tag2task no task: $count";
}
$count = 0;
$uniqTag = []; // lowerTag => [id, tag]
$nonuniqTag = []; // id => [tag, lowerTag, uniqId, uniqTag, taskCount]
$q = $db->dq("SELECT id,name,COUNT(task_id) c FROM {$db->prefix}tags t LEFT JOIN {$db->prefix}tag2task tt ON t.id=tt.tag_id GROUP BY id ORDER BY id");
while ($r = $q->fetchAssoc()) {
$v = mb_strtolower((string)$r['name'], 'UTF-8');
if (!isset($uniqTag[$v])) {
$uniqTag[$v] = [$r['id'], $r['name']];
}
else {
$count++;
$nonuniqTag[$r['id']] = [$r['name'], $v, $uniqTag[$v][0], $uniqTag[$v][1], $r['c']];
}
}
if ($count > 0) {
$msg[] = "Non-unique tags: $count";
foreach ($nonuniqTag as $id => $a) {
$msg[] = " ID:{$id} Tag:{$a[0]} (tasks: {$a[4]}) same as ID:{$a[2]} Tag:{$a[3]}";
}
}
if (count($msg) == 0) {
$msg[] = "OK";
}
$this->report = implode("\n", $msg);
return true;
}
function repair(): bool
{
$db = DBConnection::instance();
$db->ex("BEGIN");
// Task without list
$count = (int)$db->sq("SELECT COUNT(*) FROM {$db->prefix}todolist WHERE list_id NOT IN (SELECT id FROM {$db->prefix}lists)");
if ($count > 0) {
// Move to new list
$listID = \DBCore::default()->createListWithName("Restored tasks");
$db->ex("UPDATE {$db->prefix}todolist SET list_id=? WHERE list_id NOT IN (SELECT id FROM {$db->prefix}lists)", [$listID]);
}
//Tags
$db->ex("DELETE FROM {$db->prefix}tags WHERE id NOT IN (SELECT tag_id FROM {$db->prefix}tag2task)");
$db->ex("DELETE FROM {$db->prefix}tag2task WHERE task_id NOT IN (SELECT id FROM {$db->prefix}todolist)");
$db->ex("DELETE FROM {$db->prefix}tag2task WHERE tag_id NOT IN (SELECT id FROM {$db->prefix}tags)");
//Non-unique tags replace with first unique
$uniqTag = [];
$replace = [];
$q = $db->dq("SELECT id,name FROM {$db->prefix}tags t LEFT JOIN {$db->prefix}tag2task tt ON t.id=tt.tag_id GROUP BY id ORDER BY id");
while ($r = $q->fetchAssoc()) {
$v = mb_strtolower((string)$r['name'], 'UTF-8');
if (!isset($uniqTag[$v])) {
$uniqTag[$v] = $r['id'];
}
else {
$replace[$r['id']] = $uniqTag[$v];
}
}
foreach ($replace as $id => $newId) {
$db->ex("UPDATE {$db->prefix}tag2task SET tag_id=? WHERE tag_id=?", [$newId, $id]);
}
$db->ex("DELETE FROM {$db->prefix}tags WHERE id NOT IN (SELECT tag_id FROM {$db->prefix}tag2task)");
// TODO: tag2task no list ?
$db->ex("COMMIT");
return true;
}
}