213 lines
8.8 KiB
PHP
213 lines
8.8 KiB
PHP
<?PHP
|
|
/**
|
|
* Contains class NodaValidationHelper.
|
|
*
|
|
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
|
*/
|
|
declare(strict_types = 1);
|
|
|
|
/**
|
|
* A class of static functions for validating single fields of noda entities.
|
|
*/
|
|
final class NodaValidationHelper {
|
|
|
|
private 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
|
|
* guess based on the length and character composition of the description can be
|
|
* made.
|
|
*
|
|
* @param string $description Input descrition.
|
|
* @param string[] $names 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 validateActorDescription(string $description, array $names = []):void {
|
|
|
|
// For nodac, empty actor 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 author name is provided");
|
|
}
|
|
|
|
// Throw error on descriptions that are too short
|
|
if (\mb_strlen($description) < 10) {
|
|
throw new MDgenericInvalidInputsException("Author description is too short");
|
|
}
|
|
|
|
// Validate actor description based on character composition.
|
|
|
|
$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.");
|
|
}
|
|
|
|
if (!empty($names)) {
|
|
|
|
$clearedChars = [' ' => ' ', ',' => ' ', ';' => ' ', '.' => ' '];
|
|
|
|
$namesMerged = implode(' ', $names);
|
|
$namesMerged = strtr($namesMerged, $clearedChars);
|
|
$uniqueNames = array_unique(array_diff(explode(' ', $namesMerged), ['']));
|
|
sort($uniqueNames);
|
|
|
|
$descCleared = strtr($description, $clearedChars);
|
|
$descWords = array_unique(array_diff(explode(' ', $descCleared), ['']));
|
|
sort($descWords);
|
|
|
|
if ($uniqueNames === $descWords) {
|
|
throw new MDgenericInvalidInputsException("The actor name was simply repeated in the description. This is not enough.");
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Checks if an actor name is valid.
|
|
* Returns 0 if the actor can be added as a new one / actor name can be used as a new one.
|
|
* Returns the ID for already known actors.
|
|
* Throws an exception if the actor is blacklisted.
|
|
*
|
|
* @param MDMysqli $mysqli_noda DB connection to vocabulary.
|
|
* @param string $lang User language.
|
|
* @param string $persinst_name Actor name.
|
|
* @param string $persinst_name_en Actor name (short).
|
|
* @param string $persinst_geburtsjahr Birth year.
|
|
* @param string $persinst_sterbejahr Death year.
|
|
* @param string $context_identifier Context / instance identifier.
|
|
* @param integer $institution_id Institution ID.
|
|
*
|
|
* @return integer
|
|
*/
|
|
public static function checkPersinstNameIsUsable(MDMysqli $mysqli_noda, string $lang, string $persinst_name, string $persinst_name_en, string $persinst_geburtsjahr, string $persinst_sterbejahr, string $context_identifier, int $institution_id):int {
|
|
|
|
if ($storedType = NodaDistinctlyTypedStrings::lookup($mysqli_noda, $lang, $persinst_name_en)) {
|
|
|
|
if ($storedType !== 'persinst') {
|
|
throw new MDpageParameterMissingException("This term is marked to be distinctly a " . $storedType);
|
|
}
|
|
|
|
}
|
|
|
|
// Special case: ? or "unbekannt" as a given name.
|
|
if (str_starts_with($persinst_name_en, '? ') || str_starts_with(strtolower($persinst_name_en), 'unbekannt ') ) {
|
|
throw new MDBlacklistedInputException("Term is blacklisted");
|
|
}
|
|
|
|
// Check if the place name is in the current language's blacklist.
|
|
if (NodaBlacklistedTerms::checkPersinstBlacklistedInDb($mysqli_noda, $lang, $persinst_name) === true) {
|
|
throw new MDBlacklistedInputException("Term is blacklisted");
|
|
}
|
|
if (NodaBlacklistedTerms::checkPersinstBlacklistedInDb($mysqli_noda, $lang, $persinst_name_en) === true) {
|
|
throw new MDBlacklistedInputException("Term is blacklisted");
|
|
}
|
|
|
|
if ($existingPersinstId = NodaIDGetter::getPersinstIDByNamesAndRewrites($mysqli_noda, $lang, $persinst_name_en, $persinst_geburtsjahr, $persinst_sterbejahr, $context_identifier, $institution_id)) {
|
|
return $existingPersinstId;
|
|
}
|
|
|
|
if ($existingPersinstId = NodaIDGetter::getPersinstIDByNamesAndRewrites($mysqli_noda, $lang, $persinst_name, $persinst_geburtsjahr, $persinst_sterbejahr, $context_identifier, $institution_id)) {
|
|
return $existingPersinstId;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
|
* Checks if an place name is valid.
|
|
* Returns 0 if the place can be added as a new one / place name can be used as a new one.
|
|
* Returns the ID for already known places.
|
|
* Throws an exception if the place is blacklisted.
|
|
*
|
|
* @param MDMysqli $mysqli_noda DB connection to vocabulary.
|
|
* @param string $lang User language.
|
|
* @param string $place_name Place name.
|
|
* @param string $context_identifier Context / instance identifier.
|
|
* @param integer $institution_id Institution ID.
|
|
*
|
|
* @return integer
|
|
*/
|
|
public static function checkPlaceNameIsUsable(MDMysqli $mysqli_noda, string $lang, string $place_name, string $context_identifier, int $institution_id):int {
|
|
|
|
if ($storedType = NodaDistinctlyTypedStrings::lookup($mysqli_noda, $lang, $place_name)) {
|
|
|
|
if ($storedType !== 'orte') {
|
|
throw new MDpageParameterMissingException("This term is marked to be distinctly a " . $storedType);
|
|
}
|
|
|
|
}
|
|
|
|
// Check if the place name is in the current language's blacklist.
|
|
if (NodaBlacklistedTerms::checkPlaceBlacklistedInDb($mysqli_noda, $lang, $place_name) === true) {
|
|
throw new MDBlacklistedInputException("Term is blacklisted");
|
|
}
|
|
|
|
if ($existingPlaceId = NodaIDGetter::getPlaceIDByNamesAndRewrites($mysqli_noda, $lang, $place_name, $context_identifier, $institution_id)) {
|
|
return $existingPlaceId;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
}
|