Passed
Branch feature/2.1-geodispersion-dev (1d61a8)
by Jonathan
61:21
created

SourceStatusService::sourceStatusForFact()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 19
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 29
rs 8.8333
1
<?php
2
3
/**
4
 * webtrees-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage IsSourced
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2009-2021, Jonathan Jaubart
10
 * @license https://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
11
 */
12
13
declare(strict_types=1);
14
15
namespace MyArtJaub\Webtrees\Module\IsSourced\Services;
16
17
use Fisharebest\Webtrees\Date;
18
use Fisharebest\Webtrees\Fact;
19
use Fisharebest\Webtrees\Family;
20
use Fisharebest\Webtrees\Gedcom;
21
use Fisharebest\Webtrees\GedcomRecord;
22
use Fisharebest\Webtrees\Individual;
23
use MyArtJaub\Webtrees\Module\IsSourced\Data\FactSourceStatus;
24
use MyArtJaub\Webtrees\Module\IsSourced\Data\NullFactSourceStatus;
25
use MyArtJaub\Webtrees\Module\IsSourced\Data\SourceStatus;
26
27
/**
28
 * Service for computing the status of sources for records and facts.
29
 */
30
class SourceStatusService
31
{
32
33
    /**
34
     * Maximum timespan between the date of a source and the date of the event to consider the source precise.
35
     * Arbitrally set to approximately a year around the event date.
36
     *
37
     * @var int DATE_PRECISION_MARGIN
38
     */
39
    private const DATE_PRECISION_MARGIN = 180;
40
41
    /**
42
     * Return the status of source citations for a fact.
43
     *
44
     * @param Fact $fact
45
     * @return FactSourceStatus
46
     */
47
    public function sourceStatusForFact(Fact $fact): FactSourceStatus
48
    {
49
        $source_status = new FactSourceStatus();
50
51
        $date = $fact->date();
52
        $source_status
53
            ->setFactHasDate($date->isOK())
54
            ->setFactHasPreciseDate($date->qual1 === '' && $date->minimumJulianDay() === $date->maximumJulianDay());
55
56
        foreach ($fact->getCitations() as $citation) {
57
            $source_status
58
                ->setHasSource(true)
59
                ->addHasSupportingDocument(preg_match('/\n3 _ACT (?:.*)/', $citation) === 1);
60
61
            preg_match_all("/\n3 DATA(?:\n[4-9] .*)*\n4 DATE (.*)/", $citation, $date_matches, PREG_SET_ORDER);
62
            foreach ($date_matches as $date_match) {
63
                $source_date = new Date($date_match[1]);
64
                $source_status
65
                    ->addSourceHasDate($source_date->isOK())
66
                    ->addSourceMatchesFactDate($date->isOK() && $source_date->isOK()
67
                        && abs($source_date->julianDay() - $date->julianDay()) < self::DATE_PRECISION_MARGIN);
68
            }
69
70
            if ($source_status->isFullySourced()) {
71
                return $source_status;
72
            }
73
        }
74
75
        return $source_status;
76
    }
77
78
    /**
79
     * Return the status of sources for a Gedcom record.
80
     *
81
     * @param GedcomRecord $record
82
     * @return SourceStatus
83
     */
84
    public function sourceStatusForRecord(GedcomRecord $record): SourceStatus
85
    {
86
        $source_status = new SourceStatus();
87
88
        foreach ($record->facts(['SOUR']) as $source) {
89
            $source_status
90
                ->setHasSource(true)
91
                ->addHasSupportingDocument($source->attribute('_ACT') !== '');
92
93
            if ($source_status->isFullySourced()) {
94
                return $source_status;
95
            }
96
        }
97
98
        return $source_status;
99
    }
100
101
    /**
102
     * Return the status of source citations for a list of fact types associated with a record.
103
     *
104
     * @param GedcomRecord $record
105
     * @param array $tags
106
     * @return FactSourceStatus
107
     */
108
    public function sourceStatusForFactsWithTags(GedcomRecord $record, array $tags): FactSourceStatus
109
    {
110
        $source_status = new NullFactSourceStatus();
111
112
        foreach ($record->facts($tags) as $fact) {
113
            $source_status = $source_status->combineWith($this->sourceStatusForFact($fact));
114
            assert($source_status instanceof FactSourceStatus);
115
            if ($source_status->isFullySourced()) {
116
                return $source_status;
117
            }
118
        }
119
120
        return $source_status;
121
    }
122
123
    /**
124
     * Return the status of source citations for an individual's birth events.
125
     *
126
     * @param Individual $individual
127
     * @return FactSourceStatus
128
     */
129
    public function sourceStatusForBirth(Individual $individual): FactSourceStatus
130
    {
131
        return $this->sourceStatusForFactsWithTags($individual, Gedcom::BIRTH_EVENTS);
132
    }
133
134
    /**
135
     * Return the status of source citations for an individual's death events.
136
     *
137
     * @param Individual $individual
138
     * @return FactSourceStatus
139
     */
140
    public function sourceStatusForDeath(Individual $individual): FactSourceStatus
141
    {
142
        return $this->sourceStatusForFactsWithTags($individual, Gedcom::DEATH_EVENTS);
143
    }
144
145
    /**
146
     * Return the status of source citations for a family's marriage events.
147
     *
148
     * @param Family $family
149
     * @return FactSourceStatus
150
     */
151
    public function sourceStatusForMarriage(Family $family): FactSourceStatus
152
    {
153
        $marr_events = array_merge(Gedcom::MARRIAGE_EVENTS, ['MARC', 'MARL', 'MARS']);
154
        return $this->sourceStatusForFactsWithTags($family, $marr_events);
155
    }
156
}
157