From c84e3401ff3f60848c03a311f3aadfbb4ab25b71 Mon Sep 17 00:00:00 2001 From: Joshua Ramon Enslin Date: Thu, 6 May 2021 23:24:43 +0200 Subject: [PATCH] Add classes for keeping the fulltext (search) tables in sync --- src/NodaPersinstFulltextSync.php | 162 ++++++++++++++++++++++++++++++ src/NodaPlaceFulltextSync.php | 163 ++++++++++++++++++++++++++++++ src/NodaSourceFulltextSync.php | 167 +++++++++++++++++++++++++++++++ src/NodaTagFulltextSync.php | 163 ++++++++++++++++++++++++++++++ src/NodaTimeFulltextSync.php | 163 ++++++++++++++++++++++++++++++ 5 files changed, 818 insertions(+) create mode 100644 src/NodaPersinstFulltextSync.php create mode 100644 src/NodaPlaceFulltextSync.php create mode 100644 src/NodaSourceFulltextSync.php create mode 100644 src/NodaTagFulltextSync.php create mode 100644 src/NodaTimeFulltextSync.php diff --git a/src/NodaPersinstFulltextSync.php b/src/NodaPersinstFulltextSync.php new file mode 100644 index 0000000..d985ecc --- /dev/null +++ b/src/NodaPersinstFulltextSync.php @@ -0,0 +1,162 @@ + + */ +declare(strict_types = 1); + +/** + * Class for keeping the persinst fulltext index in sync. + */ +final class NodaPersinstFulltextSync { + + /** @var MDMysqli */ + private MDMysqli $_mysqli_noda; + + /** + * Removes the obsolete entries. + * + * @return void + */ + public function removeObsolete():void { + + $result = $this->_mysqli_noda->do_read_query("SELECT 1 + FROM `persinst_fulltext` + WHERE `persinst_fulltext`.`persinst_id` NOT IN (SELECT `persinst`.`persinst_id` FROM `persinst`) + LIMIT 1"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return; + } + $result->close(); + $result = null; + + $this->_mysqli_noda->do_update_query_large("DELETE FROM `persinst_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `persinst` + WHERE `persinst`.`persinst_id` = `persinst_fulltext`.`persinst_id`)"); + + } + + /** + * Gets the entries to update. + * + * @return array + */ + public function getNewEntries():array { + + $result = $this->_mysqli_noda->do_read_query("SELECT `persinst_id`, + `persinst_anzeigename`, `persinst_name` + FROM `persinst` + WHERE NOT EXISTS (SELECT 1 + FROM `persinst_fulltext` + WHERE `persinst`.`persinst_id` = `persinst_fulltext`.`persinst_id` + AND `persinst`.`persinst_erfasst_am` <= `persinst_fulltext`.`update_timestamp`) + LIMIT 10000"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return []; + } + + $toUpdate = []; + + while ($cur = $result->fetch_assoc()) { + $persinst_id = (int)$cur['persinst_id']; + unset($cur['persinst_id']); + $toUpdate[$persinst_id] = $cur; + } + $result->close(); + $result = null; + + $tlResult = $this->_mysqli_noda->do_read_query("SELECT `persinst_translation`.`persinst_id`, `trans_name` AS `name` + FROM `persinst_translation` + WHERE `persinst_translation`.`persinst_id` IN (" . implode(', ', array_keys($toUpdate)) . ")"); + + $translations = []; + while ($cur = $tlResult->fetch_assoc()) { + $persinst_id = (int)$cur['persinst_id']; + if (empty($translations[$persinst_id])) { + $translations[$persinst_id] = [$cur['name']]; + } + else $translations[$persinst_id][] = $cur['name']; + } + $tlResult->close(); + $tlResult = null; + + $newEntries = []; + + foreach ($toUpdate as $persinst_id => $values) { + if (isset($translations[$persinst_id])) $values = array_merge($values, $translations[$persinst_id]); + $newEntries[$persinst_id] = implode(' ', array_unique($values)); + } + + return $newEntries; + + } + + /** + * Loads the list of entries to update. + * + * @return void + */ + public function update():void { + + if (empty($toUpdate = $this->getNewEntries())) { + return; + } + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->autocommit(false); + } + + $updateStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `persinst_fulltext` + (`persinst_id`, `content`, `update_timestamp`) + VALUES + (?, ?, NOW()) + ON DUPLICATE KEY UPDATE `content` = ?, + `update_timestamp` = NOW()"); + + foreach ($toUpdate as $key => $value) { + $updateStmt->bind_param("iss", $key, $value, $value); + $updateStmt->execute(); + } + + $updateStmt->close(); + $updateStmt = null; + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->commit(); + $this->_mysqli_noda->autocommit(true); + } + + } + + /** + * Sync: Wrapper function glueing together the sync process. + * + * @return void + */ + public function sync():void { + + $this->removeObsolete(); + $this->update(); + + } + + /** + * Constructor. + * + * @param MDMysqli $mysqli_noda DB connection. + * + * @return void + */ + public function __construct(MDMysqli $mysqli_noda) { + + $this->_mysqli_noda = $mysqli_noda; + + } +} diff --git a/src/NodaPlaceFulltextSync.php b/src/NodaPlaceFulltextSync.php new file mode 100644 index 0000000..d6ec332 --- /dev/null +++ b/src/NodaPlaceFulltextSync.php @@ -0,0 +1,163 @@ + + */ +declare(strict_types = 1); + +/** + * Class for keeping the places fulltext index in sync. + */ +final class NodaPlaceFulltextSync { + + /** @var MDMysqli */ + private MDMysqli $_mysqli_noda; + + /** + * Removes the obsolete entries. + * + * @return void + */ + public function removeObsolete():void { + + $result = $this->_mysqli_noda->do_read_query("SELECT 1 + FROM `orte_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `orte` + WHERE `orte`.`ort_id` = `orte_fulltext`.`ort_id`) + LIMIT 1"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return; + } + $result->close(); + $result = null; + + $this->_mysqli_noda->do_update_query_large("DELETE FROM `orte_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `orte` + WHERE `orte`.`ort_id` = `orte_fulltext`.`ort_id`)"); + + } + + /** + * Gets the entries to update. + * + * @return array + */ + public function getNewEntries():array { + + $result = $this->_mysqli_noda->do_read_query("SELECT `ort_id`, + `ort_name` + FROM `orte` + WHERE NOT EXISTS (SELECT 1 + FROM `orte_fulltext` + WHERE `orte`.`ort_id` = `orte_fulltext`.`ort_id` + AND `orte`.`ort_erfasst_am` <= `orte_fulltext`.`update_timestamp`) + LIMIT 10000"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return []; + } + + $toUpdate = []; + + while ($cur = $result->fetch_assoc()) { + $ort_id = (int)$cur['ort_id']; + unset($cur['ort_id']); + $toUpdate[$ort_id] = $cur; + } + $result->close(); + $result = null; + + $tlResult = $this->_mysqli_noda->do_read_query("SELECT `ort_translation`.`ort_id`, `trans_name` AS `name` + FROM `ort_translation` + WHERE `ort_translation`.`ort_id` IN (" . implode(', ', array_keys($toUpdate)) . ")"); + + $translations = []; + while ($cur = $tlResult->fetch_assoc()) { + $ort_id = (int)$cur['ort_id']; + if (empty($translations[$ort_id])) { + $translations[$ort_id] = [$cur['name']]; + } + else $translations[$ort_id][] = $cur['name']; + } + $tlResult->close(); + $tlResult = null; + + $newEntries = []; + + foreach ($toUpdate as $ort_id => $values) { + if (isset($translations[$ort_id])) $values = array_merge($values, $translations[$ort_id]); + $newEntries[$ort_id] = implode(' ', array_unique($values)); + } + + return $newEntries; + + } + + /** + * Loads the list of entries to update. + * + * @return void + */ + public function update():void { + + if (empty($toUpdate = $this->getNewEntries())) { + return; + } + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->autocommit(false); + } + + $updateStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `orte_fulltext` + (`ort_id`, `content`, `update_timestamp`) + VALUES + (?, ?, NOW()) + ON DUPLICATE KEY UPDATE `content` = ?, + `update_timestamp` = NOW()"); + + foreach ($toUpdate as $key => $value) { + $updateStmt->bind_param("iss", $key, $value, $value); + $updateStmt->execute(); + } + + $updateStmt->close(); + $updateStmt = null; + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->commit(); + $this->_mysqli_noda->autocommit(true); + } + + } + + /** + * Sync: Wrapper function glueing together the sync process. + * + * @return void + */ + public function sync():void { + + $this->removeObsolete(); + $this->update(); + + } + + /** + * Constructor. + * + * @param MDMysqli $mysqli_noda DB connection. + * + * @return void + */ + public function __construct(MDMysqli $mysqli_noda) { + + $this->_mysqli_noda = $mysqli_noda; + + } +} diff --git a/src/NodaSourceFulltextSync.php b/src/NodaSourceFulltextSync.php new file mode 100644 index 0000000..6ebe905 --- /dev/null +++ b/src/NodaSourceFulltextSync.php @@ -0,0 +1,167 @@ + + */ +declare(strict_types = 1); + +/** + * Class for keeping the source fulltext index in sync. + */ +final class NodaSourceFulltextSync { + + /** @var MDMysqli */ + private MDMysqli $_mysqli_noda; + + /** + * Removes the obsolete entries. + * + * @return void + */ + public function removeObsolete():void { + + $result = $this->_mysqli_noda->do_read_query("SELECT 1 + FROM `source_fulltext_search` + WHERE NOT EXISTS (SELECT 1 FROM `source` + WHERE `source`.`source_id` = `source_fulltext_search`.`source_id`) + LIMIT 1"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return; + } + $result->close(); + $result = null; + + $this->_mysqli_noda->do_update_query_large("DELETE FROM `source_fulltext_search` + WHERE NOT EXISTS (SELECT 1 FROM `source` + WHERE `source`.`source_id` = `source_fulltext_search`.`source_id`)"); + + } + + /** + * Gets the entries to update. + * + * @return array + */ + public function getNewEntries():array { + + $result = $this->_mysqli_noda->do_read_query("SELECT `source_id`, + `source_title`, `source_year`, `source_booktitle`, `source_venue`, + `source_volume`, `source_issue`, `source_pages`, `source_url`, + `source_doi`, `source_isbn`, `source_license` + FROM `source` + WHERE NOT EXISTS (SELECT 1 + FROM `source_fulltext_search` + WHERE `source`.`source_id` = `source_fulltext_search`.`source_id` + AND `source`.`source_update_timestamp` <= `source_fulltext_search`.`update_timestamp`)"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return []; + } + + $toUpdate = []; + + while ($cur = $result->fetch_assoc()) { + $cur['authors'] = ""; + $source_id = (int)$cur['source_id']; + unset($cur['source_id']); + $toUpdate[$source_id] = $cur; + } + $result->close(); + $result = null; + + $authorsResult = $this->_mysqli_noda->do_read_query("SELECT `source_author`.`source_id`, `persinst_anzeigename` AS `name` + FROM `persinst`, `source_author` + WHERE `source_author`.`author_id` = `persinst`.`persinst_id` + AND `source_author`.`source_id` IN (" . implode(', ', array_keys($toUpdate)) . ")"); + + $authors = []; + while ($cur = $authorsResult->fetch_assoc()) { + $source_id = (int)$cur['source_id']; + if (empty($authors[$source_id])) { + $authors[$source_id] = [$cur['name']]; + } + else $authors[$source_id][] = $cur['name']; + } + $authorsResult->close(); + $authorsResult = null; + + $newEntries = []; + + foreach ($toUpdate as $source_id => $values) { + $cur = implode(' ', $values); + if (!empty($authors[$source_id])) $cur .= ' ' . implode(' ', array_unique($authors[$source_id])); + $newEntries[$source_id] = $cur; + } + + return $newEntries; + + } + + /** + * Loads the list of entries to update. + * + * @return void + */ + public function update():void { + + if (empty($toUpdate = $this->getNewEntries())) { + return; + } + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->autocommit(false); + } + + $updateStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `source_fulltext_search` + (`source_id`, `content`, `update_timestamp`) + VALUES + (?, ?, NOW()) + ON DUPLICATE KEY UPDATE `content` = ?, + `update_timestamp` = NOW()"); + + foreach ($toUpdate as $key => $value) { + $updateStmt->bind_param("iss", $key, $value, $value); + $updateStmt->execute(); + } + + $updateStmt->close(); + $updateStmt = null; + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->commit(); + $this->_mysqli_noda->autocommit(true); + } + + } + + /** + * Sync: Wrapper function glueing together the sync process. + * + * @return void + */ + public function sync():void { + + $this->removeObsolete(); + $this->update(); + + } + + /** + * Constructor. + * + * @param MDMysqli $mysqli_noda DB connection. + * + * @return void + */ + public function __construct(MDMysqli $mysqli_noda) { + + $this->_mysqli_noda = $mysqli_noda; + + } +} diff --git a/src/NodaTagFulltextSync.php b/src/NodaTagFulltextSync.php new file mode 100644 index 0000000..311cf6c --- /dev/null +++ b/src/NodaTagFulltextSync.php @@ -0,0 +1,163 @@ + + */ +declare(strict_types = 1); + +/** + * Class for keeping the tags fulltext index in sync. + */ +final class NodaTagFulltextSync { + + /** @var MDMysqli */ + private MDMysqli $_mysqli_noda; + + /** + * Removes the obsolete entries. + * + * @return void + */ + public function removeObsolete():void { + + $result = $this->_mysqli_noda->do_read_query("SELECT 1 + FROM `tag_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `tag` + WHERE `tag`.`tag_id` = `tag_fulltext`.`tag_id`) + LIMIT 1"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return; + } + $result->close(); + $result = null; + + $this->_mysqli_noda->do_update_query_large("DELETE FROM `tag_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `tag` + WHERE `tag`.`tag_id` = `tag_fulltext`.`tag_id`)"); + + } + + /** + * Gets the entries to update. + * + * @return array + */ + public function getNewEntries():array { + + $result = $this->_mysqli_noda->do_read_query("SELECT `tag_id`, + `tag_name` + FROM `tag` + WHERE NOT EXISTS (SELECT 1 + FROM `tag_fulltext` + WHERE `tag`.`tag_id` = `tag_fulltext`.`tag_id` + AND `tag`.`tag_erfasst_am` <= `tag_fulltext`.`update_timestamp`) + LIMIT 10000"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return []; + } + + $toUpdate = []; + + while ($cur = $result->fetch_assoc()) { + $tag_id = (int)$cur['tag_id']; + unset($cur['tag_id']); + $toUpdate[$tag_id] = $cur; + } + $result->close(); + $result = null; + + $tlResult = $this->_mysqli_noda->do_read_query("SELECT `tag_translation`.`tag_id`, `trans_name` AS `name` + FROM `tag_translation` + WHERE `tag_translation`.`tag_id` IN (" . implode(', ', array_keys($toUpdate)) . ")"); + + $translations = []; + while ($cur = $tlResult->fetch_assoc()) { + $tag_id = (int)$cur['tag_id']; + if (empty($translations[$tag_id])) { + $translations[$tag_id] = [$cur['name']]; + } + else $translations[$tag_id][] = $cur['name']; + } + $tlResult->close(); + $tlResult = null; + + $newEntries = []; + + foreach ($toUpdate as $tag_id => $values) { + if (isset($translations[$tag_id])) $values = array_merge($values, $translations[$tag_id]); + $newEntries[$tag_id] = implode(' ', array_unique($values)); + } + + return $newEntries; + + } + + /** + * Loads the list of entries to update. + * + * @return void + */ + public function update():void { + + if (empty($toUpdate = $this->getNewEntries())) { + return; + } + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->autocommit(false); + } + + $updateStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `tag_fulltext` + (`tag_id`, `content`, `update_timestamp`) + VALUES + (?, ?, NOW()) + ON DUPLICATE KEY UPDATE `content` = ?, + `update_timestamp` = NOW()"); + + foreach ($toUpdate as $key => $value) { + $updateStmt->bind_param("iss", $key, $value, $value); + $updateStmt->execute(); + } + + $updateStmt->close(); + $updateStmt = null; + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->commit(); + $this->_mysqli_noda->autocommit(true); + } + + } + + /** + * Sync: Wrapper function glueing together the sync process. + * + * @return void + */ + public function sync():void { + + $this->removeObsolete(); + $this->update(); + + } + + /** + * Constructor. + * + * @param MDMysqli $mysqli_noda DB connection. + * + * @return void + */ + public function __construct(MDMysqli $mysqli_noda) { + + $this->_mysqli_noda = $mysqli_noda; + + } +} diff --git a/src/NodaTimeFulltextSync.php b/src/NodaTimeFulltextSync.php new file mode 100644 index 0000000..4cdfb5e --- /dev/null +++ b/src/NodaTimeFulltextSync.php @@ -0,0 +1,163 @@ + + */ +declare(strict_types = 1); + +/** + * Class for keeping the times fulltext index in sync. + */ +final class NodaTimeFulltextSync { + + /** @var MDMysqli */ + private MDMysqli $_mysqli_noda; + + /** + * Removes the obsolete entries. + * + * @return void + */ + public function removeObsolete():void { + + $result = $this->_mysqli_noda->do_read_query("SELECT 1 + FROM `zeiten_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `zeiten` + WHERE `zeiten`.`zeit_id` = `zeiten_fulltext`.`zeit_id`) + LIMIT 1"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return; + } + $result->close(); + $result = null; + + $this->_mysqli_noda->do_update_query_large("DELETE FROM `zeiten_fulltext` + WHERE NOT EXISTS (SELECT 1 FROM `zeiten` + WHERE `zeiten`.`zeit_id` = `zeiten_fulltext`.`zeit_id`)"); + + } + + /** + * Gets the entries to update. + * + * @return array + */ + public function getNewEntries():array { + + $result = $this->_mysqli_noda->do_read_query("SELECT `zeit_id`, + `zeit_name` + FROM `zeiten` + WHERE NOT EXISTS (SELECT 1 + FROM `zeiten_fulltext` + WHERE `zeiten`.`zeit_id` = `zeiten_fulltext`.`zeit_id` + AND `zeiten`.`zeit_erfasst_am` <= `zeiten_fulltext`.`update_timestamp`) + LIMIT 10000"); + + if ($result->num_rows === 0) { + $result->close(); + $result = null; + return []; + } + + $toUpdate = []; + + while ($cur = $result->fetch_assoc()) { + $zeit_id = (int)$cur['zeit_id']; + unset($cur['zeit_id']); + $toUpdate[$zeit_id] = $cur; + } + $result->close(); + $result = null; + + $tlResult = $this->_mysqli_noda->do_read_query("SELECT `zeit_translation`.`zeit_id`, `trans_name` AS `name` + FROM `zeit_translation` + WHERE `zeit_translation`.`zeit_id` IN (" . implode(', ', array_keys($toUpdate)) . ")"); + + $translations = []; + while ($cur = $tlResult->fetch_assoc()) { + $time_id = (int)$cur['zeit_id']; + if (empty($translations[$time_id])) { + $translations[$time_id] = [$cur['name']]; + } + else $translations[$time_id][] = $cur['name']; + } + $tlResult->close(); + $tlResult = null; + + $newEntries = []; + + foreach ($toUpdate as $zeit_id => $values) { + if (isset($translations[$zeit_id])) $values = array_merge($values, $translations[$zeit_id]); + $newEntries[$zeit_id] = implode(' ', array_unique($values)); + } + + return $newEntries; + + } + + /** + * Loads the list of entries to update. + * + * @return void + */ + public function update():void { + + if (empty($toUpdate = $this->getNewEntries())) { + return; + } + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->autocommit(false); + } + + $updateStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `zeiten_fulltext` + (`zeit_id`, `content`, `update_timestamp`) + VALUES + (?, ?, NOW()) + ON DUPLICATE KEY UPDATE `content` = ?, + `update_timestamp` = NOW()"); + + foreach ($toUpdate as $key => $value) { + $updateStmt->bind_param("iss", $key, $value, $value); + $updateStmt->execute(); + } + + $updateStmt->close(); + $updateStmt = null; + + if (count($toUpdate) > 1) { + $this->_mysqli_noda->commit(); + $this->_mysqli_noda->autocommit(true); + } + + } + + /** + * Sync: Wrapper function glueing together the sync process. + * + * @return void + */ + public function sync():void { + + $this->removeObsolete(); + $this->update(); + + } + + /** + * Constructor. + * + * @param MDMysqli $mysqli_noda DB connection. + * + * @return void + */ + public function __construct(MDMysqli $mysqli_noda) { + + $this->_mysqli_noda = $mysqli_noda; + + } +}