';
exit;
}
}
else {
$updatePersinstStmt->bind_param("si", $datafromwiki, $persinst_id);
$updatePersinstStmt->execute();
$output = true;
}
$updatePersinstStmt->close();
// Update edit metadata
$updatePersinstEditInfoStmt = $this->_mysqli_noda->do_prepare("UPDATE `persinst`
SET `persinst_erfasst_am` = NOW(),
`persinst_erfasst_von` = ?
WHERE `persinst_id` = ?");
$updatePersinstEditInfoStmt->bind_param("si", $erfasst_von, $persinst_id);
$updatePersinstEditInfoStmt->execute();
$updatePersinstEditInfoStmt->close();
return $output;
}
/**
* Function for updating birth and death times based on Wikidata information.
*
* @param array $data Data loaded from Wikidata.
* @param integer $persinst_id Actor ID.
*
* @return void
*/
public function enterPersinstBirthDeathDatesFromWikidata(array $data, int $persinst_id):void {
$result = $this->_mysqli_noda->query_by_stmt("SELECT `persinst_geburtsjahr`,
`persinst_sterbejahr`, `persinst_gender`
FROM `persinst`
WHERE `persinst_id` = ?", "i", $persinst_id);
if (!($actor_dates = $result->fetch_assoc())) {
throw new MDmainEntityNotExistentException("Failed to fetch actor information");
}
$result->close();
if ($actor_dates['persinst_geburtsjahr'] === '') {
// Try to get birth date
if (!empty($data['claims']['P569'])
and !empty($data['claims']['P569']['0']['mainsnak']['datavalue']['value']['time'])
// Ignore entries with century / very inprecise birth dates
and (empty($data['claims']['P569']['0']['mainsnak']['datavalue']['value']['precision']) || (int)$data['claims']['P569']['0']['mainsnak']['datavalue']['value']['precision'] !== 7)
) {
$birth_date = self::wikidataBirthDeathToYear($data['claims']['P569']['0']['mainsnak']['datavalue']['value']['time']);
}
if (!empty($birth_date)) {
$updateStmt = $this->_mysqli_noda->do_prepare("UPDATE `persinst`
SET `persinst_geburtsjahr` = ?
WHERE `persinst_id` = ?
LIMIT 1");
$updateStmt->bind_param("ii", $birth_date, $persinst_id);
$updateStmt->execute();
$updateStmt->close();
}
}
if ($actor_dates['persinst_sterbejahr'] === '') {
// Try to get birth date
if (!empty($data['claims']['P570']) and !empty($data['claims']['P570']['0']['mainsnak']['datavalue']['value']['time'])) {
$death_date = self::wikidataBirthDeathToYear($data['claims']['P570']['0']['mainsnak']['datavalue']['value']['time']);
}
if (!empty($death_date)) {
$updateStmt = $this->_mysqli_noda->do_prepare("UPDATE `persinst`
SET `persinst_sterbejahr` = ?
WHERE `persinst_id` = ?
LIMIT 1");
$updateStmt->bind_param("ii", $death_date, $persinst_id);
$updateStmt->execute();
$updateStmt->close();
}
}
if ($actor_dates['persinst_gender'] === '') {
// Try to get birth date
if (!empty($data['claims']['P21']) and !empty($data['claims']['P21']['0']['mainsnak']['datavalue']['value']['id'])) {
$wikidata_gender_id = $data['claims']['P21']['0']['mainsnak']['datavalue']['value']['id'];
switch ($wikidata_gender_id) {
case "Q6581097": // male
case "Q44148": // male organism
case "Q2449503": // transgender man
$wikidata_gender = "male";
break;
case "Q6581072":
case "Q1052281": // transgender female
case "Q43445": // female organism
$wikidata_gender = "female";
break;
case "Q48270":
$wikidata_gender = "other";
break;
default:
throw new Exception("Unknown gender: Q-ID is " . $wikidata_gender_id);
}
}
if (!empty($wikidata_gender)) {
$updateStmt = $this->_mysqli_noda->do_prepare("UPDATE `persinst`
SET `persinst_gender` = ?
WHERE `persinst_id` = ?
LIMIT 1");
$updateStmt->bind_param("si", $wikidata_gender, $persinst_id);
$updateStmt->execute();
$updateStmt->close();
}
}
}
/**
* Function for retrieving information.
*
* @param string $lang The user's selected used language.
* @param string $wikidata_id Wikidata ID.
* @param integer $persinst_id Actor ID.
* @param string $erfasst_von User name who's currently editing.
*
* @return void
*/
public function retrievePersinstInfoFromWikidataID(string $lang, string $wikidata_id, int $persinst_id, string $erfasst_von) {
self::validateWikidataId($wikidata_id);
$data = json_decode(MD_STD::runCurl("https://www.wikidata.org/wiki/Special:EntityData/" . $wikidata_id . ".json", 10000), true);
if ($data === null) {
throw new MDhttpFailedException("Failed fetching from Wikidata. Try again later.");
}
$data = $data['entities'][$wikidata_id];
// Get links to wikipedia
$wikilink = $wikilinkterm = [];
foreach (self::LANGUAGES_MAIN_DESC as $tLang) {
if (isset($data['sitelinks'][$tLang . 'wiki']['url'])) $wikilink[$tLang] = $data['sitelinks'][$tLang . 'wiki']['url'];
if (isset($data['sitelinks'][$tLang . 'wiki']['title'])) $wikilinkterm[$tLang] = str_replace(' ', '_', $data['sitelinks'][$tLang . 'wiki']['title']);
}
$alreadyEntered = false;
if (isset($wikilink[$lang]) and isset($wikilinkterm[$lang]) and is_string($wikilinkterm[$lang])) {
$datafromwiki = MD_STD::runCurl(self::_getWikipediaApiLink($lang, $wikilinkterm[$lang]), 10000);
$datafromwiki = json_decode($datafromwiki, true)['parse']['text']['*'];
# Process data retrieved from wikipedia
if (!empty($datafromwiki = self::_cleanWikidataInput((string)$datafromwiki))) {
$alreadyEntered = $this->retrievePersinstDescFromWikipedia($persinst_id, $wikidata_id, $datafromwiki, $wikilink[$lang], $lang, $lang, $erfasst_von);
}
}
foreach (self::LANGUAGES_MAIN_DESC as $cur_lang) {
if ($alreadyEntered === true) break;
if (!isset($wikilink[$cur_lang]) || !isset($wikilinkterm[$cur_lang]) || !is_string($wikilinkterm[$cur_lang])) continue;
$datafromwiki = MD_STD::runCurl(self::_getWikipediaApiLink($cur_lang, $wikilinkterm[$cur_lang]), 10000);
$datafromwiki = json_decode($datafromwiki, true)['parse']['text']['*'];
# Process data retrieved from wikipedia
if ($datafromwiki = self::_cleanWikidataInput((string)$datafromwiki)) {
$alreadyEntered = $this->retrievePersinstDescFromWikipedia($persinst_id, $wikidata_id, $datafromwiki, $wikilink[$cur_lang], $lang, "$cur_lang", $erfasst_von);
}
}
$this->enterPersinstBirthDeathDatesFromWikidata($data, $persinst_id);
// Get links to other norm data sources
$nodaLinks = [
new MDNodaLink(MDNodaRepository::wikidata, $wikidata_id)
];
foreach (self::P_IDS_NODA_TAGS as $vocabName => $pId) {
if (isset($data['claims'][$pId])) {
if (empty($data['claims'][$pId][0]['mainsnak']['datavalue'])) continue;
$url = $data['claims'][$pId][0]['mainsnak']['datavalue']['value'];
if ($vocabName === 'loc' || ($vocabName === 'lcsh')) {
$vocabName = $this->_determineLocRefMode($url);
if (empty($vocabName)) continue;
}
if (!in_array($vocabName, MDNodaRepositoriesSet::REPOSITORIES_ACTOR, true)) continue;
$nodaLinks[] = new MDNodaLink(MDNodaRepository::fromString($vocabName), $url);
}
}
// GET links to other noda entries.
NodaBatchInserter::linkNodaForPersinst($this->_mysqli_noda, $persinst_id, $nodaLinks, $erfasst_von);
$this->getWikidataTranslationsForPersinst($data, $persinst_id);
NodaLogEdit::logPersinstEdit($this->_mysqli_noda, $persinst_id, "wikidata-fetcher", $erfasst_von, 'update', 'synchronize');
}
/**
* Function for fetching translations from Wikipedia, based on Wikidata information.
*
* @param array $data Entity fetched from wikidata.
* @param integer $persinst_id Actor ID.
* @param string[] $checkForLangs Languages to check for. Defaults to all
* languages generally loaded by the wikidata fetcher.
*
* @return void
*/
public function getWikidataTranslationsForPersinst(array $data, int $persinst_id, array $checkForLangs = self::LANGUAGES_TO_CHECK):void {
if (empty($translations = self::listTranslationsFromWikidataWikipedia($checkForLangs, $data))) {
return;
}
$toInsert = [];
foreach ($translations as $lang => $values) {
$toInsert[] = [
'persinst_id' => $persinst_id,
'lang' => $lang,
'name' => $values['label'],
'description' => $values['description'],
'link' => $values['link'],
];
}
NodaBatchInserter::insertPersinstTranslations($this->_mysqli_noda, $toInsert);
}
/**
* Returns the current description of a place.
*
* @param integer $onum Place ID.
*
* @return string
*/
private function getPlaceDescription(int $onum):string {
$currentPlaceResult = $this->_mysqli_noda->query_by_stmt("SELECT `ort_anmerkung`
FROM `orte`
WHERE `ort_id` = ?", "i", $onum);
if (!($curPlaceInfo = $currentPlaceResult->fetch_row())) {
$currentPlaceResult->close();
throw new Exception("This place does not exist");
}
$currentPlaceResult->close();
return $curPlaceInfo[0];
}
/**
* Returns the current description of a tag.
*
* @param integer $tag_id Tag ID.
*
* @return string
*/
private function getTagDescription(int $tag_id):string {
$result = $this->_mysqli_noda->query_by_stmt("SELECT `tag_anmerkung`
FROM `tag`
WHERE `tag_id` = ?", "i", $tag_id);
if (!($cur = $result->fetch_row())) {
$result->close();
return '';
}
$result->close();
return $cur[0];
}
/**
* Function for entering base information about a place from wikidata.
*
* @param string $cur_place_desc Mysqli result pointing to the current place.
* @param string $datafromwiki Data parsed from wikidata.
* @param array $wikilink Wikilink.
* @param string $preflang Language of the user interface in general.
* @param string $lang Language of the main entry.
* @param integer $placeID ID of the place.
* @param string $erfasst_von User name.
*
* @return boolean
*/
public function enterPlaceDescFromWikidata(string $cur_place_desc, string $datafromwiki, array $wikilink, string $preflang, string $lang, int $placeID, string $erfasst_von):bool {
$datafromwiki = '"' . $datafromwiki . '" - (Wikipedia (' . $lang . ') ' . date("d.m.Y") . ')';
if (!empty(trim($cur_place_desc)) and substr($cur_place_desc, 0, 3) !== 'GND') {
switch ($this->_retrievalMode) {
case "add":
$datafromwiki = $cur_place_desc . PHP_EOL . PHP_EOL . $datafromwiki;
break;
case "keep":
$datafromwiki = $cur_place_desc;
break;
case "replace":
break;
default:
$tlLoader = new MDTlLoader("wiki_getter_place", $preflang);
echo self::generateHTMLHeadForWikidataFetcher($lang);
echo self::generateWikidataFetcherHeader($tlLoader);
echo '
';
return $output;
}
/**
* Function for generating a wikidata results list.
*
* @param string $link Links.
* @param string $searchTerm Search term.
* @param string $lang Language.
*
* @return string
*/
public static function generateWikidataResultsList(string $link, string $searchTerm, string $lang):string {
if (empty($wikidata_data = self::searchWikidataForString($searchTerm))) {
return '
' . ucfirst($searchTerm) . ' not found in Wikidata
';
}
$output = '
';
foreach ($wikidata_data as $result) {
$output .= self::generateWikidataResultsListEntry($link, $searchTerm, $lang, $result);
}
$output .= '
';
return $output;
}
/**
* Attempts to parse birth or death years from the data returned by wikidata.
*
* @param string $inputTime Input time in the format delivered by wikidata.
*
* @return string
*/
public static function wikidataBirthDeathToYear(string $inputTime):string {
$birth_date_int = strtotime(substr($inputTime, 1, 4));
if ($birth_date_int) {
$birth_date = date("Y", $birth_date_int);
if ($birth_date === date("Y") and ($tTime = strtotime($inputTime)) !== false) {
$birth_date = date("Y", $tTime);
}
return $birth_date;
}
return '';
}
/**
* Function for generating a wikidata results list for actors, keeping track of life dates.
*
* @param string $link Links.
* @param string $searchTerm Search term.
* @param string $lang Language.
* @param integer $yearOfBirth Year of birth.
* @param integer $yearOfDeath Year of death.
*
* @return string
*/
public static function generateWikidataResultsListForActors(string $link, string $searchTerm, string $lang, int $yearOfBirth, int $yearOfDeath):string {
if (empty($wikidata_data = self::searchWikidataForString($searchTerm))) {
return '
' . ucfirst($searchTerm) . ' not found in Wikidata
';
}
$qLinksToCheck = [];
foreach ($wikidata_data as $entry) {
$qLinksToCheck[$entry['id']] = "https://www.wikidata.org/wiki/Special:EntityData/" . $entry['id'] . ".json";
}
$fetched = MD_STD::runCurlMulti($qLinksToCheck, 10000);
$yearsOfBirthList = $yearsOfDeathList = [];
foreach ($fetched as $qId => $data) {
if (!($jsonData = json_decode($data, true))) {
continue;
}
if (empty($jsonData['entities'][$qId])) {
continue;
}
$data = $jsonData['entities'][$qId];
if (!empty($data['claims']['P569']) and !empty($data['claims']['P569']['0']['mainsnak']['datavalue']['value']['time'])) {
$yearsOfBirthList[$qId] = (int)self::wikidataBirthDeathToYear($data['claims']['P569']['0']['mainsnak']['datavalue']['value']['time']);
}
if (!empty($data['claims']['P570']) and !empty($data['claims']['P570']['0']['mainsnak']['datavalue']['value']['time'])) {
$yearsOfDeathList[$qId] = (int)self::wikidataBirthDeathToYear($data['claims']['P570']['0']['mainsnak']['datavalue']['value']['time']);
}
}
$output = '
';
foreach ($wikidata_data as $result) {
if (empty($result['id'])) continue;
if (!empty($yearsOfBirthList[$result['id']])) {
if (empty($result['description'])) {
$result['description'] = 'Born: ' . $yearsOfBirthList[$result['id']];
}
else $result['description'] .= ' Born: ' . $yearsOfBirthList[$result['id']];
}
if (!empty($yearsOfDeathList[$result['id']])) {
if (empty($result['description'])) {
$result['description'] = 'Death: ' . $yearsOfDeathList[$result['id']];
}
else $result['description'] .= ' Death: ' . $yearsOfDeathList[$result['id']];
}
if (!empty($yearsOfBirthList[$result['id']]) && !empty($yearsOfDeathList[$result['id']])) {
if ($yearsOfBirthList[$result['id']] === $yearOfBirth
&& $yearsOfDeathList[$result['id']] === $yearOfDeath
) {
$result['description'] .= ' Suggestion!';
}
}
$output .= self::generateWikidataResultsListEntry($link, $searchTerm, $lang, $result);
}
$output .= '
';
return $output;
}
/**
* Function generates HTML head for wikidata fetchers.
*
* @param string $lang User language.
* @param boolean $implyEnd If set to true, the end string will be echoed at the end of the script execution.
*
* @return string
*/
public static function generateHTMLHeadForWikidataFetcher(string $lang, bool $implyEnd = true):string {
$output = "
Get Wikidata
";
if (defined("MAIN_CSS_FILE")) {
$output .= "";
}
$output .= "
";
if ($implyEnd === true) {
register_shutdown_function(function() :void {
echo printHTMLEnd();
});
}
return MD_STD::minimizeHTMLString($output);
}
/**
* Function generate header for wikidata fetcher pages.
*
* @param MDTlLoader $tlLoader Translation variable.
* @param string $additional Additional info.
* @param string $searchTerm Search term.
*
* @return string
*/
public static function generateWikidataFetcherHeader(MDTlLoader $tlLoader, string $additional = "", string $searchTerm = ""):string {
if (empty($searchTerm) and !empty($_GET['suchbegriff'])) {
$searchTerm = (string)$_GET['suchbegriff'];
}
$output = '