MDNodaHelpers/src/Sync/NodaSourceFulltextSync.php

168 lines
4.6 KiB
PHP

<?PHP
/**
* Contains a class for keeping the source fulltext index in sync.
*
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/
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<string>
*/
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;
}
}