Refactor Plausi from musdb to move the logic into this subrepository

See #948
This commit is contained in:
Joshua Ramon Enslin 2023-07-18 22:05:00 +02:00
parent f35115e38c
commit 863c3a3c93
Signed by: jrenslin
GPG Key ID: 46016F84501B70AE
6 changed files with 933 additions and 1 deletions

View File

@ -1,3 +1,22 @@
# Quality Assessment Tools at museum-digital
The classes of this library provide tools to access the quality of museum object records and provide tips for improving it.
The classes of this library provide tools to access the quality of museum object
records and provide tips for improving it.
## Tools
- PuQI
PuQI (class `MDPuqi`) generates a score determining the quality of object metadata
based on e.g. counting linked entries.
## Plausi
Plausi analyzes an object's linked events (e.g. production, use) and identifies
logical inconsistencies.
## Publications
### PuQI
Rohde-Enslin, S. (2015). PuQI A Smart Way to Create Better Data. Uncommon Culture, 6(2), 122-129. <https://uncommonculture.org/ojs/index.php/UC/article/view/6218>

View File

@ -0,0 +1,75 @@
<?PHP
/**
* Represents a higher level category of event types.
*
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/
declare(strict_types = 1);
/**
* Represents a higher level category of event types.
*/
enum MDEventCategory implements JsonSerializable {
case production;
case post_production;
case pre_production;
case no_production;
/**
* Returns an MDEventCategory based on a given event type.
*
* @param integer $event_type Event type.
*
* @return MDEventCategory
*/
public static function fromEventType(int $event_type):MDEventCategory {
if (in_array($event_type, MDEventsSet::EVENTS_PRODUCTION, true)) {
return self::production;
}
if (in_array($event_type, MDEventsSet::EVENTS_POST_PRODUCTION, true)) {
return self::post_production;
}
if (in_array($event_type, MDEventsSet::EVENTS_PRE_PRODUCTION, true)) {
return self::pre_production;
}
if (in_array($event_type, MDEventsSet::EVENTS_NO_PRODUCTION, true)) {
return self::no_production;
}
if ($event_type === 5) {
return self::no_production;
}
throw new Exception("Uncategorized event type: " . $event_type);
}
/**
* Lists all available names.
*
* @return array<string>
*/
public static function caseNames():array {
$output = [];
$cases = self::cases();
foreach ($cases as $case) {
$output[] = $case->name;
}
return $output;
}
/**
* Provides the option to serialize as a string during json_encode().
*
* @return string
*/
public function jsonSerialize():string {
return $this->name;
}
}

View File

@ -0,0 +1,616 @@
<?PHP
/**
* Plausability checker for object events.
*
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/
declare(strict_types = 1);
/**
* Plausability checker for object events.
*/
final class MDPlausi {
const UNKNOWN_TIME_MAX = MDRequirementsSet::TIME_LATEST_YEAR;
const UNKNOWN_TIME_MIN = MDRequirementsSet::TIME_EARLIEST_YEAR;
private readonly int $default_time_max;
private readonly int $default_time_min;
private MDTlLoader $_tlLoader;
/** @var array<MDPlausiEvent> */
private array $_events;
/** @var array<string> */
private array $_messageList = [];
private bool $_hasCertainWarnings = false; // True === 'alarm'
private bool $_is_print_material;
private bool $_is_painted_drawn;
private MDPlausiEventCategory $_production;
private MDPlausiEventCategory $_pre_production;
private MDPlausiEventCategory $_post_production;
private MDPlausiEventCategory $_printing_plate;
private MDPlausiEventCategory $_template_creation;
/**
* Checks whether events themselves are logical regarding the birth and
* death dates vis-a-vis the stated time.
*
* @return void
*/
private function _checkPlausibilityOnBirthDeath():void {
if (empty($this->_events)) return;
// Get values for time_entries and actor_life dates from nodac
foreach ($this->_events as $event) {
// Evaluating actor birth
if ($event->actor_birth_normalized !== false) {
// Work on the object started before the actor was born
if ($event->time_start_normalized !== false && $event->time_start_normalized < $event->actor_birth_normalized) {
$this->_messageList[] = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$event->event_type) . '</b> (' . $event->time_name . ') ' . $this->_tlLoader->tl("quality", "quality", "before_birth_possibly") . ' ' . $event->actor_name;
}
// The actor was involved with the object totally before they were born
// Ended being involved before birth
else if ($event->time_end_normalized !== false && $event->time_end_normalized < $event->actor_birth_normalized) {
$this->_messageList[] = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$event->event_type) . '</b> (' . $event->time_name . ') ' . $this->_tlLoader->tl("quality", "quality", "before_birth") . ' ' . $event->actor_name;
$this->_hasCertainWarnings = true;
}
}
// Evaluate actor death
if ($event->actor_death_normalized !== false) {
// Check if the actor died before they started being involved with the object
if ($event->time_start_normalized !== false && $event->actor_death_normalized < $event->time_start_normalized) {
$this->_messageList[] = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$event->event_type) . '</b> (' . $event->time_name . ') ' . $this->_tlLoader->tl("quality", "quality", "after_death") . ' ' . $event->actor_name;
$this->_hasCertainWarnings = true;
}
else if ($event->time_end_normalized !== false && $event->actor_death_normalized < $event->time_end_normalized) {
$this->_messageList[] = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$event->event_type) . '</b> (' . $event->time_name . ') ' . $this->_tlLoader->tl("quality", "quality", "after_death_possibly") . ' ' . $event->actor_name;
}
}
}
}
/**
* Evaluates the relation between template creation, printing plate or drawing dates.
*
* @return void
*/
public function _evaluateTemplateStatus():void {
// Printing plate was produced before template was even started
if ($this->_printing_plate->latest_event_type !== 0
&& $this->_template_creation->earliest_event_type !== 0
&& $this->_printing_plate->latest < $this->_template_creation->earliest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", "12") . '</b>';
$message .= $this->_printing_plate->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", "4") . '</b>';
$message .= $this->_template_creation->formulateMessagePartForEarliest($this->_tlLoader);
$this->_messageList[] = $message;
$this->_hasCertainWarnings = true;
}
// Printing plate was produced before template was finished
else if ($this->_printing_plate->latest_event_type !== 0
&& $this->_template_creation->latest_event_type !== 0
&& $this->_printing_plate->latest < $this->_template_creation->latest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", "12") . '</b>';
$message .= $this->_printing_plate->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before_possibly") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", "4") . '</b>';
$message .= $this->_template_creation->formulateMessagePartForLatest($this->_tlLoader);
$this->_messageList[] = $message;
}
}
/**
* Adds a warning message if an object was both drawn and printed
* (prints of drawn materials make the drawing a template).
*
* @return void
*/
private function _evaluateDrawingsWhichArePrinted():void {
// Paintings should not be printed at the same time
if ($this->_is_painted_drawn === true and $this->_is_print_material === true) {
$message = '<b>' . $this->_tlLoader->tl("quality", "quality", "print_not_paint") . '</b> ' . $this->_tlLoader->tl("quality", "quality", "better_use") . ' "' . $this->_tlLoader->tl("eventtype_name", "eventname", "4") . '" . ';
$this->_hasCertainWarnings = true;
}
}
/**
* Evaluates if an object's preproduction (e.g. template) took place after the object was
* already produced.
*
* @return void
*/
private function _evaluatePreproductionAfterProduction():void {
// Printing plate was produced before template was finished
if ($this->_production->latest_event_type !== 0
&& $this->_pre_production->earliest_event_type !== 0
&& $this->_production->latest < $this->_pre_production->earliest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_production->latest_event_type) . '</b>';
$message .= $this->_production->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_pre_production->earliest_event_type) . '</b>';
$message .= $this->_pre_production->formulateMessagePartForEarliest($this->_tlLoader);
$this->_messageList[] = $message;
$this->_hasCertainWarnings = true;
}
// Printing plate was produced before template was finished
else if ($this->_production->latest_event_type !== 0
&& $this->_pre_production->latest_event_type !== 0
&& $this->_production->latest < $this->_pre_production->latest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_production->latest_event_type) . '</b>';
$message .= $this->_production->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before_possibly") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_pre_production->latest_event_type) . '</b>';
$message .= $this->_pre_production->formulateMessagePartForLatest($this->_tlLoader);
$this->_messageList[] = $message;
}
}
/**
* Evaluates if an object's preproduction (e.g. template) took place after the object was
* already being used (or otherwise interacted with past it's completion).
*
* @return void
*/
private function _evaluatePreproductionAfterPostproduction():void {
// Printing plate was postproduced before template was finished
if ($this->_post_production->latest_event_type !== 0
&& $this->_pre_production->earliest_event_type !== 0
&& $this->_post_production->latest < $this->_pre_production->earliest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_post_production->latest_event_type) . '</b>';
$message .= $this->_post_production->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_pre_production->earliest_event_type) . '</b>';
$message .= $this->_pre_production->formulateMessagePartForEarliest($this->_tlLoader);
$this->_messageList[] = $message;
$this->_hasCertainWarnings = true;
}
// E.g. template creation after being all use was finished
else if ($this->_post_production->latest_event_type !== 0
&& $this->_pre_production->latest_event_type !== 0
&& $this->_post_production->latest < $this->_pre_production->latest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_post_production->latest_event_type) . '</b>';
$message .= $this->_post_production->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_pre_production->latest_event_type) . '</b>';
$message .= $this->_pre_production->formulateMessagePartForLatest($this->_tlLoader);
$this->_messageList[] = $message;
$this->_hasCertainWarnings = true;
}
// E.g. template creation was only started after the object was beyond use
// This may happen, if the template is for renovations or so. Hence, there is
// only a warning here.
else if ($this->_post_production->earliest_event_type !== 0
&& $this->_pre_production->earliest_event_type !== 0
&& $this->_post_production->earliest < $this->_pre_production->earliest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_post_production->earliest_event_type) . '</b>';
$message .= $this->_post_production->formulateMessagePartForEarliest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before_possibly") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_pre_production->earliest_event_type) . '</b>';
$message .= $this->_pre_production->formulateMessagePartForEarliest($this->_tlLoader);
$this->_messageList[] = $message;
}
}
/**
* Evaluates if an object's production (e.g. template) took place after the object was
* already being used (or otherwise interacted with past it's completion).
*
* @return void
*/
private function _evaluateProductionAfterPostproduction():void {
if ($this->_post_production->earliest_event_type !== 0
&& $this->_production->earliest_event_type !== 0
&& $this->_post_production->earliest < $this->_production->earliest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_post_production->earliest_event_type) . '</b>';
$message .= $this->_post_production->formulateMessagePartForEarliest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_production->earliest_event_type) . '</b>';
$message .= $this->_production->formulateMessagePartForEarliest($this->_tlLoader);
$this->_messageList[] = $message;
$this->_hasCertainWarnings = true;
}
else if ($this->_post_production->earliest_event_type !== 0
&& $this->_production->latest_event_type !== 0
&& $this->_post_production->earliest < $this->_production->latest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_post_production->earliest_event_type) . '</b>';
$message .= $this->_post_production->formulateMessagePartForEarliest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before_possibly") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_production->latest_event_type) . '</b>';
$message .= $this->_production->formulateMessagePartForLatest($this->_tlLoader);
$this->_messageList[] = $message;
}
else if ($this->_post_production->latest_event_type !== 0
&& $this->_production->latest_event_type !== 0
&& $this->_post_production->latest < $this->_production->latest) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_post_production->latest_event_type) . '</b>';
$message .= $this->_post_production->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before_possibly") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_production->latest_event_type) . '</b>';
$message .= $this->_production->formulateMessagePartForLatest($this->_tlLoader);
$this->_messageList[] = $message;
}
}
/**
* Warns if an actor was displayed on an object finished before they were born.
*
* @return void
*/
private function _checkActorDisplayedBeforeBirth():void {
foreach ($this->_events as $event) {
// Ignore events other than "was displayed"
if ($event->event_type !== 5) continue;
if ($event->actor_birth_normalized !== false
&& $this->_production->latest_event_type !== 0
&& $event->actor_birth_normalized > $this->_production->latest
) {
$message = '<b>' . $this->_tlLoader->tl("eventtype_name", "eventname", (string)$this->_production->latest_event_type) . '</b>';
$message .= $this->_production->formulateMessagePartForLatest($this->_tlLoader);
$message .= ' ' . $this->_tlLoader->tl("quality", "quality", "before") . ' <b>' . $this->_tlLoader->tl("eventtype_name", "eventname", "5") . '</b>';
$message .= ' (' . $this->_tlLoader->tl("basis", "basis", "actor_short") . ': ' . $event->actor_name . ' (* ' . $event->actor_birth . '))';
$this->_messageList[] = $message;
$this->_hasCertainWarnings = true;
}
}
}
/**
* Checks plausibility by event category.
*
* @return void
*/
private function _checkIllogicalEventsByCategory():void {
$this->_evaluateTemplateStatus();
$this->_evaluateDrawingsWhichArePrinted();
$this->_evaluatePreproductionAfterProduction();
$this->_evaluatePreproductionAfterPostproduction();
$this->_evaluateProductionAfterPostproduction();
}
/**
* Runs the available evaluations.
*
* @return void
*/
public function evaluate():void {
$this->_checkPlausibilityOnBirthDeath();
$this->_checkIllogicalEventsByCategory();
$this->_checkActorDisplayedBeforeBirth();
}
/**
* Setup function for setting event categories.
*
* @return void
*/
public function _categorizeEvents():void {
foreach ($this->_events as $event) {
if ($event->actor_death_normalized !== false) {
$actor_death = date("Y", $event->actor_death_normalized);
}
else $actor_death = self::UNKNOWN_TIME_MIN;
switch ($event->event_category) {
case MDEventCategory::production:
if ($event->time_start_normalized !== false && $this->_production->earliest > $event->time_start_normalized) {
$this->_production->earliest = $event->time_start_normalized;
$this->_production->earliest_name = $event->time_name;
$this->_production->earliest_time_name = $event->time_start;
$this->_production->earliest_source = 'time';
$this->_production->earliest_event_type = $event->event_type;
}
if ($event->time_end_normalized !== false && $this->_production->latest < $event->time_end_normalized) {
$this->_production->latest = $event->time_end_normalized;
$this->_production->latest_name = $event->time_name;
$this->_production->latest_time_name = $event->time_end;
$this->_production->latest_source = 'time';
$this->_production->latest_event_type = $event->event_type;
}
if ($event->actor_birth_normalized !== false && $this->_production->earliest > $event->actor_birth_normalized) {
$this->_production->earliest = $event->actor_birth_normalized;
$this->_production->earliest_name = $event->actor_name;
$this->_production->earliest_time_name = $event->actor_birth;
$this->_production->earliest_source = 'actor';
$this->_production->earliest_event_type = $event->event_type;
}
if ($event->actor_death_normalized !== false && $this->_production->latest < $event->actor_death_normalized) {
$this->_production->latest = $event->actor_death_normalized;
$this->_production->latest_name = $event->actor_name;
$this->_production->latest_time_name = $event->actor_death;
$this->_production->latest_source = 'actor';
$this->_production->latest_event_type = $event->event_type;
}
break;
case MDEventCategory::pre_production:
if ($event->time_start_normalized !== false && $this->_pre_production->earliest > $event->time_start_normalized) {
$this->_pre_production->earliest = $event->time_start_normalized;
$this->_pre_production->earliest_name = $event->time_name;
$this->_pre_production->earliest_time_name = $event->time_start;
$this->_pre_production->earliest_source = 'time';
$this->_pre_production->earliest_event_type = $event->event_type;
}
if ($event->time_end_normalized !== false && $this->_pre_production->latest < $event->time_end_normalized) {
$this->_pre_production->latest = $event->time_end_normalized;
$this->_pre_production->latest_name = $event->time_name;
$this->_pre_production->latest_time_name = $event->time_end;
$this->_pre_production->latest_source = 'time';
$this->_pre_production->latest_event_type = $event->event_type;
}
if ($event->actor_birth_normalized !== false && $this->_pre_production->earliest > $event->actor_birth_normalized) {
$this->_pre_production->earliest = $event->actor_birth_normalized;
$this->_pre_production->earliest_name = $event->actor_name;
$this->_pre_production->earliest_time_name = $event->actor_birth;
$this->_pre_production->earliest_source = 'actor';
$this->_pre_production->earliest_event_type = $event->event_type;
}
if ($event->actor_death_normalized !== false && $this->_pre_production->latest < $event->actor_death_normalized) {
$this->_pre_production->latest = $event->actor_death_normalized;
$this->_pre_production->latest_name = $event->actor_name;
$this->_pre_production->latest_time_name = $event->actor_death;
$this->_pre_production->latest_source = 'actor';
$this->_pre_production->latest_event_type = $event->event_type;
}
break;
case MDEventCategory::post_production:
if ($event->time_start_normalized !== false && $this->_post_production->earliest > $event->time_start_normalized) {
$this->_post_production->earliest = $event->time_start_normalized;
$this->_post_production->earliest_name = $event->time_name;
$this->_post_production->earliest_time_name = $event->time_start;
$this->_post_production->earliest_source = 'time';
$this->_post_production->earliest_event_type = $event->event_type;
}
if ($event->time_end_normalized !== false && $this->_post_production->latest < $event->time_end_normalized) {
$this->_post_production->latest = $event->time_end_normalized;
$this->_post_production->latest_name = $event->time_name;
$this->_post_production->latest_time_name = $event->time_end;
$this->_post_production->latest_source = 'time';
$this->_post_production->latest_event_type = $event->event_type;
}
if ($event->actor_birth_normalized !== false && $this->_post_production->earliest > $event->actor_birth_normalized) {
$this->_post_production->earliest = $event->actor_birth_normalized;
$this->_post_production->earliest_name = $event->actor_name;
$this->_post_production->earliest_time_name = $event->actor_birth;
$this->_post_production->earliest_source = 'actor';
$this->_post_production->earliest_event_type = $event->event_type;
}
if ($event->actor_death_normalized !== false && $this->_post_production->latest < $event->actor_death_normalized) {
$this->_post_production->latest = $event->actor_death_normalized;
$this->_post_production->latest_name = $event->actor_name;
$this->_post_production->latest_time_name = $event->actor_death;
$this->_post_production->latest_source = 'actor';
$this->_post_production->latest_event_type = $event->event_type;
}
break;
}
if ($event->event_type === 9 || $event->event_type === 19) {
$this->_is_painted_drawn = true;
}
if ($event->event_type === 4) {
if ($event->time_start_normalized !== false && $this->_template_creation->earliest > $event->time_start_normalized) {
$this->_template_creation->earliest = $event->time_start_normalized;
$this->_template_creation->earliest_name = $event->time_name;
$this->_template_creation->earliest_time_name = $event->time_start;
$this->_template_creation->earliest_source = 'time';
$this->_template_creation->earliest_event_type = $event->event_type;
}
if ($event->time_end_normalized !== false && $this->_template_creation->latest < $event->time_end_normalized) {
$this->_template_creation->latest = $event->time_end_normalized;
$this->_template_creation->latest_name = $event->time_name;
$this->_template_creation->latest_time_name = $event->time_end;
$this->_template_creation->latest_source = 'time';
$this->_template_creation->latest_event_type = $event->event_type;
}
if ($event->actor_birth_normalized !== false && $this->_template_creation->earliest > $event->actor_birth_normalized) {
$this->_template_creation->earliest = $event->actor_birth_normalized;
$this->_template_creation->earliest_name = $event->actor_name;
$this->_template_creation->earliest_time_name = $event->actor_birth;
$this->_template_creation->earliest_source = 'actor';
$this->_template_creation->earliest_event_type = $event->event_type;
}
if ($event->actor_death_normalized !== false && $this->_template_creation->latest < $event->actor_death_normalized) {
$this->_template_creation->latest = $event->actor_death_normalized;
$this->_template_creation->latest_name = $event->actor_name;
$this->_template_creation->latest_time_name = $event->actor_death;
$this->_template_creation->latest_source = 'actor';
$this->_template_creation->latest_event_type = $event->event_type;
}
}
else if ($event->event_type === 12) {
if ($event->time_start_normalized !== false && $this->_printing_plate->earliest > $event->time_start_normalized) {
$this->_printing_plate->earliest = $event->time_start_normalized;
$this->_printing_plate->earliest_name = $event->time_name;
$this->_printing_plate->earliest_time_name = $event->time_start;
$this->_printing_plate->earliest_source = 'time';
$this->_printing_plate->earliest_event_type = $event->event_type;
}
if ($event->time_end_normalized !== false && $this->_printing_plate->latest < $event->time_end_normalized) {
$this->_printing_plate->latest = $event->time_end_normalized;
$this->_printing_plate->latest_name = $event->time_name;
$this->_printing_plate->latest_time_name = $event->time_end;
$this->_printing_plate->latest_source = 'time';
$this->_printing_plate->latest_event_type = $event->event_type;
}
if ($event->actor_birth_normalized !== false && $this->_printing_plate->earliest > $event->actor_birth_normalized) {
$this->_printing_plate->earliest = $event->actor_birth_normalized;
$this->_printing_plate->earliest_name = $event->actor_name;
$this->_printing_plate->earliest_time_name = $event->actor_birth;
$this->_printing_plate->earliest_source = 'actor';
$this->_printing_plate->earliest_event_type = $event->event_type;
}
if ($event->actor_death_normalized !== false && $this->_printing_plate->latest < $event->actor_death_normalized) {
$this->_printing_plate->latest = $event->actor_death_normalized;
$this->_printing_plate->latest_name = $event->actor_name;
$this->_printing_plate->latest_time_name = $event->actor_death;
$this->_printing_plate->latest_source = 'actor';
$this->_printing_plate->latest_event_type = $event->event_type;
}
$this->_is_print_material = true;
}
}
if (!isset($this->_is_painted_drawn)) $this->_is_painted_drawn = true;
if (!isset($this->_is_print_material)) $this->_is_print_material = true;
}
/**
* Returns the message list.
*
* @return array<string>
*/
public function getMessages():array {
return $this->_messageList;
}
/**
* Returns the warning status.
*
* @return boolean
*/
public function getWarningStatus():bool {
return $this->_hasCertainWarnings;
}
/**
* Constructor.
*
* @param MDTlLoader $tlLoader Translation loader.
* @param array<MDPlausiEvent> $events Events.
*
* @return void
*/
public function __construct(MDTlLoader $tlLoader, array $events) {
$this->_tlLoader = $tlLoader;
$this->_events = $events;
$this->default_time_max = time();
$this->default_time_min = -99999999999999999;
$this->_production = new MDPlausiEventCategory($this->default_time_max, $this->default_time_min);
$this->_pre_production = new MDPlausiEventCategory($this->default_time_max, $this->default_time_min);
$this->_post_production = new MDPlausiEventCategory($this->default_time_max, $this->default_time_min);
$this->_printing_plate = new MDPlausiEventCategory($this->default_time_max, $this->default_time_min);
$this->_template_creation = new MDPlausiEventCategory($this->default_time_max, $this->default_time_min);
$this->_categorizeEvents();
}
}

View File

@ -0,0 +1,99 @@
<?PHP
/**
* An event as required for the plausibility checker for events.
*
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/
declare(strict_types = 1);
/**
* An event as required for the plausibility checker for events.
*/
final class MDPlausiEvent {
public readonly int $event_type;
public readonly MDEventCategory $event_category;
public readonly string $time_name;
public readonly string $time_start;
public readonly string $time_end;
public readonly int|false $time_start_normalized;
public readonly int|false $time_end_normalized;
public readonly string $actor_name;
public readonly string $actor_birth;
public readonly string $actor_death;
public readonly int|false $actor_birth_normalized;
public readonly int|false $actor_death_normalized;
/**
* Attempts to parse a time.
*
* @param string $time Time to parse.
*
* @return array{earliest: int|false, latest: int|false}
*/
private function _attemptParsingTime(string $time):array {
if (empty($time)) return ['earliest' => false, 'latest' => false];
// 2005
if (in_array(strlen($time), [4, 5], true) and is_numeric(substr($time, 1))) {
return [
'earliest' => strtotime($time . '-01-01'),
'latest' => strtotime($time . '-12-31'),
];
}
// 2005-2006
if (strlen($time) === 9) {
$parts = explode('-', $time);
if (count($parts) === 2) {
return [
'earliest' => strtotime($parts[0]. '-01-01'),
'latest' => strtotime($parts[1]. '-12-31'),
];
}
}
$strtotime = strtotime($time);
return [
'earliest' => $strtotime,
'latest' => $strtotime,
];
}
/**
* Constructor.
*
* @param integer $event_type Event type.
* @param string $time_name Time.
* @param string $time_start Start.
* @param string $time_end End.
* @param string $actor_name Name of the linked actor.
* @param string $actor_birth Birth of the linked actor.
* @param string $actor_death Time of death of the linked actor.
*
* @return void
*/
public function __construct(int $event_type, string $time_name, string $time_start, string $time_end, string $actor_name, string $actor_birth, string $actor_death) {
$this->event_type = $event_type;
$this->time_name = $time_name;
$this->time_start = $time_start;
$this->time_end = $time_end;
$this->actor_name = $actor_name;
$this->actor_birth = $actor_birth;
$this->actor_death = $actor_death;
$this->time_start_normalized = $this->_attemptParsingTime($time_start)['earliest'];
$this->time_end_normalized = $this->_attemptParsingTime($time_end)['latest'];
$this->actor_birth_normalized = $this->_attemptParsingTime($actor_birth)['earliest'];
$this->actor_death_normalized = $this->_attemptParsingTime($actor_death)['latest'];
$this->event_category = MDEventCategory::fromEventType($event_type);
}
}

View File

@ -0,0 +1,78 @@
<?PHP
/**
* Handles event category as used by MDPlausi.
*
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/
declare(strict_types = 1);
/**
* Handles event category as used by MDPlausi.
*/
final class MDPlausiEventCategory {
public int $earliest;
public int $latest;
public string $earliest_name = '';
public string $latest_name = '';
public string $earliest_time_name = '';
public string $latest_time_name = '';
/** @var 'actor'|'time' */
public string $earliest_source;
/** @var 'actor'|'time' */
public string $latest_source;
public int $earliest_event_type = 0;
public int $latest_event_type = 0;
/**
* Formulates a plausi message part base on the earliest use of the category.
*
* @param MDTlLoader $tlLoader Translation loader.
*
* @return string
*/
public function formulateMessagePartForEarliest(MDTlLoader $tlLoader):string {
if ($this->earliest_source === 'actor') {
return ' (' . $tlLoader->tl("basis", "basis", "actor_short") . ': ' . $this->earliest_name . ' (* ' . $this->earliest_time_name . '))';
}
else {
return ' (' . $this->earliest_name . ')';
}
}
/**
* Formulates a plausi message part base on the latest use of the category.
*
* @param MDTlLoader $tlLoader Translation loader.
*
* @return string
*/
public function formulateMessagePartForLatest(MDTlLoader $tlLoader):string {
if ($this->latest_source === 'actor') {
return ' (' . $tlLoader->tl("basis", "basis", "actor_short") . ': ' . $this->latest_name . ' (✝ ' . $this->latest_time_name . '))';
}
else {
return ' (' . $this->latest_name . ')';
}
}
/**
* Constructor.
*
* @param int $default_earliest Default earliest time.
* @param int $default_latest Default latest time.
*
* @return void
*/
public function __construct(int $default_earliest, int $default_latest) {
$this->earliest = $default_earliest;
$this->latest = $default_latest;
}
}

View File

@ -0,0 +1,45 @@
<?PHP
/**
* Represents the plausibility check status.
*
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/
declare(strict_types = 1);
/**
* Represents the plausibility check status.
*/
enum MDPlausiStatus implements JsonSerializable {
case alarm;
case okay;
/**
* Lists all available names.
*
* @return array<string>
*/
public static function caseNames():array {
$output = [];
$cases = self::cases();
foreach ($cases as $case) {
$output[] = $case->name;
}
return $output;
}
/**
* Provides the option to serialize as a string during json_encode().
*
* @return string
*/
public function jsonSerialize():string {
return $this->name;
}
}