Compare commits
82 Commits
6af51323e7
...
master
Author | SHA1 | Date | |
---|---|---|---|
119f216907 | |||
25668b7b16
|
|||
8a31cf216e
|
|||
ff474341ed
|
|||
1051e10732
|
|||
057cac0f1b
|
|||
0053fbe030
|
|||
7a2856ffad
|
|||
00638152cf
|
|||
dba60dbce6
|
|||
f84fe1bca5
|
|||
423959ac94
|
|||
e8edb4a459
|
|||
8491b62a83
|
|||
bb2b1c2c32
|
|||
5054d3c62f
|
|||
beba838c0d
|
|||
54dd958073
|
|||
5b99304b5c
|
|||
5cce98f15b
|
|||
5036c77f32
|
|||
e95415be8f
|
|||
5192781494
|
|||
d9d9f7fcdc
|
|||
dbfa0df17f
|
|||
3409ec7afe
|
|||
27ac3f255a
|
|||
9d7d53a858
|
|||
28f6db67ff
|
|||
2f3bc5f2fa
|
|||
39362f537a | |||
de0357473a
|
|||
ef43270fb2
|
|||
338e09f001
|
|||
4cf9eaf4fa
|
|||
18438251a7
|
|||
1cf0f9858a
|
|||
1d50027809
|
|||
d1cee17ef5
|
|||
baf7905e0b
|
|||
9bf14d7d91
|
|||
a621534136
|
|||
51fe9a5e45
|
|||
9c2eaa2929
|
|||
546c17031a
|
|||
bf22f5541d
|
|||
e036d7881a
|
|||
d8db941485
|
|||
b7bb7364d4
|
|||
4dcd93b947
|
|||
c72ad51dda | |||
d6dea3e280
|
|||
6f7ad13c4e
|
|||
48355a6a36
|
|||
7cfe752c94
|
|||
29ca05f552
|
|||
eb371d4270
|
|||
16f36c0852
|
|||
669a8a1459
|
|||
a9c506497c
|
|||
06f13c1a71
|
|||
cd49f194f2
|
|||
9b63a4d95d
|
|||
96ba020514
|
|||
c650e57eda
|
|||
dea09b17cd
|
|||
cc0997f412
|
|||
f18e4c3edc
|
|||
f220a77ad7
|
|||
58d3569718
|
|||
27528c9cf7
|
|||
205e77da0e
|
|||
f36938b8dd
|
|||
cfa9cee60d
|
|||
83a557b989
|
|||
7f342ed3c4 | |||
7d303e219f
|
|||
ce480f8b9f
|
|||
eb14615917
|
|||
bd775bec45
|
|||
2cdfa2e948 | |||
81a7d64e27
|
@ -13,7 +13,7 @@ final class NodaBlacklistedTerms {
|
||||
/**
|
||||
* A blacklist of disallowed tags. All entries are listed in full lowercase.
|
||||
*/
|
||||
const TAG_BLACKLIST = [
|
||||
public const TAG_BLACKLIST = [
|
||||
'de' => [
|
||||
'andere',
|
||||
'anderes',
|
||||
@ -33,16 +33,35 @@ final class NodaBlacklistedTerms {
|
||||
'ding',
|
||||
'dinge',
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'nichtmünzliches',
|
||||
'unbestimmt',
|
||||
'AA',
|
||||
'BB',
|
||||
'CC',
|
||||
'DD',
|
||||
'EE',
|
||||
'FF',
|
||||
'GG',
|
||||
'HH',
|
||||
'LL',
|
||||
'-',
|
||||
'?',
|
||||
],
|
||||
'en' => [
|
||||
'other',
|
||||
'others',
|
||||
'unknown',
|
||||
'various',
|
||||
'-',
|
||||
'?',
|
||||
],
|
||||
'hu' => [
|
||||
'ism.',
|
||||
'ismeretlen',
|
||||
'-',
|
||||
'?',
|
||||
],
|
||||
];
|
||||
|
||||
|
@ -10,7 +10,6 @@ declare(strict_types = 1);
|
||||
* Abstract class to be inherited by classes for writing consolidated vocabulary names.
|
||||
*/
|
||||
abstract class NodaConsolidatedNamesAbstract {
|
||||
|
||||
/**
|
||||
* This function sanitizes a string.
|
||||
*
|
||||
|
@ -79,17 +79,18 @@ final class NodaConsolidatedNamesForPersinst extends NodaConsolidatedNamesAbstra
|
||||
if (count($parts) !== 2) return [];
|
||||
|
||||
$nameOnly = trim($parts[0]);
|
||||
$dateString = rtrim($parts[1], ')'); //
|
||||
$dateString = trim(rtrim($parts[1], ')')); //
|
||||
|
||||
if (!empty($dates = NodaTimeSplitter::is_timespan($dateString))
|
||||
&& $dates[0] !== '?'
|
||||
&& $dates[1] !== '?'
|
||||
&& intval($dates[1]) - intval($dates[0]) < 150
|
||||
&& $dates->start_year !== '?'
|
||||
&& $dates->end_year !== '?'
|
||||
&& $dates->start_year !== $dates->end_year
|
||||
&& intval($dates->end_year) - intval($dates->start_year) < 150
|
||||
) {
|
||||
return [
|
||||
'name' => $nameOnly,
|
||||
'birth' => $dates[0],
|
||||
'death' => $dates[1],
|
||||
'birth' => $dates->start_year,
|
||||
'death' => $dates->end_year,
|
||||
];
|
||||
}
|
||||
|
||||
@ -120,5 +121,4 @@ final class NodaConsolidatedNamesForPersinst extends NodaConsolidatedNamesAbstra
|
||||
return \trim($name, " ;.\t" . PHP_EOL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ final class NodaConsolidatedNamesForPlaces extends NodaConsolidatedNamesAbstract
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function _rewrite_narrower_broader_pairs_to_brackets(string $name, string $indicator, $separator = ', '):string {
|
||||
private static function _rewrite_narrower_broader_pairs_to_brackets(string $name, string $indicator, string $separator = ', '):string {
|
||||
|
||||
if (str_contains($name, $indicator)
|
||||
&& substr_count($name, $indicator) === 1
|
||||
@ -105,8 +105,7 @@ final class NodaConsolidatedNamesForPlaces extends NodaConsolidatedNamesAbstract
|
||||
|
||||
// Skip entries like "Vaci utca 12 Budapest, Vaci utca"
|
||||
$indicatorTrimmed = trim($indicator);
|
||||
if (
|
||||
(str_ends_with($parts[0], $indicatorTrimmed) && str_contains($parts[1], $indicatorTrimmed))
|
||||
if ((str_ends_with($parts[0], $indicatorTrimmed) && str_contains($parts[1], $indicatorTrimmed))
|
||||
|| (str_ends_with($parts[1], $indicatorTrimmed) && str_contains($parts[0], $indicatorTrimmed))
|
||||
) {
|
||||
return $name;
|
||||
@ -133,10 +132,8 @@ final class NodaConsolidatedNamesForPlaces extends NodaConsolidatedNamesAbstract
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $name;
|
||||
|
||||
}
|
||||
@ -226,7 +223,7 @@ final class NodaConsolidatedNamesForPlaces extends NodaConsolidatedNamesAbstract
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function _rewrite_ukrainian_names_by_hierarchy($name):string {
|
||||
private static function _rewrite_ukrainian_names_by_hierarchy(string $name):string {
|
||||
|
||||
$identifiersByLevel = [
|
||||
'state' => [' РСР', 'РСР ', ' АРСР', 'АРСР ', ' губернія', 'губернія '],
|
||||
@ -328,13 +325,14 @@ final class NodaConsolidatedNamesForPlaces extends NodaConsolidatedNamesAbstract
|
||||
}
|
||||
|
||||
$output = $main_name;
|
||||
if (!empty($specifiers)) $output .= ' (' . implode(', ', $specifiers) . ')';
|
||||
if (!empty($specifiers)) {
|
||||
$output .= ' (' . implode(', ', $specifiers) . ')';
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans and consolidates name parts appearing regularly in Ukrainian place names.
|
||||
*
|
||||
@ -427,15 +425,12 @@ final class NodaConsolidatedNamesForPlaces extends NodaConsolidatedNamesAbstract
|
||||
|
||||
// If one of the parts is a blacklisted term or a cardinal directions, skip this
|
||||
|
||||
if (
|
||||
(in_array($parts[0], self::_COUNTRY_REWRITE_BLACKLISTED_TERMS, true)
|
||||
|| in_array($parts[0], $cardinal_directions, true)
|
||||
|| in_array(strtolower($parts[0]), $cardinal_directions, true)
|
||||
)
|
||||
if ((in_array($parts[0], self::_COUNTRY_REWRITE_BLACKLISTED_TERMS, true)
|
||||
|| in_array($parts[0], $cardinal_directions, true)
|
||||
|| in_array(strtolower($parts[0]), $cardinal_directions, true))
|
||||
|| (in_array($parts[1], self::_COUNTRY_REWRITE_BLACKLISTED_TERMS, true)
|
||||
|| in_array($parts[1], $cardinal_directions, true)
|
||||
|| in_array(strtolower($parts[1]), $cardinal_directions, true)
|
||||
)
|
||||
|| in_array($parts[1], $cardinal_directions, true)
|
||||
|| in_array(strtolower($parts[1]), $cardinal_directions, true))
|
||||
) {
|
||||
return $name;
|
||||
}
|
||||
|
74
src/NodaCountingTimeIndicator.php
Normal file
74
src/NodaCountingTimeIndicator.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Represents a time indicator (CE / BCE).
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* Represents a time indicator (CE / BCE).
|
||||
*/
|
||||
enum NodaCountingTimeIndicator implements JsonSerializable {
|
||||
|
||||
case ce;
|
||||
case bce;
|
||||
|
||||
/**
|
||||
* Returns a value of this type based on a string.
|
||||
*
|
||||
* @param string $input Input to get a value from.
|
||||
*
|
||||
* @return NodaCountingTimeIndicator
|
||||
*/
|
||||
public static function fromString(string $input):NodaCountingTimeIndicator {
|
||||
|
||||
return match($input) {
|
||||
'+' => self::ce,
|
||||
'-' => self::bce,
|
||||
'ce' => self::ce,
|
||||
'bce' => self::bce,
|
||||
default => throw new MDpageParameterNotFromListException("Unknown counting time indicator (bc / bce)"),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a canonical string representation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toString():string {
|
||||
|
||||
return match($this) {
|
||||
self::ce => '+',
|
||||
self::bce => '-',
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a canonical string representation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toGerman():string {
|
||||
|
||||
return match($this) {
|
||||
self::ce => ' n. Chr.',
|
||||
self::bce => ' v. Chr.',
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the option to serialize as a string during json_encode().
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function jsonSerialize():string {
|
||||
|
||||
return $this->toString();
|
||||
|
||||
}
|
||||
}
|
@ -10,7 +10,6 @@ declare(strict_types = 1);
|
||||
* contains a string.
|
||||
*/
|
||||
final class NodaDistinctlyTypedStrings {
|
||||
|
||||
/**
|
||||
* Checks the vocabulary database whether it contains a given string.
|
||||
*
|
||||
@ -40,5 +39,4 @@ final class NodaDistinctlyTypedStrings {
|
||||
return $cur[0];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,6 +44,32 @@ final class NodaGroup {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns basic description of a group.
|
||||
*
|
||||
* @param integer $group_id Group ID.
|
||||
*
|
||||
* @return array{name: string, comment: string}
|
||||
*/
|
||||
public function getDescription(int $group_id):array {
|
||||
|
||||
$result = $this->_mysqli_noda->query_by_stmt("SELECT `group_name`, `comment`
|
||||
FROM `group`
|
||||
WHERE `group_id` = ?", "i", $group_id);
|
||||
|
||||
if (!($cur = $result->fetch_row())) {
|
||||
$result->close();
|
||||
throw new MDmainEntityNotExistentException("This group does not seem to exist");
|
||||
}
|
||||
$result->close();
|
||||
|
||||
return [
|
||||
'name' => $cur[0],
|
||||
'comment' => $cur[1],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a group.
|
||||
*
|
||||
@ -54,6 +80,10 @@ final class NodaGroup {
|
||||
*/
|
||||
public function insert(string $name, string $comment = ''):int {
|
||||
|
||||
if (empty($name)) {
|
||||
throw new MDpageParameterMissingException("Name cannot be empty when adding groups.");
|
||||
}
|
||||
|
||||
$insertStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `group`
|
||||
(`group_name`, `comment`)
|
||||
VALUES
|
||||
@ -68,6 +98,55 @@ final class NodaGroup {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a group.
|
||||
*
|
||||
* @param integer $group_id ID of the group to update.
|
||||
* @param string $name Name of the group.
|
||||
* @param string $comment Optional: Comment for the group.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update(int $group_id, string $name, string $comment = ''):void {
|
||||
|
||||
if (empty($name)) {
|
||||
throw new MDpageParameterMissingException("Name cannot be empty when adding groups.");
|
||||
}
|
||||
|
||||
$insertStmt = $this->_mysqli_noda->do_prepare("UPDATE `group`
|
||||
SET `group_name` = ?,
|
||||
`comment` = ?
|
||||
WHERE `group_id` = ?");
|
||||
|
||||
$insertStmt->bind_param("ssi", $name, $comment, $group_id);
|
||||
$insertStmt->execute();
|
||||
$insertStmt->close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a group.
|
||||
*
|
||||
* @param integer $group_id ID of the group to delete.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete(int $group_id):void {
|
||||
|
||||
$this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_persinst`
|
||||
WHERE `group_id` = ?", "i", $group_id);
|
||||
$this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_orte`
|
||||
WHERE `group_id` = ?", "i", $group_id);
|
||||
$this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_zeiten`
|
||||
WHERE `group_id` = ?", "i", $group_id);
|
||||
$this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_tag`
|
||||
WHERE `group_id` = ?", "i", $group_id);
|
||||
|
||||
$this->_mysqli_noda->update_query_by_stmt("DELETE FROM `group`
|
||||
WHERE `group_id` = ?", "i", $group_id);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds actors to a nodac group.
|
||||
*
|
||||
|
@ -10,6 +10,30 @@ declare(strict_types = 1);
|
||||
* Contains static functions for getting IDs for noda entries by various means.
|
||||
*/
|
||||
final class NodaIDGetter {
|
||||
/**
|
||||
* Comparison operation that allows for equality but also returns true
|
||||
* if capitalization differs. If diacritics are available in one case
|
||||
* and not in the other, there will be no match.
|
||||
* This is needed to identify sufficiently exact matches despite a table
|
||||
* collation of *_ci in MySQL.
|
||||
*
|
||||
* @param string $string_one First string in comparison.
|
||||
* @param string $string_two Second string in comparison.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function _stri_matches(string $string_one, string $string_two):bool {
|
||||
|
||||
if ($string_one === $string_two) {
|
||||
return true;
|
||||
}
|
||||
if (\strtolower($string_one) === \strtolower($string_two)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Actors
|
||||
@ -80,21 +104,22 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$persinstRewriteResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`, `input_name`
|
||||
FROM `persinst_rewriting`
|
||||
WHERE `language` = ?
|
||||
AND `input_name` = ?
|
||||
LIMIT 1", "ss", $lang, $name);
|
||||
|
||||
if ($persinstRewriteData = $persinstRewriteResult->fetch_row()) {
|
||||
$output = $persinstRewriteData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$persinstRewriteResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -111,21 +136,53 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$persinstByTLNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`, `trans_name`
|
||||
FROM `persinst_translation`
|
||||
WHERE `trans_name` = ?
|
||||
AND `trans_language` = ?
|
||||
LIMIT 2", "ss", $name, $lang);
|
||||
|
||||
if ($persinstByTlData = $persinstByTLNameResult->fetch_row()) {
|
||||
$output = $persinstByTlData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$persinstByTLNameResult->close();
|
||||
return 0;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns persinst ID by entry in persinst translations table,
|
||||
* irrespective of language.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Database connection.
|
||||
* @param string $name Name of the persinst to search for.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getPersinstIDByAnyTransName(MDMysqli $mysqli_noda, string $name):int {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`, `trans_name`
|
||||
FROM `persinst_translation`
|
||||
WHERE `trans_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
$result->close();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -145,8 +202,8 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$persinstByTLNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_translation`.`persinst_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_translation`.`persinst_id`, `trans_name`
|
||||
FROM `persinst_translation`, `persinst`
|
||||
WHERE `persinst_translation`.`persinst_id` = `persinst`.`persinst_id`
|
||||
AND `trans_name` = ?
|
||||
@ -155,14 +212,15 @@ final class NodaIDGetter {
|
||||
AND `persinst_sterbejahr` = ?
|
||||
LIMIT 2", "ssss", $name, $lang, $birth, $death);
|
||||
|
||||
if ($persinstByTlData = $persinstByTLNameResult->fetch_row()) {
|
||||
$output = $persinstByTlData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$persinstByTLNameResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -178,22 +236,23 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$persinstByBaseNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`, `persinst_anzeigename`, `persinst_name`, CONCAT(`persinst_name`, ' (', `persinst_geburtsjahr`, '-', `persinst_sterbejahr`, ')')
|
||||
FROM `persinst`
|
||||
WHERE `persinst_anzeigename` = ?
|
||||
OR `persinst_name` = ?
|
||||
OR CONCAT(`persinst_name`, ' (', `persinst_geburtsjahr`, '-', `persinst_sterbejahr`, ')') = ?
|
||||
LIMIT 2", "sss", $name, $name, $name);
|
||||
|
||||
if ($persinstByBaseData = $persinstByBaseNameResult->fetch_row()) {
|
||||
$output = $persinstByBaseData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name) || self::_stri_matches($cur[2], $name) || self::_stri_matches($cur[3], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$persinstByBaseNameResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -211,8 +270,8 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$persinstByBaseNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`, `persinst_anzeigename`, `persinst_name`, CONCAT(`persinst_name`, ' (', `persinst_geburtsjahr`, '-', `persinst_sterbejahr`, ')')
|
||||
FROM `persinst`
|
||||
WHERE (
|
||||
`persinst_anzeigename` = ?
|
||||
@ -223,14 +282,15 @@ final class NodaIDGetter {
|
||||
AND `persinst_sterbejahr` = ?
|
||||
LIMIT 2", "sssss", $name, $name, $name, $birth, $death);
|
||||
|
||||
if ($persinstByBaseData = $persinstByBaseNameResult->fetch_row()) {
|
||||
$output = $persinstByBaseData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name) || self::_stri_matches($cur[2], $name) || self::_stri_matches($cur[3], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$persinstByBaseNameResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -284,22 +344,23 @@ final class NodaIDGetter {
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$lookUpName = $name . $birthYear . $deathYear;
|
||||
$persinstByImportLogResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `persinst_id`, `input_string`
|
||||
FROM `persinst_logged_imports`
|
||||
WHERE `instance` = ?
|
||||
AND `institution_id` = ?
|
||||
AND `input_string` = ?
|
||||
LIMIT 2", "sis", $instance, $institution_id, $lookUpName);
|
||||
|
||||
if ($persinstByImportLogData = $persinstByImportLogResult->fetch_row()) {
|
||||
$output = $persinstByImportLogData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $lookUpName)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$persinstByImportLogResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -345,21 +406,22 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$placeRewriteResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`, `input_name`
|
||||
FROM `ort_rewriting`
|
||||
WHERE `language` = ?
|
||||
AND `input_name` = ?
|
||||
LIMIT 1", "ss", $lang, $name);
|
||||
|
||||
if ($placeRewriteData = $placeRewriteResult->fetch_row()) {
|
||||
$output = $placeRewriteData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$placeRewriteResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -375,20 +437,21 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$placeByBaseNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`, `ort_name`
|
||||
FROM `orte`
|
||||
WHERE `ort_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
if ($placeByBaseData = $placeByBaseNameResult->fetch_row()) {
|
||||
$output = $placeByBaseData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$placeByBaseNameResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -405,21 +468,53 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$placeByTLNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`, `trans_name`
|
||||
FROM `ort_translation`
|
||||
WHERE `trans_name` = ?
|
||||
AND `trans_language` = ?
|
||||
LIMIT 2", "ss", $name, $lang);
|
||||
|
||||
if ($placeByTlData = $placeByTLNameResult->fetch_row()) {
|
||||
$output = $placeByTlData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$placeByTLNameResult->close();
|
||||
return 0;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns place ID by entry in place translations table, irrespective of
|
||||
* language.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Database connection.
|
||||
* @param string $name Name of the place to search for.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getPlaceIDByAnyTransName(MDMysqli $mysqli_noda, string $name):int {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`, `trans_name`
|
||||
FROM `ort_translation`
|
||||
WHERE `trans_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
$result->close();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -470,22 +565,23 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$placeByImportLogResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `ort_id`, `input_string`
|
||||
FROM `orte_logged_imports`
|
||||
WHERE `instance` = ?
|
||||
AND `institution_id` = ?
|
||||
AND `input_string` = ?
|
||||
LIMIT 2", "sis", $instance, $institution_id, $name);
|
||||
|
||||
if ($placeByImportLogData = $placeByImportLogResult->fetch_row()) {
|
||||
$output = $placeByImportLogData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($cur[1], $name)) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$placeByImportLogResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -533,17 +629,19 @@ final class NodaIDGetter {
|
||||
|
||||
$output = [];
|
||||
|
||||
$tagRewriteResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`, `input_name`
|
||||
FROM `tag_rewriting`
|
||||
WHERE `tag_language` = ?
|
||||
AND `input_name` = ?", "ss", $lang, $name);
|
||||
|
||||
while ($tagRewriteData = $tagRewriteResult->fetch_row()) {
|
||||
$output[] = $tagRewriteData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$output[] = $cur[0];
|
||||
}
|
||||
}
|
||||
|
||||
$tagRewriteResult->close();
|
||||
$result->close();
|
||||
|
||||
return $output;
|
||||
|
||||
@ -561,20 +659,21 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$tagByBaseNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`, `tag_name`
|
||||
FROM `tag`
|
||||
WHERE `tag_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
if ($tagByBaseData = $tagByBaseNameResult->fetch_row()) {
|
||||
$output = $tagByBaseData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$tagByBaseNameResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -591,21 +690,53 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$tagByTLNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`, `trans_name`
|
||||
FROM `tag_translation`
|
||||
WHERE `trans_name` = ?
|
||||
AND `trans_language` = ?
|
||||
LIMIT 2", "ss", $name, $lang);
|
||||
|
||||
if ($tagByTlData = $tagByTLNameResult->fetch_row()) {
|
||||
$output = $tagByTlData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$tagByTLNameResult->close();
|
||||
return 0;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tag ID by entry in tag translations table,
|
||||
* irrespective of language.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Database connection.
|
||||
* @param string $name Name of the tag to search for.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getTagIDByAnyTransName(MDMysqli $mysqli_noda, string $name):int {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`, `trans_name`
|
||||
FROM `tag_translation`
|
||||
WHERE `trans_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
$result->close();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -656,22 +787,23 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$tagByImportLogResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `tag_id`, `input_string`
|
||||
FROM `tag_logged_imports`
|
||||
WHERE `instance` = ?
|
||||
AND `institution_id` = ?
|
||||
AND `input_string` = ?
|
||||
LIMIT 2", "sis", $instance, $institution_id, $name);
|
||||
|
||||
if ($tagByImportLogData = $tagByImportLogResult->fetch_row()) {
|
||||
$output = $tagByImportLogData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$tagByImportLogResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -719,20 +851,21 @@ final class NodaIDGetter {
|
||||
|
||||
$output = [];
|
||||
|
||||
$timeRewriteResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`, `input_name`
|
||||
FROM `zeit_rewriting`
|
||||
WHERE `language` = ?
|
||||
AND `input_name` = ?", "ss", $lang, $name);
|
||||
|
||||
if ($timeRewriteData = $timeRewriteResult->fetch_row()) {
|
||||
$output = (int)$timeRewriteData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$timeRewriteResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -748,20 +881,21 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$timeByBaseNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`, `zeit_name`
|
||||
FROM `zeiten`
|
||||
WHERE `zeit_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
if ($timeByBaseData = $timeByBaseNameResult->fetch_row()) {
|
||||
$output = $timeByBaseData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$timeByBaseNameResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -778,21 +912,52 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$timeByTLNameResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`, `trans_name`
|
||||
FROM `zeit_translation`
|
||||
WHERE `trans_name` = ?
|
||||
AND `trans_language` = ?
|
||||
LIMIT 2", "ss", $name, $lang);
|
||||
|
||||
if ($timeByTlData = $timeByTLNameResult->fetch_row()) {
|
||||
$output = $timeByTlData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$timeByTLNameResult->close();
|
||||
return 0;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time ID by entry in time translations table.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Database connection.
|
||||
* @param string $name Name of the time to search for.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getTimeIDByAnyTransName(MDMysqli $mysqli_noda, string $name):int {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`, `trans_name`
|
||||
FROM `zeit_translation`
|
||||
WHERE `trans_name` = ?
|
||||
LIMIT 2", "s", $name);
|
||||
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
$result->close();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -810,22 +975,23 @@ final class NodaIDGetter {
|
||||
|
||||
if (empty($name)) return 0;
|
||||
|
||||
$timeByImportLogResult = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`
|
||||
$result = $mysqli_noda->query_by_stmt("
|
||||
SELECT `zeit_id`, `input_string`
|
||||
FROM `zeiten_logged_imports`
|
||||
WHERE `instance` = ?
|
||||
AND `institution_id` = ?
|
||||
AND `input_string` = ?
|
||||
LIMIT 2", "sis", $instance, $institution_id, $name);
|
||||
|
||||
if ($timeByImportLogData = $timeByImportLogResult->fetch_row()) {
|
||||
$output = $timeByImportLogData[0];
|
||||
while ($cur = $result->fetch_row()) {
|
||||
if (self::_stri_matches($name, $cur[1])) {
|
||||
$result->close();
|
||||
return (int)$cur[0];
|
||||
}
|
||||
}
|
||||
else $output = 0;
|
||||
$result->close();
|
||||
|
||||
$timeByImportLogResult->close();
|
||||
|
||||
return $output;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@ -956,4 +1122,79 @@ final class NodaIDGetter {
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks each string in a list of strings for its existence as a tag name.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Database connection.
|
||||
* @param string $lang Language to check in.
|
||||
* @param non-empty-array<string> $phrases List of phrases to check.
|
||||
*
|
||||
* @return array{count: int, tag: integer[], actor: integer[], time: integer[], place: integer[]}
|
||||
*/
|
||||
public static function searchEntryNamesByList(MDMysqli $mysqli_noda, string $lang, array $phrases):array {
|
||||
|
||||
$output = [
|
||||
'count' => 0,
|
||||
'tag' => [],
|
||||
'actor' => [],
|
||||
'time' => [],
|
||||
'place' => [],
|
||||
];
|
||||
|
||||
foreach ($phrases as $phrase) {
|
||||
|
||||
if (($tag_id = NodaIDGetter::getTagIDByNamesAndRewrites($mysqli_noda, $lang, $phrase)) !== 0 && !in_array($tag_id, $output['tag'], true)) {
|
||||
$output['tag'][] = $tag_id;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($tag_id_by_tl = NodaIDGetter::getTagIDByAnyTransName($mysqli_noda, $phrase)) !== 0 && !in_array($tag_id_by_tl, $output['tag'], true)) {
|
||||
$output['tag'][] = $tag_id_by_tl;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($place_id = NodaIDGetter::getPlaceIDByNamesAndRewrites($mysqli_noda, $lang, $phrase)) !== 0 && !in_array($place_id, $output['place'], true)) {
|
||||
$output['place'][] = $place_id;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($place_id = NodaIDGetter::getPlaceIDByAnyTransName($mysqli_noda, $phrase)) !== 0 && !in_array($place_id, $output['place'], true)) {
|
||||
$output['place'][] = $place_id;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($persinst_id = NodaIDGetter::getPersinstIDByNamesAndRewrites($mysqli_noda, $lang, $phrase, '', '')) !== 0 && !in_array($persinst_id, $output['actor'], true)) {
|
||||
$output['actor'][] = $persinst_id;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($persinst_id = NodaIDGetter::getPersinstIDByAnyTransName($mysqli_noda, $phrase)) !== 0 && !in_array($persinst_id, $output['actor'], true)) {
|
||||
$output['actor'][] = $persinst_id;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($time_id = NodaIDGetter::getTimeIDByNamesAndRewrites($mysqli_noda, $lang, $phrase)) !== 0 && !in_array($time_id, $output['time'], true)) {
|
||||
$output['time'][] = $time_id;
|
||||
++$output['count'];
|
||||
}
|
||||
else if (($time_id = NodaIDGetter::getTimeIDByAnyTransName($mysqli_noda, $phrase)) !== 0 && !in_array($time_id, $output['time'], true)) {
|
||||
$output['time'][] = $time_id;
|
||||
++$output['count'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (count($phrases) !== $output['count']) {
|
||||
return [
|
||||
'count' => 0,
|
||||
'tag' => [],
|
||||
'actor' => [],
|
||||
'time' => [],
|
||||
'place' => [],
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($output['tag'])) sort($output['tag']);
|
||||
if (!empty($output['actor'])) sort($output['actor']);
|
||||
if (!empty($output['time'])) sort($output['time']);
|
||||
if (!empty($output['place'])) sort($output['place']);
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,12 @@ final class NodaImportLogger {
|
||||
$logStmt = $mysqli_noda->do_prepare("INSERT INTO `persinst_logged_imports`
|
||||
(`instance`, `institution_id`, `input_string`, `persinst_id`)
|
||||
VALUES (?, ?, ?, ?)");
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $loggedName, $persinst_id);
|
||||
$logStmt->execute();
|
||||
try {
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $loggedName, $persinst_id);
|
||||
$logStmt->execute();
|
||||
}
|
||||
catch (MDMysqliDuplicateKeysError $e) {
|
||||
}
|
||||
$logStmt->close();
|
||||
|
||||
}
|
||||
@ -54,8 +58,12 @@ final class NodaImportLogger {
|
||||
$logStmt = $mysqli_noda->do_prepare("INSERT INTO `orte_logged_imports`
|
||||
(`instance`, `institution_id`, `input_string`, `ort_id`)
|
||||
VALUES (?, ?, ?, ?)");
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $name, $ort_id);
|
||||
$logStmt->execute();
|
||||
try {
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $name, $ort_id);
|
||||
$logStmt->execute();
|
||||
}
|
||||
catch (MDMysqliDuplicateKeysError $e) {
|
||||
}
|
||||
$logStmt->close();
|
||||
|
||||
}
|
||||
@ -76,8 +84,12 @@ final class NodaImportLogger {
|
||||
$logStmt = $mysqli_noda->do_prepare("INSERT INTO `zeiten_logged_imports`
|
||||
(`instance`, `institution_id`, `input_string`, `zeit_id`)
|
||||
VALUES (?, ?, ?, ?)");
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $name, $zeit_id);
|
||||
$logStmt->execute();
|
||||
try {
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $name, $zeit_id);
|
||||
$logStmt->execute();
|
||||
}
|
||||
catch (MDMysqliDuplicateKeysError $e) {
|
||||
}
|
||||
$logStmt->close();
|
||||
|
||||
}
|
||||
@ -98,8 +110,12 @@ final class NodaImportLogger {
|
||||
$logStmt = $mysqli_noda->do_prepare("INSERT INTO `tag_logged_imports`
|
||||
(`instance`, `institution_id`, `input_string`, `tag_id`)
|
||||
VALUES (?, ?, ?, ?)");
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $name, $tag_id);
|
||||
$logStmt->execute();
|
||||
try {
|
||||
$logStmt->bind_param("sisi", $instance, $institution_id, $name, $tag_id);
|
||||
$logStmt->execute();
|
||||
}
|
||||
catch (MDMysqliDuplicateKeysError $e) {
|
||||
}
|
||||
$logStmt->close();
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ final class NodaLogEdit {
|
||||
|
||||
const SECTION_WHITELIST = [
|
||||
'base',
|
||||
'addition',
|
||||
'noda_link',
|
||||
'name_variant',
|
||||
'logged_import_concordances',
|
||||
|
@ -107,4 +107,26 @@ final class NodaMailChecker {
|
||||
return self::validateMailDomainAccessibilityCached($mysqli, $domain);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates mail address, throwing an exception if the mail address is not valid.
|
||||
*
|
||||
* @param MDMysqli $mysqli DB connection.
|
||||
* @param string $mail_address Address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function validateMail(MDMysqli $mysqli, string $mail_address):string {
|
||||
|
||||
if (empty($mail_address)) return $mail_address;
|
||||
|
||||
$mail_address = MD_STD_IN::sanitize_email($mail_address);
|
||||
|
||||
if (self::validateMailByDomainAccessibilityCached($mysqli, $mail_address) === false) {
|
||||
throw new MDInvalidEmail("The host name of the entered mail address is invalid");
|
||||
}
|
||||
|
||||
return $mail_address;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +143,54 @@ final class NodaNameGetter {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function for getting persinst names in bulk.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda DB connection.
|
||||
* @param string $lang Language.
|
||||
* @param array<integer> $persinst_ids Persinst IDs.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function getBatchPersinstNamesWithLifeDates(MDMysqli $mysqli_noda, string $lang, array $persinst_ids):array {
|
||||
|
||||
$output = [];
|
||||
|
||||
// Get translations
|
||||
$result = $mysqli_noda->do_read_query("SELECT `persinst`.`persinst_id`, `trans_name`, `persinst_geburtsjahr`, `persinst_sterbejahr`
|
||||
FROM `persinst_translation`, `persinst`
|
||||
WHERE `trans_language` = '" . $mysqli_noda->escape_string($lang) . "'
|
||||
AND `persinst`.`persinst_id` = `persinst_translation`.`persinst_id`
|
||||
AND `persinst`.`persinst_id` IN (" . implode(', ', $persinst_ids) . ")");
|
||||
|
||||
while ($cur = $result->fetch_row()) {
|
||||
$name = (string)$cur[1];
|
||||
if (!empty($cur[2]) || !empty($cur[3])) {
|
||||
$name .= ' (' . $cur[2] . '-' . $cur[3] . ')';
|
||||
}
|
||||
$output[(int)$cur[0]] = $name;
|
||||
}
|
||||
$result->close();
|
||||
|
||||
if (!empty($persinst_ids_left = array_diff($persinst_ids, array_keys($output)))) {
|
||||
$result = $mysqli_noda->do_read_query("SELECT `persinst_id`, `persinst_anzeigename`
|
||||
FROM `persinst`
|
||||
WHERE `persinst_id` IN (" . implode(', ', $persinst_ids_left) . ")");
|
||||
|
||||
while ($cur = $result->fetch_row()) {
|
||||
$output[(int)$cur[0]] = (string)$cur[1];
|
||||
}
|
||||
$result->close();
|
||||
}
|
||||
|
||||
if (count($output) > 1) {
|
||||
asort($output);
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function for getting time names in bulk.
|
||||
*
|
||||
|
407
src/NodaSplitTime.php
Normal file
407
src/NodaSplitTime.php
Normal file
@ -0,0 +1,407 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Describes a time after splitting / transfer object.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* Describes a time after splitting / transfer object.
|
||||
*/
|
||||
final class NodaSplitTime {
|
||||
|
||||
public const DEFAULT_DATE = '0001-01-01';
|
||||
|
||||
public readonly string $start_year;
|
||||
public readonly string $end_year;
|
||||
|
||||
public readonly string $counting_time_month;
|
||||
public readonly string $counting_time_day;
|
||||
|
||||
public readonly NodaCountingTimeIndicator $counting_time_indicator;
|
||||
public readonly NodaTimeBeforeAfterIndicator $before_after_indicator;
|
||||
|
||||
public string $start_date;
|
||||
public string $end_date;
|
||||
|
||||
/**
|
||||
* Returns a single, exact date.
|
||||
*
|
||||
* @param string $year Year.
|
||||
* @param string $month Month.
|
||||
* @param string $day Day.
|
||||
* @param NodaTimeBeforeAfterIndicator $before_after_indicator Determines if the time is exact or before / after.
|
||||
*
|
||||
* @return NodaSplitTime
|
||||
*/
|
||||
public static function genExactDate(string $year, string $month, string $day, NodaTimeBeforeAfterIndicator $before_after_indicator = NodaTimeBeforeAfterIndicator::none):NodaSplitTime {
|
||||
|
||||
$start_year = $end_year = $year;
|
||||
$start_date = $end_date = $year . '-' . $month . '-' . $day;
|
||||
|
||||
if ($before_after_indicator === NodaTimeBeforeAfterIndicator::before
|
||||
|| $before_after_indicator === NodaTimeBeforeAfterIndicator::until
|
||||
) {
|
||||
$start_year = $start_date = '?';
|
||||
}
|
||||
if ($before_after_indicator === NodaTimeBeforeAfterIndicator::after
|
||||
|| $before_after_indicator === NodaTimeBeforeAfterIndicator::since
|
||||
) {
|
||||
$end_year = $end_date = '?';
|
||||
}
|
||||
|
||||
return new NodaSplitTime($start_year, $end_year, $month, $day, start_date: $start_date, end_date: $end_date);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the entered start year.
|
||||
*
|
||||
* @param string $input Input to validate.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _validateStartYear(string $input):void {
|
||||
|
||||
if (strlen($input) > 6) {
|
||||
throw new MDgenericInvalidInputsException("Time statement longer than 6 characters is impossible");
|
||||
}
|
||||
|
||||
if (($this->before_after_indicator === NodaTimeBeforeAfterIndicator::before
|
||||
|| $this->before_after_indicator === NodaTimeBeforeAfterIndicator::until)
|
||||
&& $input !== '?'
|
||||
) {
|
||||
throw new MDgenericInvalidInputsException("Times with no certain start need to have a question mark (?) entered as a start date");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the entered end year.
|
||||
*
|
||||
* @param string $input Input to validate.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _validateEndYear(string $input):void {
|
||||
|
||||
if (strlen($input) > 6) {
|
||||
throw new MDgenericInvalidInputsException("Time statement longer than 6 characters is impossible");
|
||||
}
|
||||
|
||||
if (($this->before_after_indicator === NodaTimeBeforeAfterIndicator::after
|
||||
|| $this->before_after_indicator === NodaTimeBeforeAfterIndicator::since)
|
||||
&& $input !== '?'
|
||||
) {
|
||||
throw new MDgenericInvalidInputsException("Times with no certain end need to have a question mark (?) entered as a end date");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads to four digits. E.g. 2 > 02.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function pad_to_two(string $input):string {
|
||||
|
||||
return \substr("00" . $input, -2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the entered month string.
|
||||
*
|
||||
* @param string $input Input to validate.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _validateCountingTimeMonth(string $input):string {
|
||||
|
||||
if (strlen($input) > 2) throw new MDgenericInvalidInputsException("Input too long");
|
||||
|
||||
if ($input === '00') {
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (($parsedInt = filter_var(ltrim($input, "0"), FILTER_VALIDATE_INT)) === false) {
|
||||
throw new MDgenericInvalidInputsException("Input value is not numeric");
|
||||
}
|
||||
if ($parsedInt > 12) {
|
||||
throw new MDgenericInvalidInputsException("Attempted to set a month number beyond 12");
|
||||
}
|
||||
|
||||
return self::pad_to_two($input);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the entered day string.
|
||||
*
|
||||
* @param string $input Input to validate.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _validateCountingTimeDay(string $input):string {
|
||||
|
||||
if (strlen($input) > 2) throw new MDgenericInvalidInputsException("Input too long");
|
||||
|
||||
if ($input === '00') {
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (($parsedInt = filter_var(ltrim($input, "0"), FILTER_VALIDATE_INT)) === false) {
|
||||
throw new MDgenericInvalidInputsException("Input value is not numeric");
|
||||
}
|
||||
if ($parsedInt > 31) {
|
||||
throw new MDgenericInvalidInputsException("Attempted to set a day number beyond 31");
|
||||
}
|
||||
|
||||
return self::pad_to_two($input);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date time for the start of the time.
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function startToDateTime():DateTime {
|
||||
|
||||
if ($this->counting_time_indicator === NodaCountingTimeIndicator::bce) {
|
||||
return new DateTime('-' . $this->start_date);
|
||||
}
|
||||
else {
|
||||
return new DateTime($this->start_date);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date time for the end of the time.
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function endToDateTime():DateTime {
|
||||
|
||||
if ($this->counting_time_indicator === NodaCountingTimeIndicator::bce) {
|
||||
return new DateTime('-' . $this->end_date);
|
||||
}
|
||||
else {
|
||||
return new DateTime($this->end_date);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a time name based on the current entry.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toTimeName():string {
|
||||
|
||||
$prefix = $this->before_after_indicator->toString();
|
||||
if (!empty($prefix)) $prefix .= ' ';
|
||||
|
||||
// Determine start and end for display
|
||||
if ($this->start_year === '?') {
|
||||
$start = (int)$this->end_year;
|
||||
}
|
||||
else $start = (int)$this->start_year;
|
||||
|
||||
if ($this->end_year === '?') {
|
||||
$end = (int)$this->start_year;
|
||||
}
|
||||
else $end = (int)$this->end_year;
|
||||
|
||||
if ($this->before_after_indicator === NodaTimeBeforeAfterIndicator::before && $this->counting_time_month === '00') {
|
||||
$start++;
|
||||
$end++;
|
||||
}
|
||||
else if ($this->before_after_indicator === NodaTimeBeforeAfterIndicator::after && $this->counting_time_month === '00') {
|
||||
$start--;
|
||||
$end--;
|
||||
}
|
||||
|
||||
// Determine suffix
|
||||
if ($start < 0 && $end < 0) {
|
||||
$suffix = " v. Chr.";
|
||||
}
|
||||
else if ($end < 1000) {
|
||||
$suffix = " n. Chr.";
|
||||
}
|
||||
else $suffix = "";
|
||||
|
||||
$start = \abs($start);
|
||||
$end = \abs($end);
|
||||
|
||||
if ($start !== $end) {
|
||||
return "{$prefix}{$start}-{$end}{$suffix}";
|
||||
}
|
||||
|
||||
// A single day of a given month of a given (single) year
|
||||
else if (\intval($this->counting_time_month) !== 0 and \intval($this->counting_time_day) !== 0) {
|
||||
return "{$prefix}{$this->counting_time_day}.{$this->counting_time_month}.{$start}{$suffix}";
|
||||
}
|
||||
|
||||
// A single year
|
||||
else if ($start === $end && trim((string)$this->counting_time_month, " 0") === "" && trim((string)$this->counting_time_day, " 0") === "") {
|
||||
return "{$prefix}{$start}{$suffix}";
|
||||
}
|
||||
|
||||
// Single month of a given year
|
||||
else if ($start === $end && trim((string)$this->counting_time_month, " 0") !== "" && trim((string)$this->counting_time_day, " 0") === "") {
|
||||
|
||||
$fmt = new IntlDateFormatter(
|
||||
'de-DE',
|
||||
IntlDateFormatter::FULL,
|
||||
IntlDateFormatter::FULL,
|
||||
null,
|
||||
IntlDateFormatter::GREGORIAN,
|
||||
'MMMM Y'
|
||||
);
|
||||
|
||||
try {
|
||||
return $prefix . $fmt->format(MD_STD::strtotime("{$start}-{$this->counting_time_month}-15 01:01:01")) . $suffix;
|
||||
}
|
||||
catch (MDInvalidInputDate $e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array in the old time splitter format (array with sex values).
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function toOldFormat():array {
|
||||
|
||||
return [
|
||||
$this->start_year,
|
||||
$this->end_year,
|
||||
$this->counting_time_month,
|
||||
$this->counting_time_day,
|
||||
$this->counting_time_indicator->toString(),
|
||||
$this->before_after_indicator->toString(),
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $start_year Year.
|
||||
* @param string $end_year Year.
|
||||
* @param string $counting_time_month Month.
|
||||
* @param string $counting_time_day Day.
|
||||
* @param NodaCountingTimeIndicator $counting_time_indicator Determines if the time is BCE or CCE.
|
||||
* @param NodaTimeBeforeAfterIndicator $before_after_indicator Determines if the time is inexact to one direction.
|
||||
* @param false|string $start_date Start date.
|
||||
* @param false|string $end_date End date.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $start_year, string $end_year,
|
||||
string $counting_time_month = "00", string $counting_time_day = "00",
|
||||
NodaCountingTimeIndicator $counting_time_indicator = NodaCountingTimeIndicator::ce,
|
||||
NodaTimeBeforeAfterIndicator $before_after_indicator = NodaTimeBeforeAfterIndicator::none,
|
||||
false|string $start_date = false,
|
||||
false|string $end_date = false,
|
||||
) {
|
||||
|
||||
if (substr($start_year, 0, 1) === '-') {
|
||||
if (strlen($start_year) > 5) $start_year = '-' . str_pad(trim($start_year, '-'), 4, '-', STR_PAD_LEFT);
|
||||
}
|
||||
if ($start_date !== false && str_starts_with($start_date, '-')) {
|
||||
$parts = explode('-', trim($start_date, '-'));
|
||||
$parts[0] = str_pad($parts[0], 4, '0', STR_PAD_LEFT);
|
||||
$start_date = '-' . implode('-', $parts);
|
||||
}
|
||||
if (substr($end_year, 0, 1) === '-') {
|
||||
if (strlen($end_year) > 5) $end_year = '-' . str_pad(trim($end_year, '-'), 4, '-', STR_PAD_LEFT);
|
||||
}
|
||||
if ($end_date !== false && str_starts_with($end_date, '-')) {
|
||||
$parts = explode('-', trim($end_date, '-'));
|
||||
$parts[0] = str_pad($parts[0], 4, '0', STR_PAD_LEFT);
|
||||
$end_date = '-' . implode('-', $parts);
|
||||
}
|
||||
|
||||
$this->counting_time_indicator = $counting_time_indicator;
|
||||
$this->before_after_indicator = $before_after_indicator;
|
||||
|
||||
$this->_validateStartYear($start_year);
|
||||
$this->start_year = $start_year;
|
||||
|
||||
$this->_validateEndYear($end_year);
|
||||
$this->end_year = $end_year;
|
||||
|
||||
$this->counting_time_month = $this->_validateCountingTimeMonth($counting_time_month);
|
||||
$this->counting_time_day = $this->_validateCountingTimeDay($counting_time_day);
|
||||
|
||||
// Calculate start date and end date
|
||||
if (($this->before_after_indicator === NodaTimeBeforeAfterIndicator::before
|
||||
|| $this->before_after_indicator === NodaTimeBeforeAfterIndicator::until)
|
||||
|| $start_date === '?'
|
||||
) {
|
||||
$this->start_date = '-9999-12-31';
|
||||
}
|
||||
if (($this->before_after_indicator === NodaTimeBeforeAfterIndicator::after
|
||||
|| $this->before_after_indicator === NodaTimeBeforeAfterIndicator::since)
|
||||
|| $end_date === '?'
|
||||
) {
|
||||
$this->end_date = '9999-12-31';
|
||||
}
|
||||
|
||||
if (!isset($this->start_date) && false !== $start_date) {
|
||||
$this->start_date = date("Y-m-d", MD_STD::strtotime($start_date));
|
||||
}
|
||||
if (!isset($this->end_date) && false !== $end_date) {
|
||||
$this->end_date = date("Y-m-d", MD_STD::strtotime($end_date));
|
||||
}
|
||||
|
||||
if (!isset($this->start_date)) {
|
||||
if ($this->counting_time_month === "00") {
|
||||
$this->start_date = $this->start_year . '-01-01';
|
||||
}
|
||||
else if ($this->counting_time_day === "00") {
|
||||
$this->start_date = $this->start_year . '-' . $this->counting_time_month . '-01';
|
||||
}
|
||||
else {
|
||||
throw new MDgenericInvalidInputsException("Cannot identify start date automatically");
|
||||
}
|
||||
}
|
||||
if (!isset($this->end_date)) {
|
||||
if ($this->counting_time_month === "00") {
|
||||
$this->end_date = $this->end_year . '-12-31';
|
||||
}
|
||||
else if ($this->counting_time_day === "00") {
|
||||
$this->end_date = $this->end_year . '-' . $this->counting_time_month . '-31';
|
||||
}
|
||||
else {
|
||||
throw new MDgenericInvalidInputsException("Cannot identify end date automatically");
|
||||
}
|
||||
}
|
||||
|
||||
// Validate
|
||||
$startDateTime = MD_STD::strtotime("2000-" . substr($this->start_date, -5));
|
||||
if (checkdate((int)date('m', $startDateTime), (int)date('d', $startDateTime), (int)date('Y', $startDateTime)) === false) {
|
||||
throw new MDgenericInvalidInputsException("Invalid start date: " . $this->start_date);
|
||||
}
|
||||
|
||||
if (!empty((int)$this->counting_time_day)) {
|
||||
// The year 2000 is used here as it is a leap year and lots of years accepted in md are not accepted
|
||||
// by checkdate.
|
||||
if (checkdate((int)$this->counting_time_month, (int)$this->counting_time_day, 2000) === false) {
|
||||
throw new MDgenericInvalidInputsException("Invalid date formed by counting time: " . $this->counting_time_month . ' -- ' . $this->counting_time_day);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
64
src/NodaTagRelationIdentifier.php
Normal file
64
src/NodaTagRelationIdentifier.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Identifies the type of tag relation to an object based on known suffixes.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* Contains static functions for identifying uncertainty or blocking
|
||||
* completely uncertain inputs for actors, times, and places.
|
||||
*/
|
||||
final class NodaTagRelationIdentifier {
|
||||
|
||||
private const SUFFIXES = [
|
||||
'de' => [
|
||||
' (Motiv)' => MDTagRelationType::display_subject,
|
||||
' [Motiv]' => MDTagRelationType::display_subject,
|
||||
' <Motiv>' => MDTagRelationType::display_subject,
|
||||
|
||||
' (Material)' => MDTagRelationType::material,
|
||||
' [Material]' => MDTagRelationType::material,
|
||||
' <Material>' => MDTagRelationType::material,
|
||||
|
||||
' (Technik)' => MDTagRelationType::technique,
|
||||
' [Technik]' => MDTagRelationType::technique,
|
||||
' <Technik>' => MDTagRelationType::technique,
|
||||
]
|
||||
];
|
||||
|
||||
public readonly string $name;
|
||||
public readonly MDTagRelationType|false $relation;
|
||||
|
||||
/**
|
||||
* Constructor: Removes identifiers for well-known tag relations and determines cleaned name and relation type.
|
||||
*
|
||||
* @param string $lang Current language.
|
||||
* @param string $input_string Input string to clean.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $lang, string $input_string) {
|
||||
|
||||
if (empty(self::SUFFIXES[$lang])) {
|
||||
$this->name = $input_string;
|
||||
$this->relation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$relation = false;
|
||||
|
||||
$suffixes = self::SUFFIXES[$lang];
|
||||
foreach (array_keys($suffixes) as $suffix) {
|
||||
if (\mb_substr($input_string, \mb_strlen($suffix) * -1) === "$suffix") {
|
||||
$input_string = \mb_substr($input_string, 0, \mb_strlen($suffix) * -1);
|
||||
$relation = $suffixes[$suffix];
|
||||
}
|
||||
}
|
||||
|
||||
$this->name = $input_string;
|
||||
$this->relation = $relation;
|
||||
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ final class NodaTimeAutotranslater {
|
||||
|
||||
// TODO: Move these to NodaTimeAutotranslaterLocales
|
||||
|
||||
const LANGS_SYLLABLE_CLEANING = [
|
||||
public const LANGS_SYLLABLE_CLEANING = [
|
||||
"hu" => [
|
||||
"10-as évek" => "10-es évek",
|
||||
"40-as évek" => "40-es évek",
|
||||
@ -463,13 +463,13 @@ final class NodaTimeAutotranslater {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets translations for a given entry type.
|
||||
* Prepares translations for each available language.
|
||||
*
|
||||
* @param array<integer|string> $timeInfo Time information.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function getTranslations(array $timeInfo):array {
|
||||
public static function prepareTranslations(array $timeInfo):array {
|
||||
|
||||
if (!empty($timeInfo['zeit_name']) and strlen((string)$timeInfo['zeit_name']) > 10 and !empty($timespanDates = NodaTimeSplitter::attempt_splitting_from_till((string)$timeInfo['zeit_name']))) {
|
||||
|
||||
@ -480,12 +480,12 @@ final class NodaTimeAutotranslater {
|
||||
}
|
||||
$startTimeInfo = [
|
||||
"zeit_name" => $timespanDates['start_name'],
|
||||
"zeit_beginn" => $start[0],
|
||||
"zeit_ende" => $start[1],
|
||||
"zeit_beginn" => $start->start_year,
|
||||
"zeit_ende" => $start->end_year,
|
||||
"zeit_zaehlzeit_jahr" => NodaTimeSplitter::timePartsToCountingYear($start),
|
||||
"zeit_zaehlzeit_monat" => $start[2],
|
||||
"zeit_zaehlzeit_tag" => $start[3],
|
||||
"zeit_zaehlzeit_vorzeichen" => $start[4],
|
||||
"zeit_zaehlzeit_monat" => $start->counting_time_month,
|
||||
"zeit_zaehlzeit_tag" => $start->counting_time_day,
|
||||
"zeit_zaehlzeit_vorzeichen" => $start->counting_time_indicator->toString(),
|
||||
];
|
||||
|
||||
if (empty($end = NodaTimeSplitter::attempt_splitting($timespanDates['end_name']))) {
|
||||
@ -493,19 +493,22 @@ final class NodaTimeAutotranslater {
|
||||
}
|
||||
$endTimeInfo = [
|
||||
"zeit_name" => $timespanDates['end_name'],
|
||||
"zeit_beginn" => $end[0],
|
||||
"zeit_ende" => $end[1],
|
||||
"zeit_beginn" => $end->start_year,
|
||||
"zeit_ende" => $end->end_year,
|
||||
"zeit_zaehlzeit_jahr" => NodaTimeSplitter::timePartsToCountingYear($end),
|
||||
"zeit_zaehlzeit_monat" => $end[2],
|
||||
"zeit_zaehlzeit_tag" => $end[3],
|
||||
"zeit_zaehlzeit_vorzeichen" => $end[4],
|
||||
"zeit_zaehlzeit_monat" => $end->counting_time_month,
|
||||
"zeit_zaehlzeit_tag" => $end->counting_time_day,
|
||||
"zeit_zaehlzeit_vorzeichen" => $end->counting_time_indicator->toString(),
|
||||
];
|
||||
|
||||
$output = [];
|
||||
$cases = NodaTimeAutotranslaterLocales::cases();
|
||||
foreach ($cases as $tLang) {
|
||||
$start_term = self::getTranslations($startTimeInfo)[$tLang->name];
|
||||
$end_term = self::getTranslations($endTimeInfo)[$tLang->name];
|
||||
$startTls = self::getTranslations($startTimeInfo);
|
||||
$endTls = self::getTranslations($endTimeInfo);
|
||||
if (empty($startTls) || empty($endTls)) return [];
|
||||
$start_term = $startTls[$tLang->name];
|
||||
$end_term = $endTls[$tLang->name];
|
||||
|
||||
$output[$tLang->name] = \sprintf($tLang->formatYearspanForSprintf(), $start_term, $end_term);
|
||||
}
|
||||
@ -604,6 +607,78 @@ final class NodaTimeAutotranslater {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates correctness of years in translation strings.
|
||||
*
|
||||
* @param string|integer $start Start year.
|
||||
* @param string|integer $end End year.
|
||||
* @param array<string, string> $translations Translations.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function validateTranslations(string|int $start, string|int $end, array $translations):bool {
|
||||
|
||||
$start = ltrim((string)$start, ' 0-');
|
||||
$end = ltrim((string)$end, ' 0-');
|
||||
|
||||
// Edge cases: Centuries and decades have special translations
|
||||
// and can thus not be validated properly
|
||||
// Century BCE
|
||||
if (substr($start, -1) === "0" && substr($end, -1) === '1' && $start > $end) {
|
||||
return true;
|
||||
}
|
||||
// Century CE
|
||||
if (substr($start, -1) === "1" && substr($end, -1) === '0' && $start < $end) {
|
||||
return true;
|
||||
}
|
||||
// Decade
|
||||
if (substr($start, -1) === "0" && substr($end, -1) === '9' && $start < $end) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1920 + ? can be both Since 1920 and After 1919, so validation
|
||||
// is impossible there, too
|
||||
if ($start === '?' || $end === '?') return true;
|
||||
|
||||
// Unset unvalidatable languages
|
||||
unset($translations['ar'], $translations['fa']);
|
||||
|
||||
if ($start !== '?') {
|
||||
foreach ($translations as $t) {
|
||||
if (!str_contains($t, $start)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($end !== '?' && $start !== $end) {
|
||||
foreach ($translations as $t) {
|
||||
if (!str_contains($t, $end)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets translations for a given entry type.
|
||||
*
|
||||
* @param array<integer|string> $timeInfo Time information.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function getTranslations(array $timeInfo):array {
|
||||
|
||||
$output = self::prepareTranslations($timeInfo);
|
||||
|
||||
if (self::validateTranslations($timeInfo['zeit_beginn'], $timeInfo['zeit_ende'], $output) === false) return [];
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs autotranslater.
|
||||
*
|
||||
@ -613,7 +688,9 @@ final class NodaTimeAutotranslater {
|
||||
*/
|
||||
public function translate(array $timeInfo):void {
|
||||
|
||||
$translations = self::getTranslations($timeInfo);
|
||||
if (empty($translations = self::getTranslations($timeInfo))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_mysqli_noda->autocommit(false);
|
||||
|
||||
|
67
src/NodaTimeBeforeAfterIndicator.php
Normal file
67
src/NodaTimeBeforeAfterIndicator.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Represents a time indicator (CE / BCE).
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* Represents a time indicator (CE / BCE).
|
||||
*/
|
||||
enum NodaTimeBeforeAfterIndicator implements JsonSerializable {
|
||||
|
||||
case none;
|
||||
case after;
|
||||
case before;
|
||||
case since;
|
||||
case until;
|
||||
|
||||
/**
|
||||
* Returns a value of this type based on a string.
|
||||
*
|
||||
* @param string $input Input to get a value from.
|
||||
*
|
||||
* @return NodaTimeBeforeAfterIndicator
|
||||
*/
|
||||
public static function fromString(string $input):NodaTimeBeforeAfterIndicator {
|
||||
|
||||
return match($input) {
|
||||
'' => self::none,
|
||||
'Nach' => self::after,
|
||||
'Vor' => self::before,
|
||||
'Seit' => self::since,
|
||||
'Bis' => self::until,
|
||||
default => throw new MDpageParameterNotFromListException("Unknown before / after indicator"),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a canonical string representation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toString():string {
|
||||
|
||||
return match($this) {
|
||||
self::none => '',
|
||||
self::after => 'Nach',
|
||||
self::before => 'Vor',
|
||||
self::since => 'Seit',
|
||||
self::until => 'Bis',
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the option to serialize as a string during json_encode().
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function jsonSerialize():string {
|
||||
|
||||
return $this->name;
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@ declare(strict_types = 1);
|
||||
*/
|
||||
final class NodaUncertaintyHelper {
|
||||
|
||||
const PERSINST_INDICATORS_DISALLOWED = [
|
||||
public const PERSINST_INDICATORS_DISALLOWED = [
|
||||
"Unbekannt",
|
||||
"unbekannt",
|
||||
"Anonymus",
|
||||
@ -41,7 +41,7 @@ final class NodaUncertaintyHelper {
|
||||
"Невідомий артист", // Unknown artist
|
||||
];
|
||||
|
||||
const PERSINST_UNCERTAINTY_PREFIXES = [
|
||||
public const PERSINST_UNCERTAINTY_PREFIXES = [
|
||||
"verm. ",
|
||||
"Verm. ",
|
||||
"vermtl. ",
|
||||
@ -57,15 +57,16 @@ final class NodaUncertaintyHelper {
|
||||
"?",
|
||||
];
|
||||
|
||||
const PERSINST_UNCERTAINTY_SUFFIXES = [
|
||||
public const PERSINST_UNCERTAINTY_SUFFIXES = [
|
||||
"(?)",
|
||||
"?",
|
||||
" [vermutlich]",
|
||||
" vermutlich",
|
||||
" [verm.]",
|
||||
" [wahrscheinlich]",
|
||||
];
|
||||
|
||||
const TIME_INDICATORS_DISALLOWED = [
|
||||
public const TIME_INDICATORS_DISALLOWED = [
|
||||
"Nachgewiesen",
|
||||
"nachgewiesen",
|
||||
"o.D.",
|
||||
@ -96,10 +97,11 @@ final class NodaUncertaintyHelper {
|
||||
"б.д.", // No dating
|
||||
];
|
||||
|
||||
const TIME_UNCERTAINTY_PREFIXES = [
|
||||
public const TIME_UNCERTAINTY_PREFIXES = [
|
||||
"c. ",
|
||||
"ca ",
|
||||
"ca. ",
|
||||
"ca.",
|
||||
"Ca ",
|
||||
"Ca. ",
|
||||
"za. ",
|
||||
@ -132,7 +134,7 @@ final class NodaUncertaintyHelper {
|
||||
"Прибл.", // UK: approximately
|
||||
];
|
||||
|
||||
const TIME_UNCERTAINTY_SUFFIXES = [
|
||||
public const TIME_UNCERTAINTY_SUFFIXES = [
|
||||
"(?)",
|
||||
"?",
|
||||
" (ca.)",
|
||||
@ -141,8 +143,11 @@ final class NodaUncertaintyHelper {
|
||||
" [circa]",
|
||||
" (verm.)",
|
||||
" (vermutl.)",
|
||||
" vermutlich",
|
||||
" körül",
|
||||
", um",
|
||||
", ca.",
|
||||
", ca",
|
||||
" (um)",
|
||||
" (ок.)",
|
||||
];
|
||||
@ -150,7 +155,7 @@ final class NodaUncertaintyHelper {
|
||||
/**
|
||||
* Substrings used to express uncertainty about the validity of a place name.
|
||||
*/
|
||||
const PLACE_INDICATORS_DISALLOWED = [
|
||||
public const PLACE_INDICATORS_DISALLOWED = [
|
||||
"Unbekannt",
|
||||
"unbekannt",
|
||||
"Unknown",
|
||||
@ -175,7 +180,7 @@ final class NodaUncertaintyHelper {
|
||||
"невідоме", // No place
|
||||
];
|
||||
|
||||
const PLACE_UNCERTAINTY_PREFIXES = [
|
||||
public const PLACE_UNCERTAINTY_PREFIXES = [
|
||||
"ca ",
|
||||
"Ca ",
|
||||
"ca. ",
|
||||
@ -212,7 +217,7 @@ final class NodaUncertaintyHelper {
|
||||
"?",
|
||||
];
|
||||
|
||||
const PLACE_UNCERTAINTY_SUFFIXES = [
|
||||
public const PLACE_UNCERTAINTY_SUFFIXES = [
|
||||
"(?)",
|
||||
"(vermutl.)",
|
||||
"[vermutl.]",
|
||||
@ -232,8 +237,7 @@ final class NodaUncertaintyHelper {
|
||||
*/
|
||||
public static function trim(string $input):string {
|
||||
|
||||
$input = \trim($input, ", \t\n\r\n;-:");
|
||||
return $input;
|
||||
return \trim($input, ", \t\n\r\n;-:");
|
||||
|
||||
}
|
||||
|
||||
@ -280,7 +284,7 @@ final class NodaUncertaintyHelper {
|
||||
*/
|
||||
public static function guessTimeCertainty(string $zeit_name):bool {
|
||||
|
||||
$zeit_name = \strtolower($zeit_name);
|
||||
$zeit_name = self::trim(strtolower($zeit_name));
|
||||
|
||||
// Attempt to guess uncertainty based on prefixes.
|
||||
foreach (self::TIME_UNCERTAINTY_PREFIXES as $prefix) {
|
||||
@ -329,6 +333,14 @@ final class NodaUncertaintyHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// If brackets are included in the name, try removing prefixes and suffixes
|
||||
// from the beginning.
|
||||
if (($bracketPos = strpos($ort_name, "(")) !== false) {
|
||||
$start = substr($ort_name, 0, $bracketPos);
|
||||
$end = substr($ort_name, $bracketPos);
|
||||
$ort_name = self::cleanUncertaintyIndicatorsPlace($start) . ' ' . $end;
|
||||
}
|
||||
|
||||
return self::trim($ort_name);
|
||||
|
||||
}
|
||||
@ -343,7 +355,7 @@ final class NodaUncertaintyHelper {
|
||||
*/
|
||||
public static function guessPlaceCertainty(string $ort_name):bool {
|
||||
|
||||
$ort_name = \strtolower($ort_name);
|
||||
$ort_name = self::trim(\strtolower($ort_name));
|
||||
|
||||
// Attempt to guess uncertainty based on prefixes.
|
||||
foreach (NodaUncertaintyHelper::PLACE_UNCERTAINTY_PREFIXES as $prefix) {
|
||||
@ -359,6 +371,13 @@ final class NodaUncertaintyHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// If brackets are included in the name, try the same for everything up to the
|
||||
// first brackets.
|
||||
if (($bracketPos = strpos($ort_name, "(")) !== false) {
|
||||
$name = substr($ort_name, 0, $bracketPos);
|
||||
return self::guessPlaceCertainty($name);
|
||||
}
|
||||
|
||||
return true; // Certain / no uncertainty found
|
||||
|
||||
}
|
||||
@ -404,7 +423,7 @@ final class NodaUncertaintyHelper {
|
||||
*/
|
||||
public static function guessPersinstCertainty(string $name):bool {
|
||||
|
||||
$name = \trim(\strtolower($name));
|
||||
$name = self::trim(\strtolower($name));
|
||||
|
||||
// Attempt to guess uncertainty based on prefixes.
|
||||
foreach (NodaUncertaintyHelper::PERSINST_UNCERTAINTY_PREFIXES as $prefix) {
|
||||
|
@ -11,7 +11,59 @@ declare(strict_types = 1);
|
||||
*/
|
||||
final class NodaValidationHelper {
|
||||
|
||||
const ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS = 2;
|
||||
const ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS = 3;
|
||||
|
||||
/**
|
||||
* Validates an actor description for completeness. Of course, only an informed
|
||||
* guess based on the length and character composition of the description can be
|
||||
* made.
|
||||
*
|
||||
* @param string $description Input descrition.
|
||||
* @param string $name Names of the actor. Optional. Setting this enables
|
||||
* checks e.g. to prevent duplicating the actor name
|
||||
* as a description.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function validateTagDescription(string $description, string $name = ""):void {
|
||||
|
||||
// For nodac, empty tag descriptions are to be allowed. Thus, a
|
||||
// dedicated check for fully empty ones with a dedicated exception
|
||||
// is needed.
|
||||
if (empty($description)) {
|
||||
throw new MDInvalidEmptyInputException("No tag name is provided");
|
||||
}
|
||||
|
||||
// Throw error on descriptions that are too short
|
||||
if (\mb_strlen($description) < 10) {
|
||||
throw new MDgenericInvalidInputsException("Tag description is too short");
|
||||
}
|
||||
|
||||
// Validate tag description based on character composition.
|
||||
|
||||
// Ensure more than 3 distinct characters are used.
|
||||
$chars = \str_split($description);
|
||||
|
||||
$uniqueChars = array_unique($chars);
|
||||
if (count($uniqueChars) <= self::ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS) {
|
||||
throw new MDgenericInvalidInputsException("There need to be more than " . self::ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS . " distinct characters.");
|
||||
}
|
||||
|
||||
// Ensure more than the actor name is used.
|
||||
$clearedChars = [' ' => ' ', ',' => ' ', ';' => ' ', '.' => ' '];
|
||||
|
||||
$uniqueNames = array_unique(array_diff(explode(' ', strtr($name, $clearedChars)), ['']));
|
||||
sort($uniqueNames);
|
||||
|
||||
$descCleared = strtr($description, $clearedChars);
|
||||
$descWords = array_unique(array_diff(explode(' ', $descCleared), ['']));
|
||||
sort($descWords);
|
||||
|
||||
if ($uniqueNames === $descWords) {
|
||||
throw new MDgenericInvalidInputsException("The tag name was simply repeated in the description. This is not enough.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an actor description for completeness. Of course, only an informed
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,27 @@
|
||||
<?PHP
|
||||
/**
|
||||
* This file contains an exception class to be thrown if a user attempts to load
|
||||
* data from a Wikidata item specifically established for a disambiguation page.
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* Exception class to be thrown if a user attempts to load
|
||||
* data from a Wikidata item specifically established for a disambiguation page.
|
||||
*/
|
||||
final class NodaWikidataFetcherDisambiguationIsDisallowedException extends MDgenericInvalidInputsException {
|
||||
/**
|
||||
* Error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function errorMessage() {
|
||||
//error message
|
||||
return 'Attempted to load a disambiguation page. Please select the specific item you want to fetch to enrich the given entry: ' . $this->getMessage();
|
||||
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ declare(strict_types = 1);
|
||||
*/
|
||||
final class NodaPersinstFulltextSyncManticore {
|
||||
|
||||
const FULL_SYNC_COMMIT_AFTER = 30000;
|
||||
private const FULL_SYNC_COMMIT_AFTER = 30000;
|
||||
|
||||
/**
|
||||
* Returns all names and descriptions in the different languages of a actor.
|
||||
@ -188,6 +188,10 @@ final class NodaPersinstFulltextSyncManticore {
|
||||
|
||||
$mysqli_manticore->commit();
|
||||
|
||||
if (PHP_SAPI === 'cli' && $mysqli_noda->ping() === false) {
|
||||
$mysqli_noda->reconnect();
|
||||
}
|
||||
|
||||
// Sync translations
|
||||
|
||||
$result = $mysqli_noda->do_read_query("SELECT `persinst`.`persinst_id`, `trans_language`,
|
||||
|
@ -11,7 +11,7 @@ declare(strict_types = 1);
|
||||
*/
|
||||
final class NodaTagFulltextSyncManticore {
|
||||
|
||||
const FULL_SYNC_COMMIT_AFTER = 30000;
|
||||
private const FULL_SYNC_COMMIT_AFTER = 30000;
|
||||
|
||||
/**
|
||||
* Returns all names and descriptions in the different languages of a tag.
|
||||
@ -139,6 +139,10 @@ final class NodaTagFulltextSyncManticore {
|
||||
/**
|
||||
* Synchronizes base entries.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Connection to MySQL DB.
|
||||
* @param MDMysqli $mysqli_manticore Connection to Manticore DB.
|
||||
* @param string $databasename Name of the main noda database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function runFullSyncForBaseEntries(MDMysqli $mysqli_noda, MDMysqli $mysqli_manticore, string $databasename):void {
|
||||
@ -189,6 +193,10 @@ final class NodaTagFulltextSyncManticore {
|
||||
/**
|
||||
* Synchronizes translated entries.
|
||||
*
|
||||
* @param MDMysqli $mysqli_noda Connection to MySQL DB.
|
||||
* @param MDMysqli $mysqli_manticore Connection to Manticore DB.
|
||||
* @param string $databasename Name of the main noda database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function runFullSyncForTranslatedEntries(MDMysqli $mysqli_noda, MDMysqli $mysqli_manticore, string $databasename):void {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
enum NodaTimeAutotranslaterLocales {
|
||||
case ar;
|
||||
case crh;
|
||||
case de;
|
||||
case en;
|
||||
case es;
|
||||
@ -40,6 +41,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($lang) {
|
||||
'ar' => static::ar,
|
||||
'crh' => static::crh,
|
||||
'de' => static::de,
|
||||
'en' => static::en,
|
||||
'es' => static::es,
|
||||
@ -73,6 +75,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => 'ar_SY.utf8',
|
||||
self::crh => 'uk_UA.utf8',
|
||||
self::de => 'de_DE.utf8',
|
||||
self::en => 'en_US.utf8',
|
||||
self::es => 'es_ES.utf8',
|
||||
@ -108,6 +111,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => 'ar-SY',
|
||||
self::crh => 'uk-UA',
|
||||
self::de => 'de-DE',
|
||||
self::en => 'en-US',
|
||||
self::es => 'es-ES',
|
||||
@ -143,6 +147,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s',
|
||||
self::crh => '%s',
|
||||
self::de => '%s n. Chr.',
|
||||
self::en => '%s CE',
|
||||
self::es => '%s d.C.',
|
||||
@ -176,6 +181,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '-%s',
|
||||
self::crh => '%s рік до нашої ери',
|
||||
self::de => '%s v. Chr.',
|
||||
self::en => '%s BC',
|
||||
self::es => '%s a.C.',
|
||||
@ -211,6 +217,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s',
|
||||
self::crh => '%s',
|
||||
self::de => '%s',
|
||||
self::en => '%s',
|
||||
self::es => '%s',
|
||||
@ -244,6 +251,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s-%s',
|
||||
self::crh => '%s-%s',
|
||||
self::de => '%s-%s',
|
||||
self::en => '%s-%s',
|
||||
self::es => '%s-%s',
|
||||
@ -279,6 +287,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s-',
|
||||
self::crh => 'з %s року',
|
||||
self::de => 'Seit %s',
|
||||
self::en => 'Since %s',
|
||||
self::es => 'Desde %s',
|
||||
@ -315,6 +324,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s-',
|
||||
self::crh => 'після %s року',
|
||||
self::de => 'Nach %s',
|
||||
self::en => 'After %s',
|
||||
self::es => 'Despues de %s',
|
||||
@ -350,6 +360,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '-%s',
|
||||
self::crh => 'до %s року',
|
||||
self::de => 'Bis %s',
|
||||
self::en => 'Until %s',
|
||||
self::es => 'Hasta %s',
|
||||
@ -384,6 +395,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => 'القرن ال %s',
|
||||
self::crh => '%s століття',
|
||||
self::de => '%s. Jahrhundert',
|
||||
self::en => '%s. century',
|
||||
self::es => 'Siglo %s',
|
||||
@ -418,6 +430,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => 'القرن ال %s-%s',
|
||||
self::crh => '%s-%s століття',
|
||||
self::de => '%s.-%s. Jahrhundert',
|
||||
self::en => '%s.-%s. century',
|
||||
self::es => 'Siglo %s-%s',
|
||||
@ -452,6 +465,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s-%s',
|
||||
self::crh => '%s-ті роки',
|
||||
self::de => '%ser Jahre',
|
||||
self::en => '%ss',
|
||||
self::es => '%s-%s',
|
||||
@ -486,6 +500,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '%s-%s',
|
||||
self::crh => '%s-%s-ті роки',
|
||||
self::de => '%s-%ser Jahre',
|
||||
self::en => '%s-%ss',
|
||||
self::es => '%s-%s',
|
||||
@ -521,6 +536,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
|
||||
return match($this) {
|
||||
self::ar => '-%s',
|
||||
self::crh => 'до %s року',
|
||||
self::de => 'Vor %s',
|
||||
self::en => 'Before %s',
|
||||
self::es => 'Antes de %s',
|
||||
@ -558,6 +574,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
# self::be => '%d.%B.%Y',
|
||||
# self::bg => '%Y-%B-%d',
|
||||
# self::ca => '%d/%m/%Y',
|
||||
self::crh => '%d.%m.%Y',
|
||||
# self::cs => '%d.%B.%Y',
|
||||
# self::da => '%d-%m-%Y',
|
||||
self::de => '%d.%m.%Y',
|
||||
@ -618,6 +635,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
# self::be => '%d.%B.%Y',
|
||||
# self::bg => '%Y-%B-%d',
|
||||
# self::ca => '%d/%m/%Y',
|
||||
self::crh => 'dd.MM.Y',
|
||||
# self::cs => '%d.%B.%Y',
|
||||
# self::da => '%d-%m-%Y',
|
||||
self::de => 'dd.MM.Y',
|
||||
@ -679,6 +697,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
# self::bg => '%Y-%B',
|
||||
# self::ca => '%m/%Y',
|
||||
# self::cs => '%B.%Y',
|
||||
self::crh => '%m %Y',
|
||||
# self::da => '%m-%Y',
|
||||
self::de => '%B %Y',
|
||||
# self::el => '%B %Y',
|
||||
@ -735,6 +754,7 @@ enum NodaTimeAutotranslaterLocales {
|
||||
# self::bg => 'Y-MMMM',
|
||||
# self::ca => 'MM/Y',
|
||||
# self::cs => 'MMMM.Y',
|
||||
self::crh => 'MMMM Y',
|
||||
# self::da => 'MM-Y',
|
||||
self::de => 'MMMM Y',
|
||||
# self::el => 'MMMM Y',
|
||||
|
@ -5,13 +5,16 @@
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Small;
|
||||
|
||||
/**
|
||||
* Tests for setting uniform place names.
|
||||
*
|
||||
* @covers \NodaConsolidatedNamesForPlaces
|
||||
*/
|
||||
#[small]
|
||||
#[CoversClass(\NodaConsolidatedNamesForPlaces::class)]
|
||||
final class NodaConsolidatedNamesForPlacesTest extends TestCase {
|
||||
/**
|
||||
* Test that cleanup function returns expected values.
|
||||
@ -56,7 +59,6 @@ final class NodaConsolidatedNamesForPlacesTest extends TestCase {
|
||||
self::assertEquals("Deák Ferenc utca 16-18. (Budapest, 5. kerület)", NodaConsolidatedNamesForPlaces::consolidate_name("hu", "Deák Ferenc utca 16-18. Budapest, V."));
|
||||
self::assertEquals("Deák Ferenc utca 16-18. Budapest, V. abc", NodaConsolidatedNamesForPlaces::consolidate_name("hu", "Deák Ferenc utca 16-18. Budapest, V. abc"));
|
||||
|
||||
|
||||
// Rewriting country names in brackets
|
||||
self::assertEquals("Köln (Deutschland)", NodaConsolidatedNamesForPlaces::consolidate_name("de", "Deutschland-Köln"));
|
||||
self::assertEquals("Köln (Deutschland)", NodaConsolidatedNamesForPlaces::consolidate_name("de", "Deutschland, Köln"));
|
||||
|
615
tests/NodaIDGetterTest.php
Normal file
615
tests/NodaIDGetterTest.php
Normal file
@ -0,0 +1,615 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Test for functions for looking up entry IDs by their (exact) names.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Medium;
|
||||
|
||||
require_once __DIR__ . '/../../MDMysqli/test_connections.conf.php';
|
||||
|
||||
/**
|
||||
* Test for functions for looking up entry IDs by their (exact) names.
|
||||
*/
|
||||
#[Medium]
|
||||
#[CoversClass(\NodaIDGetter::class)]
|
||||
final class NodaIDGetterTest extends TestCase {
|
||||
|
||||
private MDMysqli $_mysqli;
|
||||
|
||||
/**
|
||||
* Quasi-constructor connects to DB.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setUp():void {
|
||||
|
||||
$this->_mysqli = md_noda_mysqli_connect();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets string and integer value from a mysql query.
|
||||
*
|
||||
* @param MDMysqli $mysqli DB connection.
|
||||
* @param string $query DB query.
|
||||
*
|
||||
* @return array{0: string, 1: integer}
|
||||
*/
|
||||
private static function _getNameAndIdFromDbQuery(MDMysqli $mysqli, string $query):array {
|
||||
|
||||
$result = $mysqli->do_read_query($query . "
|
||||
LIMIT 1");
|
||||
|
||||
if (!($cur = $result->fetch_row())) {
|
||||
throw new Exception("Failed to get result for query: " . $query);
|
||||
}
|
||||
$result->close();
|
||||
|
||||
return [
|
||||
(string)$cur[0],
|
||||
(int)$cur[1],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces vowels in string with variants with diacritics for testing
|
||||
* exact matching.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function _replaceVowelsWithDiacriticVariants(string $input):string {
|
||||
|
||||
return strtr($input, [
|
||||
'a' => 'ä',
|
||||
'o' => 'ö',
|
||||
'u' => 'ü',
|
||||
'i' => 'ï',
|
||||
'e' => 'è',
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs regular tests on the term:
|
||||
* - Matching by exact same name works.
|
||||
* - Matching by same name with different capitalization works.
|
||||
* - Matching by same name with diacritics replacing non-diacritic vowels fails
|
||||
* (counter to MySQL's _ci-type notations rules).
|
||||
*
|
||||
* @param string $function NodaIDGetter's callback function for identification.
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function runRegularComparisonTests(string $function, string $name, int $expected_id):void {
|
||||
|
||||
self::assertEquals($expected_id,
|
||||
NodaIDGetter::$function($this->_mysqli, "de", $name),
|
||||
"Entry " . $name . " is not matched in exact lookup. Expected ID: " . $expected_id);
|
||||
|
||||
// Ensure that different capitalization does not influence the results
|
||||
self::assertEquals($expected_id,
|
||||
NodaIDGetter::$function($this->_mysqli, "de", strtoupper($name)));
|
||||
self::assertEquals($expected_id,
|
||||
NodaIDGetter::$function($this->_mysqli, "de", strtolower($name)));
|
||||
|
||||
// Ensure that diacritics will stop the entry from matching
|
||||
$nameReplaced = self::_replaceVowelsWithDiacriticVariants($name);
|
||||
self::assertNotEquals($expected_id,
|
||||
NodaIDGetter::$function($this->_mysqli, "de", $nameReplaced));
|
||||
|
||||
}
|
||||
|
||||
// PersinstIDByName
|
||||
|
||||
/**
|
||||
* Returns a test actor name.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function persinstByNameProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$persinstByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `persinst_name`, `persinst_id`
|
||||
FROM `persinst`
|
||||
WHERE INSTR(`persinst_name`, 'i')");
|
||||
$persinstByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `persinst_anzeigename`, `persinst_id`
|
||||
FROM `persinst`
|
||||
WHERE INSTR(`persinst_anzeigename`, 'i')
|
||||
AND `persinst_sterbejahr` != ''");
|
||||
$persinstByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `persinst_id`
|
||||
FROM `persinst_translation`
|
||||
WHERE INSTR(`trans_name`, 'i')
|
||||
AND `trans_language` = 'de'");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Persinst ID by name: ' . $persinstByNameSimple[0] => $persinstByNameSimple,
|
||||
'Persinst ID by display name: ' . $persinstByDisplayNameSimple[0] => $persinstByDisplayNameSimple,
|
||||
'Persinst ID by translated name: ' . $persinstByDisplayNameSimple[0] => $persinstByDisplayNameSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a test actor name and life dates.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer, 2: string, 3: string}>
|
||||
*/
|
||||
public static function persinstByNameAndLifeDatesProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$result = $mysqli->do_read_query("SELECT `persinst_name_en`, `persinst_name`, `persinst_id`, `persinst_geburtsjahr`, `persinst_sterbejahr`
|
||||
FROM `persinst`
|
||||
WHERE INSTR(`persinst_name_en`, 'i')
|
||||
AND `persinst_geburtsjahr` != ''
|
||||
AND `persinst_sterbejahr` != ''
|
||||
LIMIT 1");
|
||||
if (!$cur = $result->fetch_row()) {
|
||||
throw new Exception("Error");
|
||||
}
|
||||
$result->close();
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Persinst ID by name: ' . implode(' - ', $cur) => [
|
||||
(string)$cur[0], (int)$cur[2], (string)$cur[3], (string)$cur[4],
|
||||
(string)$cur[1], (int)$cur[2], (string)$cur[3], (string)$cur[4],
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting persinst by name works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('persinstByNameProvider')]
|
||||
public function testGetPersinstIdByNameWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getPersinstIDByName", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting persinst by name and life dates works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
* @param string $birth_year Birth year.
|
||||
* @param string $death_year Death year.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('persinstByNameAndLifeDatesProvider')]
|
||||
public function testGetPersinstIdByNameAndLifeDatesWorks(string $name, int $expected_id, string $birth_year, string $death_year):void {
|
||||
|
||||
self::assertEquals($expected_id,
|
||||
NodaIDGetter::getPersinstIDByNamePlusYears($this->_mysqli, "de", $name, $birth_year, $death_year),
|
||||
"Entry " . $name . " is not matched in exact lookup. Expected ID: " . $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// PersinstIDByRewrite
|
||||
|
||||
/**
|
||||
* Returns a test actor name.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function persinstByRewriteProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$persinstByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `persinst_id`
|
||||
FROM `persinst_rewriting`
|
||||
WHERE INSTR(`input_name`, 'i')");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Persinst ID by rewrite: ' . $persinstByRewriteSimple[0] => $persinstByRewriteSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting persinst by rewrite works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('persinstByRewriteProvider')]
|
||||
public function testGetPersinstIdByRewriteWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getPersinstIDByRewrite", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// PlaceIDByName
|
||||
|
||||
/**
|
||||
* Returns a test place name.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function placeByNameProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$placeByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `ort_name`, `ort_id`
|
||||
FROM `orte`
|
||||
WHERE INSTR(`ort_name`, 'i')");
|
||||
$placeByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `ort_id`
|
||||
FROM `ort_translation`
|
||||
WHERE INSTR(`trans_name`, 'i')
|
||||
AND `trans_language` = 'de'");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Place ID by name: ' . $placeByNameSimple[0] => $placeByNameSimple,
|
||||
'Place ID by translated name: ' . $placeByDisplayNameSimple[0] => $placeByDisplayNameSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting persinst by name works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('placeByNameProvider')]
|
||||
public function testGetPlaceIdByNameWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getPlaceIDByName", $name, $expected_id);
|
||||
$this->runRegularComparisonTests("getPlaceIDByNamesAndRewrites", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// PlaceIDByRewrite
|
||||
|
||||
/**
|
||||
* Returns a test place name registered for rewriting.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function placeByRewriteProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$placeByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `ort_id`
|
||||
FROM `ort_rewriting`
|
||||
WHERE INSTR(`input_name`, 'i')");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Place ID by rewrite: ' . $placeByRewriteSimple[0] => $placeByRewriteSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting places by rewrite works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('placeByRewriteProvider')]
|
||||
public function testGetPlaceIdByRewriteWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getPlaceIDByRewrite", $name, $expected_id);
|
||||
$this->runRegularComparisonTests("getPlaceIDByNamesAndRewrites", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// TagIDByName
|
||||
|
||||
/**
|
||||
* Returns a test tag name.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function tagByNameProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$tagByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `tag_name`, `tag_id`
|
||||
FROM `tag`
|
||||
WHERE INSTR(`tag_name`, 'i')");
|
||||
$tagByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `tag_id`
|
||||
FROM `tag_translation`
|
||||
WHERE INSTR(`trans_name`, 'i')
|
||||
AND `trans_language` = 'de'");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Tag ID by name: ' . $tagByNameSimple[0] => $tagByNameSimple,
|
||||
'Tag ID by translated name: ' . $tagByDisplayNameSimple[0] => $tagByDisplayNameSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting tags by name works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('tagByNameProvider')]
|
||||
public function testGetTagIdByNameWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getTagIDByName", $name, $expected_id);
|
||||
$this->runRegularComparisonTests("getTagIDByNamesAndRewrites", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// TagIDByRewrite
|
||||
|
||||
/**
|
||||
* Returns a test tag name registered for rewriting.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function tagByRewriteProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$tagByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `tag_id`
|
||||
FROM `tag_rewriting`
|
||||
WHERE INSTR(`input_name`, 'i')");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Tag ID by rewrite: ' . $tagByRewriteSimple[0] => $tagByRewriteSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting tags by rewrite works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('tagByRewriteProvider')]
|
||||
public function testGetTagIdByRewriteWorks(string $name, int $expected_id):void {
|
||||
|
||||
self::assertContains($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", $name));
|
||||
|
||||
// Ensure that different capitalization does not influence the results
|
||||
self::assertContains($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", strtoupper($name)));
|
||||
self::assertContains($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", strtolower($name)));
|
||||
|
||||
// Ensure that diacritics will stop the entry from matching
|
||||
$nameReplaced = self::_replaceVowelsWithDiacriticVariants($name);
|
||||
self::assertFalse(in_array($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", $nameReplaced), true));
|
||||
|
||||
}
|
||||
|
||||
// TimeIDByName
|
||||
|
||||
/**
|
||||
* Returns a test time name.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function timeByNameProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$timeByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `zeit_name`, `zeit_id`
|
||||
FROM `zeiten`
|
||||
WHERE INSTR(`zeit_name`, 'i')");
|
||||
$timeByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `zeit_id`
|
||||
FROM `zeit_translation`
|
||||
WHERE INSTR(`trans_name`, 'i')
|
||||
AND `trans_language` = 'de'");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Time ID by name: ' . $timeByNameSimple[0] => $timeByNameSimple,
|
||||
'Time ID by translated name: ' . $timeByDisplayNameSimple[0] => $timeByDisplayNameSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting persinst by name works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('timeByNameProvider')]
|
||||
public function testGetTimeIdByNameWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getTimeIDByName", $name, $expected_id);
|
||||
$this->runRegularComparisonTests("getTimeIDByNamesAndRewrites", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// timeIDByRewrite
|
||||
|
||||
/**
|
||||
* Returns a test time name registered for rewriting.
|
||||
*
|
||||
* @return array<array{0: string, 1: integer}>
|
||||
*/
|
||||
public static function timeByRewriteProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$timeByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `zeit_id`
|
||||
FROM `zeit_rewriting`
|
||||
WHERE INSTR(`input_name`, 'i')
|
||||
AND `language` = 'de'");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Time ID by rewrite: ' . $timeByRewriteSimple[0] => $timeByRewriteSimple,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting times by rewrite works.
|
||||
*
|
||||
* @param string $name Name of the entry.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('timeByRewriteProvider')]
|
||||
public function testGetTimeIdByRewriteWorks(string $name, int $expected_id):void {
|
||||
|
||||
$this->runRegularComparisonTests("getTimeIDByRewrite", $name, $expected_id);
|
||||
$this->runRegularComparisonTests("getTimeIDByNamesAndRewrites", $name, $expected_id);
|
||||
|
||||
}
|
||||
|
||||
// Entity getters by norm data references
|
||||
|
||||
/**
|
||||
* Data provider for norm data reference for actors.
|
||||
*
|
||||
* @return array<array{0: MDNodaLink, 1: integer}>
|
||||
*/
|
||||
public static function nodaRefForActorsProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$nodaSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `noda_link`, `persinst_id`
|
||||
FROM `noda`
|
||||
WHERE `noda_source` = 'Wikidata'
|
||||
AND `noda_link` != ''");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Valid actor ID by norm data reference: ' . $nodaSimple[0] => [
|
||||
new MDNodaLink(MDNodaRepository::wikidata, $nodaSimple[0]),
|
||||
$nodaSimple[1],
|
||||
],
|
||||
'Invalid, non-existing Wikidata ID' => [
|
||||
new MDNodaLink(MDNodaRepository::wikidata, 'Q11111111111111'),
|
||||
0,
|
||||
],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting actor ID by norm data reference.
|
||||
*
|
||||
* @param MDNodaLink $link Noda link.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('nodaRefForActorsProvider')]
|
||||
public function testGetPersinstByNodaLinkWorks(MDNodaLink $link, int $expected_id):void {
|
||||
|
||||
self::assertEquals($expected_id, NodaIDGetter::getPersinstIDByNodaLink($this->_mysqli, $link));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for norm data reference for places.
|
||||
*
|
||||
* @return array<array{0: MDNodaLink, 1: integer}>
|
||||
*/
|
||||
public static function nodaRefForPlacesProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$nodaSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `noda_link`, `ort_id`
|
||||
FROM `noda_orte`
|
||||
WHERE `noda_source` = 'Wikidata'
|
||||
AND `noda_link` != ''");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Valid place ID by norm data reference: ' . $nodaSimple[0] => [
|
||||
new MDNodaLink(MDNodaRepository::wikidata, $nodaSimple[0]),
|
||||
$nodaSimple[1],
|
||||
],
|
||||
'Invalid, non-existing Wikidata ID' => [
|
||||
new MDNodaLink(MDNodaRepository::wikidata, 'Q11111111111111'),
|
||||
0,
|
||||
],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting place ID by norm data reference.
|
||||
*
|
||||
* @param MDNodaLink $link Noda link.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('nodaRefForPlacesProvider')]
|
||||
public function testGetPlaceByNodaLinkWorks(MDNodaLink $link, int $expected_id):void {
|
||||
|
||||
self::assertEquals($expected_id, NodaIDGetter::getPlaceIDByNodaLink($this->_mysqli, $link));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for norm data reference for tags.
|
||||
*
|
||||
* @return array<array{0: MDNodaLink, 1: integer}>
|
||||
*/
|
||||
public static function nodaRefForTagsProvider():array {
|
||||
|
||||
$mysqli = md_noda_mysqli_connect();
|
||||
$nodaSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `noda_link`, `tag_id`
|
||||
FROM `noda_tag`
|
||||
WHERE `noda_source` = 'Wikidata'
|
||||
AND `noda_link` != ''");
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Valid tag ID by norm data reference: ' . $nodaSimple[0] => [
|
||||
new MDNodaLink(MDNodaRepository::wikidata, $nodaSimple[0]),
|
||||
$nodaSimple[1],
|
||||
],
|
||||
'Invalid, non-existing Wikidata ID' => [
|
||||
new MDNodaLink(MDNodaRepository::wikidata, 'Q11111111111111'),
|
||||
0,
|
||||
],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting tag ID by norm data reference.
|
||||
*
|
||||
* @param MDNodaLink $link Noda link.
|
||||
* @param integer $expected_id Expected target ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('nodaRefForTagsProvider')]
|
||||
public function testGetTagByNodaLinkWorks(MDNodaLink $link, int $expected_id):void {
|
||||
|
||||
self::assertEquals($expected_id, NodaIDGetter::getTagIDByNodaLink($this->_mysqli, $link));
|
||||
|
||||
}
|
||||
}
|
@ -6,12 +6,14 @@
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Small;
|
||||
|
||||
/**
|
||||
* This script contains tests for the actor name splitter.
|
||||
*
|
||||
* @covers \NodaNameSplitter
|
||||
*/
|
||||
#[Small]
|
||||
#[CoversClass(\NodaIDGetter::class)]
|
||||
final class NodaNameSplitterTest extends TestCase {
|
||||
/**
|
||||
* Test to check whether the HTML page is correctly generated.
|
||||
|
50
tests/NodaTagRelationIdentifierTest.php
Normal file
50
tests/NodaTagRelationIdentifierTest.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Tests for the identification of tag relation types to objects based on input tag names.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Small;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
/**
|
||||
* This script contains tests for the uncertainty helper.
|
||||
*/
|
||||
#[small]
|
||||
#[CoversClass(\NodaTagRelationIdentifier::class)]
|
||||
final class NodaTagRelationIdentifierTest extends TestCase {
|
||||
/**
|
||||
* Returns input tag names with and without known suffixes signaling the relation type.
|
||||
*
|
||||
* @return array<array{0: string, 1: string, 2: false|MDTagRelationType}>
|
||||
*/
|
||||
public static function tagNameAndRelationTypeProvider():array {
|
||||
|
||||
return [
|
||||
'Delfin' => ["Delfin", "Delfin", false],
|
||||
'Delfin (Motiv)' => ["Delfin (Motiv)", "Delfin", MDTagRelationType::display_subject],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to ensure times are correctly cleaned and parsed.
|
||||
*
|
||||
* @param string $term Term to check.
|
||||
* @param string $target_output Expected output name.
|
||||
* @param false|MDTagRelationType $target_type Expected identified relation type (or false for lack thereof).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('tagNameAndRelationTypeProvider')]
|
||||
public function testIdentificationWorksCorrectly(string $term, string $target_output, false|MDTagRelationType $target_type):void {
|
||||
|
||||
$identification = new NodaTagRelationIdentifier("de", $term);
|
||||
self::assertEquals($target_output, $identification->name);
|
||||
self::assertEquals($target_type, $identification->relation);
|
||||
|
||||
}
|
||||
}
|
@ -6,12 +6,14 @@
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Medium;
|
||||
|
||||
/**
|
||||
* This script contains tests for the automatic translation class for time names.
|
||||
*
|
||||
* @covers \NodaTimeAutotranslater
|
||||
*/
|
||||
#[Medium]
|
||||
#[CoversClass(\NodaIDGetter::class)]
|
||||
final class NodaTimeAutotranslaterTest extends TestCase {
|
||||
/**
|
||||
* Test to check whether the HTML page is correctly generated.
|
||||
@ -32,7 +34,7 @@ final class NodaTimeAutotranslaterTest extends TestCase {
|
||||
"zeit_zaehlzeit_tag" => "01",
|
||||
];
|
||||
$output = NodaTimeAutotranslater::getTranslations($timeInfo);
|
||||
self::assertEquals($output["de"], "01.05.1920");
|
||||
self::assertEquals("01.05.1920", $output["de"]);
|
||||
|
||||
}
|
||||
|
||||
@ -671,4 +673,23 @@ final class NodaTimeAutotranslaterTest extends TestCase {
|
||||
self::assertEquals($output["de"], "Vor 01.12.1919");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to check whether validating works.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidation():void {
|
||||
|
||||
$output = [
|
||||
'de' => '1.12.1920',
|
||||
];
|
||||
|
||||
self::assertFalse(NodaTimeAutotranslater::validateTranslations("1919", "1919", $output));
|
||||
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,110 +6,124 @@
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Small;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
/**
|
||||
* This script contains tests for the uncertainty helper.
|
||||
*
|
||||
* @covers \NodaUncertaintyHelper
|
||||
*/
|
||||
#[small]
|
||||
#[CoversClass(\NodaUncertaintyHelper::class)]
|
||||
final class NodaUncertaintyHelperTest extends TestCase {
|
||||
/**
|
||||
* Removes uncertainty indicators from an time name.
|
||||
* Returns time names with expected cleaned version and expected parsed certainty.
|
||||
*
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
* @return array<array{0: string, 1: string, 2: boolean}>
|
||||
*/
|
||||
public function testCleanUncertaintyIndicatorsTime():void {
|
||||
public static function uncertainTimesProvider():array {
|
||||
|
||||
self::assertEquals("1950", NodaUncertaintyHelper::cleanUncertaintyIndicatorsTime("wohl 1950"));
|
||||
self::assertEquals("1950", NodaUncertaintyHelper::cleanUncertaintyIndicatorsTime("1950"));
|
||||
return [
|
||||
'uncertainty prefix: "wohl 1950"' => ["wohl 1950", "1950", false],
|
||||
'uncertainty suffix: "1950?"' => ["1950?", "1950", false],
|
||||
'uncertainty suffix and superfluous chars: "1950 ?,"' => ["1950 ?,", "1950", false],
|
||||
'certain term with superfluous chars: "1950 ,"' => ["1950 ,", "1950", true],
|
||||
'certain term: 1950' => ["1950", "1950", true],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts guessing whether time is uncertain.
|
||||
* Returns place names with expected cleaned version and expected parsed certainty.
|
||||
*
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
* @return array<array{0: string, 1: string, 2: boolean}>
|
||||
*/
|
||||
public function testGuessTimeCertainty():void {
|
||||
public static function uncertainPlacesProvider():array {
|
||||
|
||||
self::assertFalse(NodaUncertaintyHelper::guessTimeCertainty("wohl 1950"));
|
||||
self::assertTrue(NodaUncertaintyHelper::guessTimeCertainty("1950"));
|
||||
return [
|
||||
|
||||
'uncertainty prefix: "wohl Berlin"' => ["wohl Berlin", "Berlin", false],
|
||||
'uncertainty prefix: "vermutl. Berlin"' => ["vermutl. Berlin", "Berlin", false],
|
||||
'uncertainty prefix and superfluous chars: "?-Berlin"' => ["?-Berlin", "Berlin", false],
|
||||
'uncertainty suffix: "Berlin?"' => ["Berlin?", "Berlin", false],
|
||||
'uncertainty suffix: "Berlin (?)"' => ["Berlin (?)", "Berlin", false],
|
||||
'uncertainty suffix and superfluous chars: "Berlin ?,"' => ["Berlin ?,", "Berlin", false],
|
||||
'certain term with superfluous chars: "Berlin ,"' => ["Berlin ,", "Berlin", true],
|
||||
'certain term: Berlin' => ["Berlin", "Berlin", true],
|
||||
'Berlin ? (Deutschland)' => ["Berlin ? (Deutschland)", "Berlin (Deutschland)", false],
|
||||
'Berli?n (Deutschland)' => ["Berl?n (Deutschland)", "Berl?n (Deutschland)", true],
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes uncertainty indicators from an place name.
|
||||
* Returns actor names with expected cleaned version and expected parsed certainty.
|
||||
*
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
* @return array<array{0: string, 1: string, 2: boolean}>
|
||||
*/
|
||||
public static function testCleanUncertaintyIndicatorsPlace():void {
|
||||
public static function uncertainPersinstProvider():array {
|
||||
|
||||
self::assertEquals("Berlin", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPlace("wohl Berlin"));
|
||||
self::assertEquals("Berlin", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPlace("Berlin"));
|
||||
|
||||
// Real-life examples that previously passed unencumbered
|
||||
self::assertEquals("Augsburg", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPlace("vermutlich: Augsburg"));
|
||||
self::assertEquals("Augsburg", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPlace("vermutl. Augsburg"));
|
||||
return [
|
||||
'uncertainty prefix: "wohl Barbarossa"' => ["wohl Barbarossa", "Barbarossa", false],
|
||||
'uncertainty prefix: "vermutl. Barbarossa"' => ["vermutl. Barbarossa", "Barbarossa", false],
|
||||
'uncertainty prefix and superfluous chars: "?-Barbarossa"' => ["?-Barbarossa", "Barbarossa", false],
|
||||
'uncertainty suffix: "Barbarossa?"' => ["Barbarossa?", "Barbarossa", false],
|
||||
'uncertainty suffix and superfluous chars: "Barbarossa ?,"' => ["Barbarossa ?,", "Barbarossa", false],
|
||||
'certain term with superfluous chars: "Barbarossa ,"' => ["Barbarossa ,", "Barbarossa", true],
|
||||
'certain term: Barbarossa' => ["Barbarossa", "Barbarossa", true],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts guessing whether place is uncertain.
|
||||
* Test to ensure times are correctly cleaned and parsed.
|
||||
*
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
* @param string $term Term to check.
|
||||
* @param string $target_output Expected output name.
|
||||
* @param boolean $target_certainty Expected output certainty.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function testGuessPlaceCertainty():void {
|
||||
#[DataProvider('uncertainTimesProvider')]
|
||||
public function testParsingUncertaintyFromTimes(string $term, string $target_output, bool $target_certainty):void {
|
||||
|
||||
self::assertFalse(NodaUncertaintyHelper::guessPlaceCertainty("vermutlich: Augsburg"));
|
||||
self::assertFalse(NodaUncertaintyHelper::guessPlaceCertainty("vermutl. Augsburg"));
|
||||
|
||||
self::assertFalse(NodaUncertaintyHelper::guessPlaceCertainty("wohl Berlin"));
|
||||
self::assertTrue(NodaUncertaintyHelper::guessPlaceCertainty("Berlin"));
|
||||
|
||||
self::assertFalse(NodaUncertaintyHelper::guessPlaceCertainty("?-Italien"));
|
||||
self::assertEquals($target_output, NodaUncertaintyHelper::cleanUncertaintyIndicatorsTime($term));
|
||||
self::assertEquals($target_certainty, NodaUncertaintyHelper::guessTimeCertainty($term));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes uncertainty indicators from an actor name.
|
||||
* Test to ensure places are correctly cleaned and parsed.
|
||||
*
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
* @param string $term Term to check.
|
||||
* @param string $target_output Expected output name.
|
||||
* @param boolean $target_certainty Expected output certainty.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function testCleanUncertaintyIndicatorsPersinst():void {
|
||||
#[DataProvider('uncertainPlacesProvider')]
|
||||
public function testParsingUncertaintyFromPlaces(string $term, string $target_output, bool $target_certainty):void {
|
||||
|
||||
self::assertEquals("Barbarossa", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPersinst("wohl Barbarossa"));
|
||||
self::assertEquals("Barbarossa", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPersinst("Barbarossa"));
|
||||
self::assertEquals("Barbarossa", NodaUncertaintyHelper::cleanUncertaintyIndicatorsPersinst("?-Barbarossa"));
|
||||
self::assertEquals($target_output, NodaUncertaintyHelper::cleanUncertaintyIndicatorsPlace($term));
|
||||
self::assertEquals($target_certainty, NodaUncertaintyHelper::guessPlaceCertainty($term));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts guessing whether persinst is uncertain.
|
||||
* Test to ensure actor names are correctly cleaned and parsed.
|
||||
*
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
* @param string $term Term to check.
|
||||
* @param string $target_output Expected output name.
|
||||
* @param boolean $target_certainty Expected output certainty.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function testGuessPersinstCertainty():void {
|
||||
#[DataProvider('uncertainPersinstProvider')]
|
||||
public function testParsingUncertaintyFromPersinst(string $term, string $target_output, bool $target_certainty):void {
|
||||
|
||||
self::assertFalse(NodaUncertaintyHelper::guessPlaceCertainty("wohl Barbarossa"));
|
||||
self::assertTrue(NodaUncertaintyHelper::guessPlaceCertainty("Barbarossa"));
|
||||
self::assertEquals($target_output, NodaUncertaintyHelper::cleanUncertaintyIndicatorsPersinst($term));
|
||||
self::assertEquals($target_certainty, NodaUncertaintyHelper::guessPersinstCertainty($term));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,19 +5,20 @@
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Small;
|
||||
|
||||
/**
|
||||
* This script contains tests for the validation of single field contents.
|
||||
*
|
||||
* @covers \NodaValidationHelper
|
||||
*/
|
||||
#[small]
|
||||
#[CoversClass(\NodaValidationHelper::class)]
|
||||
final class NodaValidationHelperTest extends TestCase {
|
||||
/**
|
||||
* Test that a specific error is thrown if no description for actors is provided.
|
||||
*
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testActorDescriptionValidationFailsOnEmptyInput():void {
|
||||
@ -30,8 +31,6 @@ final class NodaValidationHelperTest extends TestCase {
|
||||
/**
|
||||
* Test successfully refusing too short actor descriptions.
|
||||
*
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testActorDescriptionValidationFailsOnTooShortInput():void {
|
||||
@ -44,8 +43,6 @@ final class NodaValidationHelperTest extends TestCase {
|
||||
/**
|
||||
* Test successfully refusing actor descriptions that have too few distinct characters.
|
||||
*
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testActorDescriptionValidationFailsOnTooFewDistinctCharacters():void {
|
||||
@ -58,8 +55,6 @@ final class NodaValidationHelperTest extends TestCase {
|
||||
/**
|
||||
* Test successfully refusing actor descriptions that simply duplicate the actor name.
|
||||
*
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testActorDescriptionValidationFailsOnDuplicatedActorNames():void {
|
||||
@ -80,8 +75,6 @@ final class NodaValidationHelperTest extends TestCase {
|
||||
/**
|
||||
* Test that a valid description is accepted.
|
||||
*
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testActorDescriptionValidationAcceptsValidDescription():void {
|
||||
@ -90,4 +83,68 @@ final class NodaValidationHelperTest extends TestCase {
|
||||
self::assertTrue(true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a specific error is thrown if no description for tags is provided.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTagDescriptionValidationFailsOnEmptyInput():void {
|
||||
|
||||
$this->expectException(MDInvalidEmptyInputException::class);
|
||||
NodaValidationHelper::validateTagDescription("");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successfully refusing too short tag descriptions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTagDescriptionValidationFailsOnTooShortInput():void {
|
||||
|
||||
$this->expectException(MDgenericInvalidInputsException::class);
|
||||
NodaValidationHelper::validateTagDescription("abc");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successfully refusing tag descriptions that have too few distinct characters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTagDescriptionValidationFailsOnTooFewDistinctCharacters():void {
|
||||
|
||||
$this->expectException(MDgenericInvalidInputsException::class);
|
||||
NodaValidationHelper::validateTagDescription("aaaaaaaaaaaa");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successfully refusing tag descriptions that simply duplicate the tag name.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTagDescriptionValidationFailsOnDuplicatedTagNames():void {
|
||||
|
||||
$this->expectException(MDgenericInvalidInputsException::class);
|
||||
NodaValidationHelper::validateTagDescription("Richard Lepsius", "Richard Lepsius");
|
||||
$this->expectException(MDgenericInvalidInputsException::class);
|
||||
NodaValidationHelper::validateTagDescription("Richard Lepsius", "Lepsius Richard");
|
||||
$this->expectException(MDgenericInvalidInputsException::class);
|
||||
NodaValidationHelper::validateTagDescription("Lepsius, Richard", "Lepsius, Richard");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a valid description is accepted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTagDescriptionValidationAcceptsValidDescription():void {
|
||||
|
||||
NodaValidationHelper::validateTagDescription("Richard Lepsius war ein Forscher", "Richard Lepsius");
|
||||
self::assertTrue(true);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,28 @@
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Medium;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
require_once __DIR__ . '/../../MDMysqli/test_connections.conf.php';
|
||||
require_once __DIR__ . '/../src/NodaWikidataFetcherDisambiguationIsDisallowedException.php';
|
||||
|
||||
/**
|
||||
* This script contains tests for the Wikidata fetcher.
|
||||
*
|
||||
* @covers \NodaWikidataFetcher
|
||||
*/
|
||||
#[medium]
|
||||
#[CoversClass(\NodaWikidataFetcher::class)]
|
||||
final class NodaWikidataFetcherTest extends TestCase {
|
||||
|
||||
// Test for getting translations: Telugu
|
||||
public const TEST_LANG = 'te';
|
||||
|
||||
/**
|
||||
* Test to check whether the HTML page is correctly generated.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -29,12 +38,39 @@ final class NodaWikidataFetcherTest extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider providing a Wikidata ID for a dedicated wikidata item for disambiguation pages.
|
||||
*
|
||||
* @return array<string, array{0: string}>
|
||||
*/
|
||||
public static function disambiguationPageProvider():array {
|
||||
|
||||
return [
|
||||
'Disambiguation page for "Mochi" - Q6916210' => ['Q6916210'],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw error when attempting to load a dedicated wikidata entry for a disambiguation page.
|
||||
*
|
||||
* @param string $wikidata_id Wikidata ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('disambiguationPageProvider')]
|
||||
public function testWikidataIdFromLinkFailsForDisambiguationPages(string $wikidata_id):void {
|
||||
|
||||
self::expectException(NodaWikidataFetcherDisambiguationIsDisallowedException::class);
|
||||
NodaWikidataFetcher::getWikidataEntity($wikidata_id);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to check whether the HTML page is correctly generated.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -47,9 +83,7 @@ final class NodaWikidataFetcherTest extends TestCase {
|
||||
/**
|
||||
* Test to check whether the HTML page is correctly generated.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -60,225 +94,208 @@ final class NodaWikidataFetcherTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for cleaning wikidata info.
|
||||
* Data provider for an actor that has a wikidata link and a Telugu translation.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
*
|
||||
* @return void
|
||||
* @return array<string, array{0: int, 1: string}>
|
||||
*/
|
||||
public function testCleanWikidataInput():void {
|
||||
public static function actorWithTlAndWikidataLinkProvider():array {
|
||||
|
||||
$testStr = '"<div class="mw-parser-output"><table class="infobox float-right toccolours toptextcells" style="margin: 0 0 1em 1em; width: 300px;" id="Vorlage_Infobox_Ort_in_der_Ukraine" summary="Infobox Ort in der Ukraine">
|
||||
$mysqli = md_main_mysqli_connect();
|
||||
|
||||
<tbody><tr>
|
||||
<td colspan="2" style="background-color:#AFD6FF; font-size:1.3em; font-weight:bold; text-align:center;">Werbowez (Kossiw)
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td colspan="2" style="background-color:#FFC; font-size:1em; font-weight:bold; text-align:center;"><span lang="uk-Cyrl" class="Cyrl">Вербовець</span>
|
||||
</td></tr>
|
||||
$result = $mysqli->do_read_query("SELECT `persinst_id`, `noda_nrinsource`
|
||||
FROM `" . DATABASENAME_NODA . "`.`noda`
|
||||
WHERE `noda_source` = 'Wikidata'
|
||||
AND EXISTS (SELECT 1 FROM `" . DATABASENAME_NODA . "`.`persinst_translation`
|
||||
WHERE `persinst_translation`.`persinst_id` = `noda`.`persinst_id`
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "')");
|
||||
|
||||
if (!$cur = $result->fetch_row()) {
|
||||
throw new Exception("Failed to identify an entry that has a wikidata entry and a translation for language " . self::TEST_LANG);
|
||||
}
|
||||
$result->close();
|
||||
$mysqli->close();
|
||||
|
||||
<tr style="height:120px; background-color:#FFF;">
|
||||
<td style="width: 130px; text-align:center;"><span typeof="mw:File"><a href="/wiki/Datei:Coats_of_arms_of_None.svg" class="mw-file-description" title="Wappen fehlt"><img alt="Wappen fehlt" src="//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Coats_of_arms_of_None.svg/100px-Coats_of_arms_of_None.svg.png" decoding="async" width="100" height="120" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Coats_of_arms_of_None.svg/150px-Coats_of_arms_of_None.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Coats_of_arms_of_None.svg/200px-Coats_of_arms_of_None.svg.png 2x" data-file-width="125" data-file-height="150" /></a></span>
|
||||
</td>
|
||||
<td style="width: 170px; text-align:center;"><table class="centered" style="background-color: #f9f9f9; border: none; border-collapse: collapse; width: 1px;">
|
||||
<tbody><tr><td style="border: none; padding: 0; text-align: center;"><div style="position: relative; z-index: 0; padding: 0; display: inline-block; width: -webkit-max-content; width: -moz-max-content; width: max-content; border: none;"><figure class="mw-halign-center noviewer notpageimage" typeof="mw:File"><a href="/wiki/Datei:Ukraine_adm_location_map.svg" class="mw-file-description" title="Werbowez (Kossiw) (Ukraine)"><img alt="Werbowez (Kossiw) (Ukraine)" src="//upload.wikimedia.org/wikipedia/commons/thumb/7/78/Ukraine_adm_location_map.svg/180px-Ukraine_adm_location_map.svg.png" decoding="async" width="180" height="121" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/7/78/Ukraine_adm_location_map.svg/270px-Ukraine_adm_location_map.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/7/78/Ukraine_adm_location_map.svg/360px-Ukraine_adm_location_map.svg.png 2x" data-file-width="1546" data-file-height="1038" /></a><figcaption>Werbowez (Kossiw) (Ukraine)</figcaption></figure><div style="position:absolute; top:50.7%; left:18.9%; height:0; width:0;"><div style="position:relative;z-index:100;left:-4px;top:-4px;width:8px;height:8px;line-height:0px;"><span typeof="mw:File"><a href="https://geohack.toolforge.org/geohack.php?pagename=Werbowez_(Kossiw)&language=de&params=48.342222222222_N_25.133333333333_E_dim:10000_region:UA-26_type:city(3395)&title=Werbowez+%28Kossiw%29" title="Werbowez (Kossiw) (48° 20′ 32″ N, 25° 8′ 0″O)"><img alt="" src="//upload.wikimedia.org/wikipedia/commons/thumb/9/97/ButtonRed.svg/8px-ButtonRed.svg.png" decoding="async" width="8" height="8" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/9/97/ButtonRed.svg/12px-ButtonRed.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/9/97/ButtonRed.svg/16px-ButtonRed.svg.png 2x" data-file-width="480" data-file-height="480" /></a></span></div>
|
||||
<table style="font-size:90%; border:none; background-color:transparent; border-collapse:collapse; line-height:1em; position:absolute; width:6em; margin: 0 .2em; text-align:left; left:1px; bottom:1px;"><tbody><tr><td style="border:none; vertical-align:middle;"><span style="position:relative; z-index:9; background-color:none;">Werbowez (Kossiw) </span></td></tr></tbody></table></div></div></td></tr>
|
||||
</tbody></table>
|
||||
</td></tr>
|
||||
<tr style="background-color:#AFD6FF;">
|
||||
<th colspan="2">Basisdaten
|
||||
</th></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Liste_der_Oblaste_der_Ukraine" title="Liste der Oblaste der Ukraine">Oblast</a>:</td>
|
||||
<td><a href="/wiki/Oblast_Iwano-Frankiwsk" title="Oblast Iwano-Frankiwsk">Oblast Iwano-Frankiwsk</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Liste_der_Rajone_der_Ukraine" title="Liste der Rajone der Ukraine">Rajon</a>:</td>
|
||||
<td><a href="/wiki/Rajon_Kossiw" title="Rajon Kossiw">Rajon Kossiw</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/H%C3%B6he_%C3%BCber_dem_Meeresspiegel" title="Höhe über dem Meeresspiegel">Höhe</a>:</td>
|
||||
<td>369 m
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Fl%C3%A4cheninhalt" title="Flächeninhalt">Fläche</a>:</td>
|
||||
<td>18,77 <a href="/wiki/Quadratmeter#Quadratkilometer" title="Quadratmeter">km²</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Einwohner" title="Einwohner">Einwohner</a>:</td>
|
||||
<td>3.395 <small><i>(2001)</i></small>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Bev%C3%B6lkerungsdichte" title="Bevölkerungsdichte">Bevölkerungsdichte</a>:
|
||||
</td>
|
||||
<td>181 Einwohner je km²
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Postleitzahl" title="Postleitzahl">Postleitzahlen</a>:</td>
|
||||
<td>78605
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Telefonvorwahl" title="Telefonvorwahl">Vorwahl</a>:</td>
|
||||
<td>+380 3478
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Geographische_Koordinaten" title="Geographische Koordinaten">Geographische Lage</a>:</td>
|
||||
<td><span id="text_coordinates" class="coordinates plainlinks-print"><a class="external text" href="https://geohack.toolforge.org/geohack.php?pagename=Werbowez_(Kossiw)&language=de&params=48.342222222222_N_25.133333333333_E_dim:10000_region:UA-26_type:city(3395)"><span title="Breitengrad">48° 21′ <abbr title="Nord">N</abbr></span>, <span title="Längengrad">25° 8′ <abbr title="Ost">O</abbr></span></a></span><span class="geo noexcerpt" style="display:none"><span class="body"></span><span class="latitude">48.342222222222</span><span class="longitude">25.133333333333</span><span class="elevation"></span></span><span id="coordinates" class="coordinates noprint"><span title="Koordinatensystem WGS84">Koordinaten: </span><a class="external text" href="https://geohack.toolforge.org/geohack.php?pagename=Werbowez_(Kossiw)&language=de&params=48.342222222222_N_25.133333333333_E_dim:10000_region:UA-26_type:city(3395)"><span title="Breitengrad">48° 20′ 32″ <abbr title="Nord">N</abbr></span>, <span title="Längengrad">25° 8′ 0″ <abbr title="Ost">O</abbr></span></a></span>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/KATOTTH" title="KATOTTH">KATOTTH</a>:
|
||||
</td>
|
||||
<td>UA26100010030094355
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/KOATUU" title="KOATUU">KOATUU</a>:
|
||||
</td>
|
||||
<td>2623682401
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Verwaltungsgliederung_der_Ukraine" title="Verwaltungsgliederung der Ukraine">Verwaltungsgliederung</a>:
|
||||
</td>
|
||||
<td>1 Dorf
|
||||
</td></tr>
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td>Adresse:
|
||||
</td>
|
||||
<td>вул. Миру, буд. 15<br />78605 с. Вербовець
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><a href="/wiki/Website" title="Website">Website</a>:
|
||||
</td>
|
||||
<td><a rel="nofollow" class="external text" href="http://verbovets.kosiv.net/">Offizielle Webseite</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td colspan="2" style="padding-bottom:3px; text-align:center; border-bottom:1px solid #bbb; border-top:1px solid #bbb;"><a rel="nofollow" class="external text" href="http://w1.c1.rada.gov.ua/pls/z7503/A005?rdat1=31.08.2023&rf7571=13801">Statistische Informationen</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td colspan="2" style="padding-bottom:3px; text-align:center; border-bottom:1px solid #bbb; border-top:1px solid #bbb;">
|
||||
<table class="centered" style="background-color: #f9f9f9; border: none; border-collapse: collapse; width: 1px;">
|
||||
<tbody><tr><td style="border: none; padding: 0; text-align: center;"><div style="position: relative; z-index: 0; padding: 0; display: inline-block; width: -webkit-max-content; width: -moz-max-content; width: max-content; border: none;"><figure class="mw-halign-center noviewer notpageimage" typeof="mw:File"><a href="/wiki/Datei:Ivano-Frankivsk_location_map.svg" class="mw-file-description" title="Werbowez (Kossiw) (Oblast Iwano-Frankiwsk)"><img alt="Werbowez (Kossiw) (Oblast Iwano-Frankiwsk)" src="//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Ivano-Frankivsk_location_map.svg/290px-Ivano-Frankivsk_location_map.svg.png" decoding="async" width="290" height="347" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Ivano-Frankivsk_location_map.svg/435px-Ivano-Frankivsk_location_map.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Ivano-Frankivsk_location_map.svg/580px-Ivano-Frankivsk_location_map.svg.png 2x" data-file-width="533" data-file-height="637" /></a><figcaption>Werbowez (Kossiw) (Oblast Iwano-Frankiwsk)</figcaption></figure><div style="position:absolute; top:63.3%; left:74.4%; height:0; width:0;"><div style="position:relative;z-index:100;left:-4px;top:-4px;width:8px;height:8px;line-height:0px;"><span typeof="mw:File"><a href="https://geohack.toolforge.org/geohack.php?pagename=Werbowez_(Kossiw)&language=de&params=48.342222222222_N_25.133333333333_E_dim:10000_region:UA-26_type:city(3395)&title=Werbowez+%28Kossiw%29" title="Werbowez (Kossiw) (48° 20′ 32″ N, 25° 8′ 0″O)"><img alt="" src="//upload.wikimedia.org/wikipedia/commons/thumb/9/97/ButtonRed.svg/8px-ButtonRed.svg.png" decoding="async" width="8" height="8" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/9/97/ButtonRed.svg/12px-ButtonRed.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/9/97/ButtonRed.svg/16px-ButtonRed.svg.png 2x" data-file-width="480" data-file-height="480" /></a></span></div>
|
||||
<table style="font-size:90%; border:none; background-color:transparent; border-collapse:collapse; line-height:1em; position:absolute; width:6em; margin: 0 .2em; text-align:right; right:1px; bottom:1px;"><tbody><tr><td style="border:none; vertical-align:middle;"><span style="position:relative; z-index:9; background-color:none;">Werbowez (Kossiw) </span></td></tr></tbody></table></div></div></td></tr>
|
||||
</tbody></table><span style="display:none;"><a href="/w/index.php?title=Vorlage:Positionskarte_ISO_3166-2/Wartung/noregion&action=edit&redlink=1" class="new" title="Vorlage:Positionskarte ISO 3166-2/Wartung/noregion (Seite nicht vorhanden)">i1</a></span>
|
||||
</td></tr></tbody></table>
|
||||
<p><b>Werbowez</b> (<b><span style="font-style:normal;font-weight:normal"><a href="/wiki/Ukrainische_Sprache" title="Ukrainische Sprache">ukrainisch</a></span> <span lang="uk-Cyrl" class="Cyrl" style="font-style:normal">Вербовець</span></b>; <span style="font-style:normal;font-weight:normal"><a href="/wiki/Russische_Sprache" title="Russische Sprache">russisch</a></span> <span lang="ru-Cyrl" class="Cyrl" style="font-style:normal">Вербовец</span>, <a href="/wiki/Polnische_Sprache" title="Polnische Sprache">polnisch</a> <span lang="pl" style="font-style:italic;font-weight:normal">Wierzbowiec</span>; <span style="font-style:normal;font-weight:normal"><a href="/wiki/Rum%C3%A4nische_Sprache" title="Rumänische Sprache">rumänisch</a></span> <span lang="ro-Latn" style="font-style:italic">Verboveț</span>) ist ein <a href="/wiki/Dorf" title="Dorf">Dorf</a> in der <a href="/wiki/Ukraine" title="Ukraine">ukrainischen</a> <a href="/wiki/Oblast_Iwano-Frankiwsk" title="Oblast Iwano-Frankiwsk">Oblast Iwano-Frankiwsk</a> mit etwa 3400 Einwohnern (2001).<sup id="cite_ref-1" class="reference"><a href="#cite_note-1">[1]</a></sup>
|
||||
</p>
|
||||
<figure class="mw-default-size mw-halign-left" typeof="mw:File/Thumb"><a href="/wiki/Datei:%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG" class="mw-file-description"><img src="//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG/220px-%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG" decoding="async" width="220" height="147" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG/330px-%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/9/9d/%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG/440px-%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG 2x" data-file-width="5184" data-file-height="3456" /></a><figcaption>Blick auf das Dorf</figcaption></figure>
|
||||
<p>Das um 1650 erstmals schriftlich erwähnte Dorf<sup id="cite_ref-2" class="reference"><a href="#cite_note-2">[2]</a></sup> liegt im Osten der <a href="/wiki/Historische_Landschaft" title="Historische Landschaft">historischen Landschaft</a> <a href="/wiki/Galizien" title="Galizien">Galizien</a> am Ufer der <a href="/w/index.php?title=Rybnyzja_(Fluss)&action=edit&redlink=1" class="new" title="Rybnyzja (Fluss) (Seite nicht vorhanden)">Rybnyzja</a> (<span lang="uk-Cyrl" class="Cyrl">Рибниця</span>), einem 56 km langen Nebenfluss des <a href="/wiki/Pruth" title="Pruth">Pruth</a> 7 km nordöstlich vom Rajonzentrum <a href="/wiki/Kossiw" title="Kossiw">Kossiw</a> und 95 km südlich vom Oblastzentrum <a href="/wiki/Iwano-Frankiwsk" title="Iwano-Frankiwsk">Iwano-Frankiwsk</a>. Südlich der Ortschaft verläuft die <a href="/wiki/Territorialstra%C3%9Fe" title="Territorialstraße">Territorialstraße</a> <i>T–09–09</i>.
|
||||
</p><p>Am 12. Juni 2020 wurde das Dorf ein Teil der neu gegründeten <i>Stadtgemeinde <a href="/wiki/Kossiw" title="Kossiw">Kossiw</a></i> im <a href="/wiki/Rajon_Kossiw" title="Rajon Kossiw">Rajon Kossiw</a><sup id="cite_ref-3" class="reference"><a href="#cite_note-3">[3]</a></sup>, bis dahin bildete es zusammen mit dem Dorf <a href="/w/index.php?title=Staryj_Kossiw&action=edit&redlink=1" class="new" title="Staryj Kossiw (Seite nicht vorhanden)">Staryj Kossiw</a> (<span lang="uk-Cyrl" class="Cyrl">Старий Косів</span>) die <i>Landratsgemeinde Werbowez</i> (Вербовецька сільська рада/<i>Werbowezka silska rada</i>) im Osten des Rajons.
|
||||
</p>
|
||||
<ol class="references">
|
||||
<li id="cite_note-1"><span class="mw-cite-backlink"><a href="#cite_ref-1">↑</a></span> <span class="reference-text"><a rel="nofollow" class="external text" href="http://w1.c1.rada.gov.ua/pls/z7503/A005?rf7571=13801">Ortswebseite</a> auf der offiziellen Webpräsenz der <a href="/wiki/Werchowna_Rada" title="Werchowna Rada">Werchowna Rada</a>; abgerufen am 14. November 2017 (ukrainisch)</span>
|
||||
</li>
|
||||
<li id="cite_note-2"><span class="mw-cite-backlink"><a href="#cite_ref-2">↑</a></span> <span class="reference-text"><a rel="nofollow" class="external text" href="http://ukrssr.com.ua/ifrank/kosivskiy/verbovets-kosivskiy-rayon-ivano-frankivska-oblast">Ortsgeschichte Werbowez</a> in der <a href="/wiki/Geschichte_der_St%C3%A4dte_und_D%C3%B6rfer_der_Ukrainischen_SSR" title="Geschichte der Städte und Dörfer der Ukrainischen SSR">Geschichte der Städte und Dörfer der Ukrainischen SSR</a>; abgerufen am 14. November 2017 (ukrainisch)</span>
|
||||
</li>
|
||||
<li id="cite_note-3"><span class="mw-cite-backlink"><a href="#cite_ref-3">↑</a></span> <span class="reference-text"><a rel="nofollow" class="external text" href="https://zakon.rada.gov.ua/laws/show/714-2020-%D1%80#Text">Кабінет Міністрів України Розпорядження від 12 червня 2020 р. № 714-р "Про визначення адміністративних центрів та затвердження територій територіальних громад Івано-Франківської області"</a></span>
|
||||
</li>
|
||||
</ol>
|
||||
<!--
|
||||
NewPP limit report
|
||||
Parsed by mw1396
|
||||
Cached time: 20230831121013
|
||||
Cache expiry: 42588
|
||||
Reduced expiry: true
|
||||
Complications: []
|
||||
CPU time usage: 0.219 seconds
|
||||
Real time usage: 0.274 seconds
|
||||
Preprocessor visited node count: 6414/1000000
|
||||
Post‐expand include size: 33611/2097152 bytes
|
||||
Template argument size: 12317/2097152 bytes
|
||||
Highest expansion depth: 34/100
|
||||
Expensive parser function count: 9/500
|
||||
Unstrip recursion depth: 0/20
|
||||
Unstrip post‐expand size: 1476/5000000 bytes
|
||||
Lua time usage: 0.080/10.000 seconds
|
||||
Lua memory usage: 3398800/52428800 bytes
|
||||
Number of Wikibase entities loaded: 0/400
|
||||
-->
|
||||
<!--
|
||||
Transclusion expansion time report (%,ms,calls,template)
|
||||
100.00% 239.600 1 -total
|
||||
93.55% 224.134 1 Vorlage:Infobox_Ort_in_der_Ukraine
|
||||
50.81% 121.740 2 Vorlage:Positionskarte
|
||||
49.72% 119.121 2 Vorlage:Positionskarte+
|
||||
44.41% 106.401 2 Vorlage:Positionskarte~
|
||||
33.28% 79.732 2 Vorlage:Positionskarte~*
|
||||
25.69% 61.558 3 Vorlage:Lang
|
||||
19.41% 46.499 1 Vorlage:Positionskarte_ISO_3166-2
|
||||
16.90% 40.486 12 Vorlage:CoordinateLONG
|
||||
14.02% 33.586 10 Vorlage:CoordinateLAT
|
||||
-->
|
||||
</div>" - (de.wikipedia.org 31.08.2023)';
|
||||
|
||||
$output = NodaWikidataFetcher::cleanWikidataInput($testStr);
|
||||
$expected = 'Werbowez (ukrainisch Вербовець; russisch Вербовец, polnisch Wierzbowiec; rumänisch Verboveț) ist ein Dorf in der ukrainischen Oblast Iwano-Frankiwsk mit etwa 3400 Einwohnern (2001).';
|
||||
self::assertTrue(
|
||||
str_starts_with($output, $expected),
|
||||
"Start of parsed Wikipedia text should be:" . PHP_EOL . PHP_EOL . $expected . PHP_EOL . PHP_EOL . 'Real start text is: ' . PHP_EOL . PHP_EOL . substr($output, 0, 250)
|
||||
);
|
||||
|
||||
$output = NodaWikidataFetcher::cleanWikidataInput('<div class="mw-parser-output"><figure class="mw-default-size mw-halign-right" typeof="mw:File/Thumb"><a href="/wiki/File:%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG" class="mw-file-description"><img src="//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG/220px-%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG" decoding="async" width="220" height="147" class="mw-file-element" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG/330px-%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/9/9d/%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG/440px-%D0%92%D0%B5%D1%80%D0%B1%D0%BE%D0%B2%D0%B5%D1%86%D1%8C.JPG 2x" data-file-width="5184" data-file-height="3456" /></a><figcaption></figcaption></figure>
|
||||
<p><span style="font-size: small;"><span id="coordinates"><a href="/wiki/%E5%9C%B0%E7%90%86%E5%9D%90%E6%A0%87" class="mw-redirect" title="地理坐标">坐标</a>:<style data-mw-deduplicate="TemplateStyles:r65292569">.mw-parser-output .geo-default,.mw-parser-output .geo-dms,.mw-parser-output .geo-dec{display:inline}.mw-parser-output .geo-nondefault,.mw-parser-output .geo-multi-punct{display:none}.mw-parser-output .longitude,.mw-parser-output .latitude{white-space:nowrap}</style><span class="plainlinks nourlexpansion"><a class="external text" href="//geohack.toolforge.org/geohack.php?language=zh&pagename=%E9%9F%8B%E7%88%BE%E5%8D%9A%E9%9F%8B%E9%BD%8A_(%E7%A7%91%E7%B4%A2%E5%A4%AB%E5%8D%80)&params=48_20_32_N_25_8_0_E_scale:30000"><span class="geo-default"><span class="geo-dms" title="此地的地图、航拍照片和其他数据"><span class="latitude">48°20′32″N</span> <span class="longitude">25°8′0″E</span></span></span><span class="geo-multi-punct"> / </span><span class="geo-nondefault"><span class="geo-dec" title="此地的地图、航拍照片和其他数据">48.34222°N 25.13333°E</span><span style="display:none"> / <span class="geo">48.34222; 25.13333</span></span></span></a></span></span></span>
|
||||
</p><p><b>韋爾博韋齊</b>(<a href="/wiki/%E7%83%8F%E5%85%8B%E8%98%AD%E8%AA%9E" class="mw-redirect" title="烏克蘭語">烏克蘭語</a>:<span lang="uk">Вербовець</span>),是<a href="/wiki/%E7%83%8F%E5%85%8B%E8%98%AD" class="mw-redirect" title="烏克蘭">烏克蘭</a>的村落,位於該國西部<a href="/wiki/%E4%BC%8A%E4%B8%87%E8%AF%BA-%E5%BC%97%E5%85%B0%E7%A7%91%E5%A4%AB%E6%96%AF%E5%85%8B%E5%B7%9E" title="伊万诺-弗兰科夫斯克州">伊萬諾-弗蘭科夫斯克州</a>,由<a href="/wiki/%E7%A7%91%E7%B4%A2%E5%A4%AB%E5%8D%80" class="mw-redirect" title="科索夫區">科索夫區</a>負責管轄,始建於1456年,面積18.77平方公里,2001年人口3,395。
|
||||
</p>
|
||||
<!--
|
||||
NewPP limit report
|
||||
Parsed by mw1412
|
||||
Cached time: 20230831132208
|
||||
Cache expiry: 1814400
|
||||
Reduced expiry: false
|
||||
Complications: []
|
||||
CPU time usage: 0.147 seconds
|
||||
Real time usage: 0.186 seconds
|
||||
Preprocessor visited node count: 48/1000000
|
||||
Post‐expand include size: 2084/2097152 bytes
|
||||
Template argument size: 0/2097152 bytes
|
||||
Highest expansion depth: 3/100
|
||||
Expensive parser function count: 1/500
|
||||
Unstrip recursion depth: 0/20
|
||||
Unstrip post‐expand size: 362/5000000 bytes
|
||||
Lua time usage: 0.110/10.000 seconds
|
||||
Lua memory usage: 15402517/52428800 bytes
|
||||
Number of Wikibase entities loaded: 1/400
|
||||
-->
|
||||
<!--
|
||||
Transclusion expansion time report (%,ms,calls,template)
|
||||
100.00% 152.989 1 -total
|
||||
70.07% 107.204 1 Template:Lang-uk
|
||||
29.62% 45.313 1 Template:Coord
|
||||
-->
|
||||
</div>');
|
||||
$expected = '韋爾博韋齊(烏克蘭語:Вербовець),是烏克蘭的村落,位於該國西部伊萬諾-弗蘭科夫斯克州,由科索夫區負責管轄,始建於1456年,面積18.77平方公里,2001年人口3,3';
|
||||
self::assertTrue(
|
||||
str_starts_with($output, $expected),
|
||||
"Start of parsed Wikipedia text should be:" . PHP_EOL . PHP_EOL . $expected . PHP_EOL . PHP_EOL . 'Real start text is: ' . PHP_EOL . PHP_EOL . substr($output, 0, 250)
|
||||
);
|
||||
return [
|
||||
'Actor with wikidata and translation' => [$cur[0], $cur[1]],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for cleaning wikidata info.
|
||||
* Data provider for a place that has a wikidata link and a Telugu translation.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
* @group ValidOutput
|
||||
* @small
|
||||
* @return array<string, array{0: int, 1: string}>
|
||||
*/
|
||||
public static function placeWithTlAndWikidataLinkProvider():array {
|
||||
|
||||
$mysqli = md_main_mysqli_connect();
|
||||
|
||||
$result = $mysqli->do_read_query("SELECT `ort_id`, `noda_nrinsource`
|
||||
FROM `" . DATABASENAME_NODA . "`.`noda_orte`
|
||||
WHERE `noda_source` = 'Wikidata'
|
||||
AND EXISTS (SELECT 1 FROM `" . DATABASENAME_NODA . "`.`ort_translation`
|
||||
WHERE `ort_translation`.`ort_id` = `noda_orte`.`ort_id`
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "')");
|
||||
|
||||
if (!$cur = $result->fetch_row()) {
|
||||
throw new Exception("Failed to identify an entry that has a wikidata entry and a translation for language " . self::TEST_LANG);
|
||||
}
|
||||
$result->close();
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Place with wikidata and translation' => [$cur[0], $cur[1]],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for an tag that has a wikidata link and a Telugu translation.
|
||||
*
|
||||
* @return array<string, array{0: int, 1: string}>
|
||||
*/
|
||||
public static function tagWithTlAndWikidataLinkProvider():array {
|
||||
|
||||
$mysqli = md_main_mysqli_connect();
|
||||
|
||||
$result = $mysqli->do_read_query("SELECT `tag_id`, `noda_nrinsource`
|
||||
FROM `" . DATABASENAME_NODA . "`.`noda_tag`
|
||||
WHERE `noda_source` = 'Wikidata'
|
||||
AND EXISTS (SELECT 1 FROM `" . DATABASENAME_NODA . "`.`tag_translation`
|
||||
WHERE `tag_translation`.`tag_id` = `noda_tag`.`tag_id`
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "')");
|
||||
|
||||
if (!$cur = $result->fetch_row()) {
|
||||
throw new Exception("Failed to identify an entry that has a wikidata entry and a translation for language " . self::TEST_LANG);
|
||||
}
|
||||
$result->close();
|
||||
$mysqli->close();
|
||||
|
||||
return [
|
||||
'Tag with wikidata and translation' => [$cur[0], $cur[1]],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for fetching and recording translations for an actor.
|
||||
*
|
||||
* @param integer $actor_id Actor ID.
|
||||
* @param string $wikidata_id Wikidata ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCleanWikidataInputWithoutHtml():void {
|
||||
#[DataProvider('actorWithTlAndWikidataLinkProvider')]
|
||||
public function testFetchingTranslationForPersinst(int $actor_id, string $wikidata_id):void {
|
||||
|
||||
$output = NodaWikidataFetcher::cleanWikidataInput('Werbowez (ukrainisch Вербовець; russisch Вербовец, polnisch Wierzbowiec; rumänisch Verboveț) ist ein Dorf in der ukrainischen Oblast Iwano-Frankiwsk mit etwa 3400 Einwohnern (2001).[1]');
|
||||
$expected = 'Werbowez (ukrainisch Вербовець; russisch Вербовец, polnisch Wierzbowiec; rumänisch Verboveț) ist ein Dorf in der ukrainischen Oblast Iwano-Frankiwsk mit etwa 3400 Einwohnern (2001).';
|
||||
self::assertTrue(
|
||||
str_starts_with($output, $expected),
|
||||
"Start of parsed Wikipedia text should be:" . PHP_EOL . PHP_EOL . $expected . PHP_EOL . PHP_EOL . 'Real start text is: ' . PHP_EOL . PHP_EOL . substr($output, 0, 250)
|
||||
);
|
||||
$mysqli = md_main_mysqli_connect();
|
||||
|
||||
$mysqli->do_update_query("DELETE FROM `" . DATABASENAME_NODA . "`.`persinst_translation`
|
||||
WHERE `persinst_id` = " . $actor_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'");
|
||||
|
||||
self::assertEquals(0, MDMysqliTesting::queryNumRows($mysqli, "
|
||||
FROM `" . DATABASENAME_NODA . "`.`persinst_translation`
|
||||
WHERE `persinst_id` = " . $actor_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'"));
|
||||
|
||||
$data = NodaWikidataFetcher::getWikidataEntity($wikidata_id);
|
||||
$fetcher = new NodaWikidataFetcher($mysqli);
|
||||
$fetcher->getWikidataTranslationsForPersinst($data, $actor_id, [self::TEST_LANG]);
|
||||
|
||||
self::assertEquals(1, MDMysqliTesting::queryNumRows($mysqli, "
|
||||
FROM `" . DATABASENAME_NODA . "`.`persinst_translation`
|
||||
WHERE `persinst_id` = " . $actor_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'"));
|
||||
|
||||
$mysqli->close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for fetching and recording translations for an place.
|
||||
*
|
||||
* @param integer $place_id Place ID.
|
||||
* @param string $wikidata_id Wikidata ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('placeWithTlAndWikidataLinkProvider')]
|
||||
public function testFetchingTranslationForPlace(int $place_id, string $wikidata_id):void {
|
||||
|
||||
$mysqli = md_main_mysqli_connect();
|
||||
|
||||
$mysqli->do_update_query("DELETE FROM `" . DATABASENAME_NODA . "`.`ort_translation`
|
||||
WHERE `ort_id` = " . $place_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'");
|
||||
|
||||
self::assertEquals(0, MDMysqliTesting::queryNumRows($mysqli, "
|
||||
FROM `" . DATABASENAME_NODA . "`.`ort_translation`
|
||||
WHERE `ort_id` = " . $place_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'"));
|
||||
|
||||
$data = NodaWikidataFetcher::getWikidataEntity($wikidata_id);
|
||||
$fetcher = new NodaWikidataFetcher($mysqli);
|
||||
$fetcher->getWikidataTranslationsForPlace($data, $place_id, [self::TEST_LANG]);
|
||||
|
||||
self::assertEquals(1, MDMysqliTesting::queryNumRows($mysqli, "
|
||||
FROM `" . DATABASENAME_NODA . "`.`ort_translation`
|
||||
WHERE `ort_id` = " . $place_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'"));
|
||||
|
||||
$mysqli->close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for fetching and recording translations for an tag.
|
||||
*
|
||||
* @param integer $tag_id Tag ID.
|
||||
* @param string $wikidata_id Wikidata ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('tagWithTlAndWikidataLinkProvider')]
|
||||
public function testFetchingTranslationForTag(int $tag_id, string $wikidata_id):void {
|
||||
|
||||
$mysqli = md_main_mysqli_connect();
|
||||
|
||||
$mysqli->do_update_query("DELETE FROM `" . DATABASENAME_NODA . "`.`tag_translation`
|
||||
WHERE `tag_id` = " . $tag_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'");
|
||||
|
||||
self::assertEquals(0, MDMysqliTesting::queryNumRows($mysqli, "
|
||||
FROM `" . DATABASENAME_NODA . "`.`tag_translation`
|
||||
WHERE `tag_id` = " . $tag_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'"));
|
||||
|
||||
$data = NodaWikidataFetcher::getWikidataEntity($wikidata_id);
|
||||
$fetcher = new NodaWikidataFetcher($mysqli);
|
||||
$fetcher->getWikidataTranslationsForTag($data, $tag_id, [self::TEST_LANG]);
|
||||
|
||||
self::assertEquals(1, MDMysqliTesting::queryNumRows($mysqli, "
|
||||
FROM `" . DATABASENAME_NODA . "`.`tag_translation`
|
||||
WHERE `tag_id` = " . $tag_id . "
|
||||
AND `trans_language` = '" . $mysqli->escape_string(self::TEST_LANG) . "'"));
|
||||
|
||||
$mysqli->close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that fetching translation from Wikidata returns the title of the wikipedia page,
|
||||
* not the wikidata title.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testListTranslationsFromWikidataWikipediaReturnsWikipediaTitle():void {
|
||||
|
||||
$data = NodaWikidataFetcher::getWikidataEntity("Q33550");
|
||||
|
||||
$output = NodaWikidataFetcher::listTranslationsFromWikidataWikipedia(["de"], $data);
|
||||
self::assertNotEmpty($output['de']);
|
||||
|
||||
self::assertEquals("Friedrich II. (Preußen)", $output['de']['label']);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,21 @@ declare(strict_types = 1);
|
||||
|
||||
// Try using class map as defined through /scripts/buildClassMap.php
|
||||
|
||||
foreach (array_merge([__DIR__ . '/../tests', __DIR__ . '/../src', __DIR__ . '/../src/enums', __DIR__ . '/../../MD_STD/src', __DIR__ . '/../../MDErrorReporter', __DIR__ . '/../../MDErrorReporter/exceptions', __DIR__ . '/../../MDErrorReporter/exceptions/generic', __DIR__ . '/../../MDErrorReporter/exceptions/updates']) as $classDir) {
|
||||
foreach (array_merge([__DIR__ . '/../tests',
|
||||
__DIR__ . '/../src',
|
||||
__DIR__ . '/../src/enums',
|
||||
__DIR__ . '/../../MD_STD/src',
|
||||
__DIR__ . '/../../MDErrorReporter',
|
||||
__DIR__ . '/../../MDErrorReporter/exceptions',
|
||||
__DIR__ . '/../../MDErrorReporter/exceptions/generic',
|
||||
__DIR__ . '/../../MDErrorReporter/exceptions/updates',
|
||||
__DIR__ . '/../../MDMysqli/src',
|
||||
__DIR__ . '/../../MDAllowedValueSets/src',
|
||||
__DIR__ . '/../../MDAllowedValueSets/src/classes',
|
||||
__DIR__ . '/../../MDAllowedValueSets/src/enums',
|
||||
__DIR__ . '/../../MDAllowedValueSets/exceptions',
|
||||
__DIR__ . '/../../MDMysqli/exceptions',
|
||||
]) as $classDir) {
|
||||
|
||||
if (\file_exists("$classDir/$className.php")) {
|
||||
include "$classDir/$className.php";
|
||||
@ -20,6 +34,5 @@ declare(strict_types = 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user