Passed
Push — main ( c808ff...64cea5 )
by Jonathan
03:30
created
app/Common/GeoDispersion/Config/GenericPlaceMapperConfig.php 1 patch
Indentation   +93 added lines, -93 removed lines patch added patch discarded remove patch
@@ -25,106 +25,106 @@
 block discarded – undo
25 25
  */
26 26
 class GenericPlaceMapperConfig implements PlaceMapperConfigInterface
27 27
 {
28
-    /** @var array<string, mixed> $config */
29
-    private array $config = [];
28
+	/** @var array<string, mixed> $config */
29
+	private array $config = [];
30 30
 
31
-    /**
32
-     * Get the generic mapper's config
33
-     *
34
-     * @return array<string, mixed>
35
-     */
36
-    public function config(): array
37
-    {
38
-        return $this->config;
39
-    }
31
+	/**
32
+	 * Get the generic mapper's config
33
+	 *
34
+	 * @return array<string, mixed>
35
+	 */
36
+	public function config(): array
37
+	{
38
+		return $this->config;
39
+	}
40 40
 
41
-    /**
42
-     * Set the generic mapper's config
43
-     *
44
-     * @param array<string, mixed> $config
45
-     * @return $this
46
-     */
47
-    public function setConfig(array $config): self
48
-    {
49
-        $this->config = $config;
50
-        return $this;
51
-    }
41
+	/**
42
+	 * Set the generic mapper's config
43
+	 *
44
+	 * @param array<string, mixed> $config
45
+	 * @return $this
46
+	 */
47
+	public function setConfig(array $config): self
48
+	{
49
+		$this->config = $config;
50
+		return $this;
51
+	}
52 52
 
53
-    /**
54
-     * {@inheritDoc}
55
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::get()
56
-     */
57
-    public function get(string $key, $default = null)
58
-    {
59
-        return $this->config[$key] ?? $default;
60
-    }
53
+	/**
54
+	 * {@inheritDoc}
55
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::get()
56
+	 */
57
+	public function get(string $key, $default = null)
58
+	{
59
+		return $this->config[$key] ?? $default;
60
+	}
61 61
 
62
-    /**
63
-     * {@inheritDoc}
64
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::has()
65
-     */
66
-    public function has(string $key): bool
67
-    {
68
-        return key_exists($key, $this->config);
69
-    }
62
+	/**
63
+	 * {@inheritDoc}
64
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::has()
65
+	 */
66
+	public function has(string $key): bool
67
+	{
68
+		return key_exists($key, $this->config);
69
+	}
70 70
 
71
-    /**
72
-     * {@inheritDoc}
73
-     * @see \JsonSerializable::jsonSerialize()
74
-     */
75
-    #[\ReturnTypeWillChange]
76
-    public function jsonSerialize()
77
-    {
78
-        return [
79
-            'class'     =>  get_class($this),
80
-            'config'    =>  $this->jsonSerializeConfig()
81
-        ];
82
-    }
71
+	/**
72
+	 * {@inheritDoc}
73
+	 * @see \JsonSerializable::jsonSerialize()
74
+	 */
75
+	#[\ReturnTypeWillChange]
76
+	public function jsonSerialize()
77
+	{
78
+		return [
79
+			'class'     =>  get_class($this),
80
+			'config'    =>  $this->jsonSerializeConfig()
81
+		];
82
+	}
83 83
 
84
-    /**
85
-     * Returns a representation of the mapper config compatible with Json serialisation
86
-     *
87
-     * @return mixed
88
-     */
89
-    public function jsonSerializeConfig()
90
-    {
91
-        return $this->config;
92
-    }
84
+	/**
85
+	 * Returns a representation of the mapper config compatible with Json serialisation
86
+	 *
87
+	 * @return mixed
88
+	 */
89
+	public function jsonSerializeConfig()
90
+	{
91
+		return $this->config;
92
+	}
93 93
 
94
-    /**
95
-     * {@inheritDoc}
96
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::jsonDeserialize()
97
-     *
98
-     * @param mixed $config
99
-     * @return $this
100
-     */
101
-    public function jsonDeserialize($config): self
102
-    {
103
-        if (is_string($config)) {
104
-            return $this->jsonDeserialize((array) json_decode($config));
105
-        }
106
-        if (is_array($config)) {
107
-            return $this->setConfig($config);
108
-        }
109
-        return $this;
110
-    }
94
+	/**
95
+	 * {@inheritDoc}
96
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::jsonDeserialize()
97
+	 *
98
+	 * @param mixed $config
99
+	 * @return $this
100
+	 */
101
+	public function jsonDeserialize($config): self
102
+	{
103
+		if (is_string($config)) {
104
+			return $this->jsonDeserialize((array) json_decode($config));
105
+		}
106
+		if (is_array($config)) {
107
+			return $this->setConfig($config);
108
+		}
109
+		return $this;
110
+	}
111 111
 
112
-    /**
113
-     * {@inheritDoc}
114
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::configContent()
115
-     */
116
-    public function configContent(ModuleInterface $module, Tree $tree): string
117
-    {
118
-        return '';
119
-    }
112
+	/**
113
+	 * {@inheritDoc}
114
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::configContent()
115
+	 */
116
+	public function configContent(ModuleInterface $module, Tree $tree): string
117
+	{
118
+		return '';
119
+	}
120 120
 
121
-    /**
122
-     * {@inheritDoc}
123
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::withConfigUpdate()
124
-     * @return $this
125
-     */
126
-    public function withConfigUpdate(ServerRequestInterface $request): self
127
-    {
128
-        return $this;
129
-    }
121
+	/**
122
+	 * {@inheritDoc}
123
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::withConfigUpdate()
124
+	 * @return $this
125
+	 */
126
+	public function withConfigUpdate(ServerRequestInterface $request): self
127
+	{
128
+		return $this;
129
+	}
130 130
 }
Please login to merge, or discard this patch.
app/Common/GeoDispersion/Config/NullPlaceMapperConfig.php 1 patch
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -26,62 +26,62 @@
 block discarded – undo
26 26
  */
27 27
 class NullPlaceMapperConfig implements PlaceMapperConfigInterface
28 28
 {
29
-    /**
30
-     * {@inheritDoc}
31
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::get()
32
-     */
33
-    public function get(string $key, $default = null)
34
-    {
35
-        return $default;
36
-    }
29
+	/**
30
+	 * {@inheritDoc}
31
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::get()
32
+	 */
33
+	public function get(string $key, $default = null)
34
+	{
35
+		return $default;
36
+	}
37 37
 
38
-    /**
39
-     * {@inheritDoc}
40
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::has()
41
-     */
42
-    public function has(string $key): bool
43
-    {
44
-        return false;
45
-    }
38
+	/**
39
+	 * {@inheritDoc}
40
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::has()
41
+	 */
42
+	public function has(string $key): bool
43
+	{
44
+		return false;
45
+	}
46 46
 
47
-    /**
48
-     * {@inheritDoc}
49
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::jsonDeserialize()
50
-     *
51
-     * @param mixed $config
52
-     * @return $this
53
-     */
54
-    public function jsonDeserialize($config): self
55
-    {
56
-        return $this;
57
-    }
47
+	/**
48
+	 * {@inheritDoc}
49
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::jsonDeserialize()
50
+	 *
51
+	 * @param mixed $config
52
+	 * @return $this
53
+	 */
54
+	public function jsonDeserialize($config): self
55
+	{
56
+		return $this;
57
+	}
58 58
 
59
-    /**
60
-     * {@inheritDoc}
61
-     * @see JsonSerializable::jsonSerialize()
62
-     */
63
-    #[\ReturnTypeWillChange]
64
-    public function jsonSerialize()
65
-    {
66
-        return [];
67
-    }
59
+	/**
60
+	 * {@inheritDoc}
61
+	 * @see JsonSerializable::jsonSerialize()
62
+	 */
63
+	#[\ReturnTypeWillChange]
64
+	public function jsonSerialize()
65
+	{
66
+		return [];
67
+	}
68 68
 
69
-    /**
70
-     * {@inheritDoc}
71
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::configContent()
72
-     */
73
-    public function configContent(ModuleInterface $module, Tree $tree): string
74
-    {
75
-        return '';
76
-    }
69
+	/**
70
+	 * {@inheritDoc}
71
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::configContent()
72
+	 */
73
+	public function configContent(ModuleInterface $module, Tree $tree): string
74
+	{
75
+		return '';
76
+	}
77 77
 
78
-    /**
79
-     * {@inheritDoc}
80
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::withConfigUpdate()
81
-     * @return $this
82
-     */
83
-    public function withConfigUpdate(ServerRequestInterface $request): self
84
-    {
85
-        return $this;
86
-    }
78
+	/**
79
+	 * {@inheritDoc}
80
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface::withConfigUpdate()
81
+	 * @return $this
82
+	 */
83
+	public function withConfigUpdate(ServerRequestInterface $request): self
84
+	{
85
+		return $this;
86
+	}
87 87
 }
Please login to merge, or discard this patch.
app/Common/GeoDispersion/Config/MapColorsConfig.php 1 patch
Indentation   +82 added lines, -82 removed lines patch added patch discarded remove patch
@@ -23,93 +23,93 @@
 block discarded – undo
23 23
  */
24 24
 class MapColorsConfig implements JsonSerializable
25 25
 {
26
-    private Color $default;
27
-    private Color $stroke;
28
-    private Color $max_value;
29
-    private Color $hover;
26
+	private Color $default;
27
+	private Color $stroke;
28
+	private Color $max_value;
29
+	private Color $hover;
30 30
 
31
-    /**
32
-     * Constructor for MapColorsConfig
33
-     *
34
-     * @param Color $default
35
-     * @param Color $stroke
36
-     * @param Color $max_value
37
-     * @param Color $hover
38
-     */
39
-    public function __construct(
40
-        Color $default,
41
-        Color $stroke,
42
-        Color $max_value,
43
-        Color $hover
44
-    ) {
45
-        $this->default = $default;
46
-        $this->stroke = $stroke;
47
-        $this->max_value = $max_value;
48
-        $this->hover = $hover;
49
-    }
31
+	/**
32
+	 * Constructor for MapColorsConfig
33
+	 *
34
+	 * @param Color $default
35
+	 * @param Color $stroke
36
+	 * @param Color $max_value
37
+	 * @param Color $hover
38
+	 */
39
+	public function __construct(
40
+		Color $default,
41
+		Color $stroke,
42
+		Color $max_value,
43
+		Color $hover
44
+	) {
45
+		$this->default = $default;
46
+		$this->stroke = $stroke;
47
+		$this->max_value = $max_value;
48
+		$this->hover = $hover;
49
+	}
50 50
 
51
-    /**
52
-     * Get the default color for the features
53
-     *
54
-     * @return Color
55
-     */
56
-    public function defaultColor(): Color
57
-    {
58
-        return $this->default;
59
-    }
51
+	/**
52
+	 * Get the default color for the features
53
+	 *
54
+	 * @return Color
55
+	 */
56
+	public function defaultColor(): Color
57
+	{
58
+		return $this->default;
59
+	}
60 60
 
61
-    /**
62
-     * Get the color for the features' strokes
63
-     *
64
-     * @return Color
65
-     */
66
-    public function strokeColor(): Color
67
-    {
68
-        return $this->stroke;
69
-    }
61
+	/**
62
+	 * Get the color for the features' strokes
63
+	 *
64
+	 * @return Color
65
+	 */
66
+	public function strokeColor(): Color
67
+	{
68
+		return $this->stroke;
69
+	}
70 70
 
71
-    /**
72
-     * Get the color for the features with the lowest count
73
-     *
74
-     * @return Color
75
-     */
76
-    public function minValueColor(): Color
77
-    {
78
-        return new Rgb(255, 255, 255);
79
-    }
71
+	/**
72
+	 * Get the color for the features with the lowest count
73
+	 *
74
+	 * @return Color
75
+	 */
76
+	public function minValueColor(): Color
77
+	{
78
+		return new Rgb(255, 255, 255);
79
+	}
80 80
 
81
-    /**
82
-     * Get the color for the features with the highest count
83
-     *
84
-     * @return Color
85
-     */
86
-    public function maxValueColor(): Color
87
-    {
88
-        return $this->max_value;
89
-    }
81
+	/**
82
+	 * Get the color for the features with the highest count
83
+	 *
84
+	 * @return Color
85
+	 */
86
+	public function maxValueColor(): Color
87
+	{
88
+		return $this->max_value;
89
+	}
90 90
 
91
-    /**
92
-     * Get the color for feature hovering
93
-     *
94
-     * @return Color
95
-     */
96
-    public function hoverColor(): Color
97
-    {
98
-        return $this->hover;
99
-    }
91
+	/**
92
+	 * Get the color for feature hovering
93
+	 *
94
+	 * @return Color
95
+	 */
96
+	public function hoverColor(): Color
97
+	{
98
+		return $this->hover;
99
+	}
100 100
 
101
-    /**
102
-     * {@inheritDoc}
103
-     * @see JsonSerializable::jsonSerialize()
104
-     */
105
-    #[\ReturnTypeWillChange]
106
-    public function jsonSerialize()
107
-    {
108
-        return [
109
-            'default'   => (string) $this->defaultColor()->toHex(),
110
-            'stroke'    => (string) $this->strokeColor()->toHex(),
111
-            'maxvalue'  => (string) $this->maxValueColor()->toHex(),
112
-            'hover'     => (string) $this->hoverColor()->toHex(),
113
-        ];
114
-    }
101
+	/**
102
+	 * {@inheritDoc}
103
+	 * @see JsonSerializable::jsonSerialize()
104
+	 */
105
+	#[\ReturnTypeWillChange]
106
+	public function jsonSerialize()
107
+	{
108
+		return [
109
+			'default'   => (string) $this->defaultColor()->toHex(),
110
+			'stroke'    => (string) $this->strokeColor()->toHex(),
111
+			'maxvalue'  => (string) $this->maxValueColor()->toHex(),
112
+			'hover'     => (string) $this->hoverColor()->toHex(),
113
+		];
114
+	}
115 115
 }
Please login to merge, or discard this patch.
app/Module/IsSourced/Services/SourceStatusService.php 2 patches
Indentation   +143 added lines, -143 removed lines patch added patch discarded remove patch
@@ -30,147 +30,147 @@
 block discarded – undo
30 30
  */
31 31
 class SourceStatusService
32 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
-     * Extract gedcom for all source citations of a fact.
43
-     * Logic removed from \Fisharebest\Webtrees\Fact.
44
-     *
45
-     * @param Fact $fact
46
-     * @return string[]
47
-     */
48
-    private function extractCitations(Fact $fact)
49
-    {
50
-        $extract_regex = '/\n(2 SOUR @(' . Gedcom::REGEX_XREF . ')@(?:\n[3-9] .*)*)/';
51
-        preg_match_all($extract_regex, $fact->gedcom(), $matches, PREG_SET_ORDER);
52
-        $citations = [];
53
-        foreach ($matches as $match) {
54
-            $source = Registry::sourceFactory()->make($match[2], $fact->record()->tree());
55
-            if ($source !== null && $source->canShow()) {
56
-                $citations[] = $match[1];
57
-            }
58
-        }
59
-        return $citations;
60
-    }
61
-
62
-    /**
63
-     * Return the status of source citations for a fact.
64
-     *
65
-     * @param Fact $fact
66
-     * @return FactSourceStatus
67
-     */
68
-    public function sourceStatusForFact(Fact $fact): FactSourceStatus
69
-    {
70
-        $source_status = new FactSourceStatus();
71
-
72
-        $date = $fact->date();
73
-        $source_status
74
-            ->setFactHasDate($date->isOK())
75
-            ->setFactHasPreciseDate($date->qual1 === '' && $date->minimumJulianDay() === $date->maximumJulianDay());
76
-
77
-        foreach ($this->extractCitations($fact) as $citation) {
78
-            $source_status
79
-                ->setHasSource(true)
80
-                ->addHasSupportingDocument(preg_match('/\n3 _ACT (?:.*)/', $citation) === 1);
81
-
82
-            preg_match_all("/\n3 DATA(?:\n[4-9] .*)*\n4 DATE (.*)/", $citation, $date_matches, PREG_SET_ORDER);
83
-            foreach ($date_matches as $date_match) {
84
-                $source_date = new Date($date_match[1]);
85
-                $source_status
86
-                    ->addSourceHasDate($source_date->isOK())
87
-                    ->addSourceMatchesFactDate($date->isOK() && $source_date->isOK()
88
-                        && abs($source_date->julianDay() - $date->julianDay()) < self::DATE_PRECISION_MARGIN);
89
-            }
90
-
91
-            if ($source_status->isFullySourced()) {
92
-                return $source_status;
93
-            }
94
-        }
95
-
96
-        return $source_status;
97
-    }
98
-
99
-    /**
100
-     * Return the status of sources for a Gedcom record.
101
-     *
102
-     * @param GedcomRecord $record
103
-     * @return SourceStatus
104
-     */
105
-    public function sourceStatusForRecord(GedcomRecord $record): SourceStatus
106
-    {
107
-        $source_status = new SourceStatus();
108
-
109
-        foreach ($record->facts(['SOUR']) as $source) {
110
-            $source_status
111
-                ->setHasSource(true)
112
-                ->addHasSupportingDocument($source->attribute('_ACT') !== '');
113
-
114
-            if ($source_status->isFullySourced()) {
115
-                return $source_status;
116
-            }
117
-        }
118
-
119
-        return $source_status;
120
-    }
121
-
122
-    /**
123
-     * Return the status of source citations for a list of fact types associated with a record.
124
-     *
125
-     * @param GedcomRecord $record
126
-     * @param string[] $tags
127
-     * @return FactSourceStatus
128
-     */
129
-    public function sourceStatusForFactsWithTags(GedcomRecord $record, array $tags): FactSourceStatus
130
-    {
131
-        $source_status = new NullFactSourceStatus();
132
-
133
-        foreach ($record->facts($tags) as $fact) {
134
-            $source_status = $source_status->combineWith($this->sourceStatusForFact($fact));
135
-            if ($source_status->isFullySourced()) {
136
-                return $source_status;
137
-            }
138
-        }
139
-
140
-        return $source_status;
141
-    }
142
-
143
-    /**
144
-     * Return the status of source citations for an individual's birth events.
145
-     *
146
-     * @param Individual $individual
147
-     * @return FactSourceStatus
148
-     */
149
-    public function sourceStatusForBirth(Individual $individual): FactSourceStatus
150
-    {
151
-        return $this->sourceStatusForFactsWithTags($individual, Gedcom::BIRTH_EVENTS);
152
-    }
153
-
154
-    /**
155
-     * Return the status of source citations for an individual's death events.
156
-     *
157
-     * @param Individual $individual
158
-     * @return FactSourceStatus
159
-     */
160
-    public function sourceStatusForDeath(Individual $individual): FactSourceStatus
161
-    {
162
-        return $this->sourceStatusForFactsWithTags($individual, Gedcom::DEATH_EVENTS);
163
-    }
164
-
165
-    /**
166
-     * Return the status of source citations for a family's marriage events.
167
-     *
168
-     * @param Family $family
169
-     * @return FactSourceStatus
170
-     */
171
-    public function sourceStatusForMarriage(Family $family): FactSourceStatus
172
-    {
173
-        $marr_events = [...Gedcom::MARRIAGE_EVENTS, 'MARC', 'MARL', 'MARS'];
174
-        return $this->sourceStatusForFactsWithTags($family, $marr_events);
175
-    }
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
+	 * Extract gedcom for all source citations of a fact.
43
+	 * Logic removed from \Fisharebest\Webtrees\Fact.
44
+	 *
45
+	 * @param Fact $fact
46
+	 * @return string[]
47
+	 */
48
+	private function extractCitations(Fact $fact)
49
+	{
50
+		$extract_regex = '/\n(2 SOUR @(' . Gedcom::REGEX_XREF . ')@(?:\n[3-9] .*)*)/';
51
+		preg_match_all($extract_regex, $fact->gedcom(), $matches, PREG_SET_ORDER);
52
+		$citations = [];
53
+		foreach ($matches as $match) {
54
+			$source = Registry::sourceFactory()->make($match[2], $fact->record()->tree());
55
+			if ($source !== null && $source->canShow()) {
56
+				$citations[] = $match[1];
57
+			}
58
+		}
59
+		return $citations;
60
+	}
61
+
62
+	/**
63
+	 * Return the status of source citations for a fact.
64
+	 *
65
+	 * @param Fact $fact
66
+	 * @return FactSourceStatus
67
+	 */
68
+	public function sourceStatusForFact(Fact $fact): FactSourceStatus
69
+	{
70
+		$source_status = new FactSourceStatus();
71
+
72
+		$date = $fact->date();
73
+		$source_status
74
+			->setFactHasDate($date->isOK())
75
+			->setFactHasPreciseDate($date->qual1 === '' && $date->minimumJulianDay() === $date->maximumJulianDay());
76
+
77
+		foreach ($this->extractCitations($fact) as $citation) {
78
+			$source_status
79
+				->setHasSource(true)
80
+				->addHasSupportingDocument(preg_match('/\n3 _ACT (?:.*)/', $citation) === 1);
81
+
82
+			preg_match_all("/\n3 DATA(?:\n[4-9] .*)*\n4 DATE (.*)/", $citation, $date_matches, PREG_SET_ORDER);
83
+			foreach ($date_matches as $date_match) {
84
+				$source_date = new Date($date_match[1]);
85
+				$source_status
86
+					->addSourceHasDate($source_date->isOK())
87
+					->addSourceMatchesFactDate($date->isOK() && $source_date->isOK()
88
+						&& abs($source_date->julianDay() - $date->julianDay()) < self::DATE_PRECISION_MARGIN);
89
+			}
90
+
91
+			if ($source_status->isFullySourced()) {
92
+				return $source_status;
93
+			}
94
+		}
95
+
96
+		return $source_status;
97
+	}
98
+
99
+	/**
100
+	 * Return the status of sources for a Gedcom record.
101
+	 *
102
+	 * @param GedcomRecord $record
103
+	 * @return SourceStatus
104
+	 */
105
+	public function sourceStatusForRecord(GedcomRecord $record): SourceStatus
106
+	{
107
+		$source_status = new SourceStatus();
108
+
109
+		foreach ($record->facts(['SOUR']) as $source) {
110
+			$source_status
111
+				->setHasSource(true)
112
+				->addHasSupportingDocument($source->attribute('_ACT') !== '');
113
+
114
+			if ($source_status->isFullySourced()) {
115
+				return $source_status;
116
+			}
117
+		}
118
+
119
+		return $source_status;
120
+	}
121
+
122
+	/**
123
+	 * Return the status of source citations for a list of fact types associated with a record.
124
+	 *
125
+	 * @param GedcomRecord $record
126
+	 * @param string[] $tags
127
+	 * @return FactSourceStatus
128
+	 */
129
+	public function sourceStatusForFactsWithTags(GedcomRecord $record, array $tags): FactSourceStatus
130
+	{
131
+		$source_status = new NullFactSourceStatus();
132
+
133
+		foreach ($record->facts($tags) as $fact) {
134
+			$source_status = $source_status->combineWith($this->sourceStatusForFact($fact));
135
+			if ($source_status->isFullySourced()) {
136
+				return $source_status;
137
+			}
138
+		}
139
+
140
+		return $source_status;
141
+	}
142
+
143
+	/**
144
+	 * Return the status of source citations for an individual's birth events.
145
+	 *
146
+	 * @param Individual $individual
147
+	 * @return FactSourceStatus
148
+	 */
149
+	public function sourceStatusForBirth(Individual $individual): FactSourceStatus
150
+	{
151
+		return $this->sourceStatusForFactsWithTags($individual, Gedcom::BIRTH_EVENTS);
152
+	}
153
+
154
+	/**
155
+	 * Return the status of source citations for an individual's death events.
156
+	 *
157
+	 * @param Individual $individual
158
+	 * @return FactSourceStatus
159
+	 */
160
+	public function sourceStatusForDeath(Individual $individual): FactSourceStatus
161
+	{
162
+		return $this->sourceStatusForFactsWithTags($individual, Gedcom::DEATH_EVENTS);
163
+	}
164
+
165
+	/**
166
+	 * Return the status of source citations for a family's marriage events.
167
+	 *
168
+	 * @param Family $family
169
+	 * @return FactSourceStatus
170
+	 */
171
+	public function sourceStatusForMarriage(Family $family): FactSourceStatus
172
+	{
173
+		$marr_events = [...Gedcom::MARRIAGE_EVENTS, 'MARC', 'MARL', 'MARS'];
174
+		return $this->sourceStatusForFactsWithTags($family, $marr_events);
175
+	}
176 176
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -47,7 +47,7 @@
 block discarded – undo
47 47
      */
48 48
     private function extractCitations(Fact $fact)
49 49
     {
50
-        $extract_regex = '/\n(2 SOUR @(' . Gedcom::REGEX_XREF . ')@(?:\n[3-9] .*)*)/';
50
+        $extract_regex = '/\n(2 SOUR @('.Gedcom::REGEX_XREF.')@(?:\n[3-9] .*)*)/';
51 51
         preg_match_all($extract_regex, $fact->gedcom(), $matches, PREG_SET_ORDER);
52 52
         $citations = [];
53 53
         foreach ($matches as $match) {
Please login to merge, or discard this patch.
app/Module/GeoDispersion/Model/GeoAnalysisMapAdapter.php 2 patches
Indentation   +187 added lines, -187 removed lines patch added patch discarded remove patch
@@ -29,191 +29,191 @@
 block discarded – undo
29 29
  */
30 30
 class GeoAnalysisMapAdapter
31 31
 {
32
-    private int $id;
33
-    private int $view_id;
34
-    private MapDefinitionInterface $map;
35
-    private PlaceMapperInterface $place_mapper;
36
-    private MapViewConfigInterface $config;
37
-
38
-    /**
39
-     * Constructor for GeoAnalysisMapAdapter
40
-     *
41
-     * @param int $id
42
-     * @param MapDefinitionInterface $map
43
-     * @param PlaceMapperInterface $mapper
44
-     * @param MapViewConfigInterface $config
45
-     */
46
-    public function __construct(
47
-        int $id,
48
-        int $view_id,
49
-        MapDefinitionInterface $map,
50
-        PlaceMapperInterface $mapper,
51
-        MapViewConfigInterface $config
52
-    ) {
53
-        $this->id = $id;
54
-        $this->view_id = $view_id;
55
-        $this->map = $map;
56
-        $this->place_mapper = $mapper;
57
-        $this->config = $config;
58
-        $this->place_mapper->setConfig($this->config->mapperConfig());
59
-        $this->place_mapper->setData('map', $map);
60
-        $this->place_mapper->boot();
61
-    }
62
-
63
-    /**
64
-     * Create a copy of the GeoAnalysisMapAdapter with new properties.
65
-     *
66
-     * @param MapDefinitionInterface $map
67
-     * @param PlaceMapperInterface $mapper
68
-     * @param string $mapping_property
69
-     * @return static
70
-     */
71
-    public function with(
72
-        MapDefinitionInterface $map,
73
-        PlaceMapperInterface $mapper,
74
-        string $mapping_property
75
-    ): self {
76
-        $new = clone $this;
77
-        $new->map = $map;
78
-        $new->place_mapper = $mapper;
79
-        $new->config = $this->config->with($mapping_property, $mapper->config());
80
-        return $new;
81
-    }
82
-
83
-    /**
84
-     * Get the GeoAnalysisMapAdapter ID
85
-     *
86
-     * @return int
87
-     */
88
-    public function id(): int
89
-    {
90
-        return $this->id;
91
-    }
92
-
93
-    /**
94
-     * Get the ID of the associated GeoAnalysisView
95
-     *
96
-     * @return int
97
-     */
98
-    public function geoAnalysisViewId(): int
99
-    {
100
-        return $this->view_id;
101
-    }
102
-
103
-    /**
104
-     * Get the associated target map
105
-     *
106
-     * @return MapDefinitionInterface
107
-     */
108
-    public function map(): MapDefinitionInterface
109
-    {
110
-        return $this->map;
111
-    }
112
-
113
-    /**
114
-     * Get the Place Mapper used for the mapping
115
-     *
116
-     * @return PlaceMapperInterface
117
-     */
118
-    public function placeMapper(): PlaceMapperInterface
119
-    {
120
-        return $this->place_mapper;
121
-    }
122
-
123
-    /**
124
-     * Get the configuration of the Map View.
125
-     *
126
-     * @return MapViewConfigInterface
127
-     */
128
-    public function viewConfig(): MapViewConfigInterface
129
-    {
130
-        return $this->config;
131
-    }
132
-
133
-    /**
134
-     * Convert the geographical analysis result to a MapAdapter result for usage in the Map View
135
-     *
136
-     * @param GeoAnalysisResult $result
137
-     * @return MapAdapterResult
138
-     */
139
-    public function convert(GeoAnalysisResult $result): MapAdapterResult
140
-    {
141
-        $result = $result->copy();
142
-
143
-        $features = [];
144
-        list($features_data, $result) = $this->featureAnalysisData($result);
145
-
146
-        $places_found = $result->countFound();
147
-        foreach ($this->map->features() as $feature) {
148
-            $feature_id = $this->featureId($feature);
149
-            if ($feature_id !== null && $features_data->has($feature_id)) {
150
-                /** @var MapFeatureAnalysisData $feature_data */
151
-                $feature_data = $features_data->get($feature_id)->tagAsExisting();
152
-                $place_count = $feature_data->count();
153
-                $features[] = $feature
154
-                    ->withProperty('count', $place_count)
155
-                    ->withProperty('ratio', $places_found > 0 ? $place_count / $places_found : 0)
156
-                    ->withProperty(
157
-                        'places',
158
-                        $feature_data->places()
159
-                            ->map(fn(GeoAnalysisPlace $place): string => $place->place()->firstParts(1)->first())
160
-                            ->sort(I18N::comparator())
161
-                            ->toArray()
162
-                    );
163
-            } else {
164
-                $features[] = $feature;
165
-            }
166
-        }
167
-
168
-        $features_data
169
-            ->filter(fn(MapFeatureAnalysisData $data) => !$data->existsInMap())
170
-            ->each(
171
-                fn (MapFeatureAnalysisData $data) =>
172
-                    $data->places()->each(
173
-                        function (GeoAnalysisPlace $place) use ($result): void {
174
-                            $result->exclude($place);
175
-                        }
176
-                    )
177
-            );
178
-
179
-        return new MapAdapterResult($result, $features);
180
-    }
181
-
182
-    /**
183
-     * Populate the map features with the mapped Places and total count
184
-     *
185
-     * @param GeoAnalysisResult $result
186
-     * @return mixed[]
187
-     */
188
-    protected function featureAnalysisData(GeoAnalysisResult $result): array
189
-    {
190
-        $features_mapping = new Collection();
191
-
192
-        $byplaces = $result->knownPlaces();
193
-        $byplaces->each(function (GeoAnalysisResultItem $item) use ($features_mapping, $result): void {
194
-            $id = $this->place_mapper->map($item->place()->place(), $this->config->mapMappingProperty());
195
-
196
-            if ($id !== null && mb_strlen($id) > 0) {
197
-                $features_mapping->put(
198
-                    $id,
199
-                    $features_mapping->get($id, new MapFeatureAnalysisData())->add($item->place(), $item->count())
200
-                );
201
-            } else {
202
-                $result->exclude($item->place());
203
-            }
204
-        });
205
-
206
-        return [ $features_mapping, $result];
207
-    }
208
-
209
-    /**
210
-     * Get the value of the feature property used for the mapping
211
-     *
212
-     * @param Feature $feature
213
-     * @return string|NULL
214
-     */
215
-    protected function featureId(Feature $feature): ?string
216
-    {
217
-        return $feature->getProperty($this->config->mapMappingProperty());
218
-    }
32
+	private int $id;
33
+	private int $view_id;
34
+	private MapDefinitionInterface $map;
35
+	private PlaceMapperInterface $place_mapper;
36
+	private MapViewConfigInterface $config;
37
+
38
+	/**
39
+	 * Constructor for GeoAnalysisMapAdapter
40
+	 *
41
+	 * @param int $id
42
+	 * @param MapDefinitionInterface $map
43
+	 * @param PlaceMapperInterface $mapper
44
+	 * @param MapViewConfigInterface $config
45
+	 */
46
+	public function __construct(
47
+		int $id,
48
+		int $view_id,
49
+		MapDefinitionInterface $map,
50
+		PlaceMapperInterface $mapper,
51
+		MapViewConfigInterface $config
52
+	) {
53
+		$this->id = $id;
54
+		$this->view_id = $view_id;
55
+		$this->map = $map;
56
+		$this->place_mapper = $mapper;
57
+		$this->config = $config;
58
+		$this->place_mapper->setConfig($this->config->mapperConfig());
59
+		$this->place_mapper->setData('map', $map);
60
+		$this->place_mapper->boot();
61
+	}
62
+
63
+	/**
64
+	 * Create a copy of the GeoAnalysisMapAdapter with new properties.
65
+	 *
66
+	 * @param MapDefinitionInterface $map
67
+	 * @param PlaceMapperInterface $mapper
68
+	 * @param string $mapping_property
69
+	 * @return static
70
+	 */
71
+	public function with(
72
+		MapDefinitionInterface $map,
73
+		PlaceMapperInterface $mapper,
74
+		string $mapping_property
75
+	): self {
76
+		$new = clone $this;
77
+		$new->map = $map;
78
+		$new->place_mapper = $mapper;
79
+		$new->config = $this->config->with($mapping_property, $mapper->config());
80
+		return $new;
81
+	}
82
+
83
+	/**
84
+	 * Get the GeoAnalysisMapAdapter ID
85
+	 *
86
+	 * @return int
87
+	 */
88
+	public function id(): int
89
+	{
90
+		return $this->id;
91
+	}
92
+
93
+	/**
94
+	 * Get the ID of the associated GeoAnalysisView
95
+	 *
96
+	 * @return int
97
+	 */
98
+	public function geoAnalysisViewId(): int
99
+	{
100
+		return $this->view_id;
101
+	}
102
+
103
+	/**
104
+	 * Get the associated target map
105
+	 *
106
+	 * @return MapDefinitionInterface
107
+	 */
108
+	public function map(): MapDefinitionInterface
109
+	{
110
+		return $this->map;
111
+	}
112
+
113
+	/**
114
+	 * Get the Place Mapper used for the mapping
115
+	 *
116
+	 * @return PlaceMapperInterface
117
+	 */
118
+	public function placeMapper(): PlaceMapperInterface
119
+	{
120
+		return $this->place_mapper;
121
+	}
122
+
123
+	/**
124
+	 * Get the configuration of the Map View.
125
+	 *
126
+	 * @return MapViewConfigInterface
127
+	 */
128
+	public function viewConfig(): MapViewConfigInterface
129
+	{
130
+		return $this->config;
131
+	}
132
+
133
+	/**
134
+	 * Convert the geographical analysis result to a MapAdapter result for usage in the Map View
135
+	 *
136
+	 * @param GeoAnalysisResult $result
137
+	 * @return MapAdapterResult
138
+	 */
139
+	public function convert(GeoAnalysisResult $result): MapAdapterResult
140
+	{
141
+		$result = $result->copy();
142
+
143
+		$features = [];
144
+		list($features_data, $result) = $this->featureAnalysisData($result);
145
+
146
+		$places_found = $result->countFound();
147
+		foreach ($this->map->features() as $feature) {
148
+			$feature_id = $this->featureId($feature);
149
+			if ($feature_id !== null && $features_data->has($feature_id)) {
150
+				/** @var MapFeatureAnalysisData $feature_data */
151
+				$feature_data = $features_data->get($feature_id)->tagAsExisting();
152
+				$place_count = $feature_data->count();
153
+				$features[] = $feature
154
+					->withProperty('count', $place_count)
155
+					->withProperty('ratio', $places_found > 0 ? $place_count / $places_found : 0)
156
+					->withProperty(
157
+						'places',
158
+						$feature_data->places()
159
+							->map(fn(GeoAnalysisPlace $place): string => $place->place()->firstParts(1)->first())
160
+							->sort(I18N::comparator())
161
+							->toArray()
162
+					);
163
+			} else {
164
+				$features[] = $feature;
165
+			}
166
+		}
167
+
168
+		$features_data
169
+			->filter(fn(MapFeatureAnalysisData $data) => !$data->existsInMap())
170
+			->each(
171
+				fn (MapFeatureAnalysisData $data) =>
172
+					$data->places()->each(
173
+						function (GeoAnalysisPlace $place) use ($result): void {
174
+							$result->exclude($place);
175
+						}
176
+					)
177
+			);
178
+
179
+		return new MapAdapterResult($result, $features);
180
+	}
181
+
182
+	/**
183
+	 * Populate the map features with the mapped Places and total count
184
+	 *
185
+	 * @param GeoAnalysisResult $result
186
+	 * @return mixed[]
187
+	 */
188
+	protected function featureAnalysisData(GeoAnalysisResult $result): array
189
+	{
190
+		$features_mapping = new Collection();
191
+
192
+		$byplaces = $result->knownPlaces();
193
+		$byplaces->each(function (GeoAnalysisResultItem $item) use ($features_mapping, $result): void {
194
+			$id = $this->place_mapper->map($item->place()->place(), $this->config->mapMappingProperty());
195
+
196
+			if ($id !== null && mb_strlen($id) > 0) {
197
+				$features_mapping->put(
198
+					$id,
199
+					$features_mapping->get($id, new MapFeatureAnalysisData())->add($item->place(), $item->count())
200
+				);
201
+			} else {
202
+				$result->exclude($item->place());
203
+			}
204
+		});
205
+
206
+		return [ $features_mapping, $result];
207
+	}
208
+
209
+	/**
210
+	 * Get the value of the feature property used for the mapping
211
+	 *
212
+	 * @param Feature $feature
213
+	 * @return string|NULL
214
+	 */
215
+	protected function featureId(Feature $feature): ?string
216
+	{
217
+		return $feature->getProperty($this->config->mapMappingProperty());
218
+	}
219 219
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
                     ->withProperty(
157 157
                         'places',
158 158
                         $feature_data->places()
159
-                            ->map(fn(GeoAnalysisPlace $place): string => $place->place()->firstParts(1)->first())
159
+                            ->map(fn(GeoAnalysisPlace $place) : string => $place->place()->firstParts(1)->first())
160 160
                             ->sort(I18N::comparator())
161 161
                             ->toArray()
162 162
                     );
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
             ->each(
171 171
                 fn (MapFeatureAnalysisData $data) =>
172 172
                     $data->places()->each(
173
-                        function (GeoAnalysisPlace $place) use ($result): void {
173
+                        function(GeoAnalysisPlace $place) use ($result): void {
174 174
                             $result->exclude($place);
175 175
                         }
176 176
                     )
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
         $features_mapping = new Collection();
191 191
 
192 192
         $byplaces = $result->knownPlaces();
193
-        $byplaces->each(function (GeoAnalysisResultItem $item) use ($features_mapping, $result): void {
193
+        $byplaces->each(function(GeoAnalysisResultItem $item) use ($features_mapping, $result): void {
194 194
             $id = $this->place_mapper->map($item->place()->place(), $this->config->mapMappingProperty());
195 195
 
196 196
             if ($id !== null && mb_strlen($id) > 0) {
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
             }
204 204
         });
205 205
 
206
-        return [ $features_mapping, $result];
206
+        return [$features_mapping, $result];
207 207
     }
208 208
 
209 209
     /**
Please login to merge, or discard this patch.
app/Module/GeoDispersion/PlaceMappers/CoordinatesPlaceMapper.php 1 patch
Indentation   +184 added lines, -184 removed lines patch added patch discarded remove patch
@@ -36,188 +36,188 @@
 block discarded – undo
36 36
  */
37 37
 class CoordinatesPlaceMapper implements PlaceMapperInterface
38 38
 {
39
-    use PlaceMapperTrait;
40
-
41
-    private ?string $cache_key = null;
42
-    private ?GeometryEngine $geometry_engine = null;
43
-
44
-    /**
45
-     * {@inheritDoc}
46
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::title()
47
-     */
48
-    public function title(): string
49
-    {
50
-        return I18N::translate('Mapping on place coordinates');
51
-    }
52
-
53
-    /**
54
-     * {@inheritDoc}
55
-     *
56
-     * {@internal The Place is associated to a Point only.
57
-     * PlaceLocation can calculate a BoundingBox.
58
-     * Using a BoundingBox could make the mapping more complex and potentially arbitary.
59
-     * Furthermore, when no coordinate is found for the place or its children, then it bubbles up to the parents.
60
-     * This could create the unwanted side effect of a very large area to consider}
61
-     *
62
-     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::map()
63
-     */
64
-    public function map(Place $place, string $feature_property): ?string
65
-    {
66
-        $location = new PlaceLocation($place->gedcomName());
67
-        $longitude = $location->longitude();
68
-        $latitude = $location->latitude();
69
-        if ($longitude === null || $latitude === null) {
70
-            return null;
71
-        }
72
-
73
-        $features_index = $this->featuresIndex();
74
-        if ($features_index === null) {
75
-            return null;
76
-        }
77
-
78
-        $place_point = Point::xy($longitude, $latitude, $features_index['SRID']);
79
-        $grid_box = $this->getGridCell(
80
-            $place_point,
81
-            $features_index['map_NE'],
82
-            $features_index['map_SW'],
83
-            $features_index['nb_columns']
84
-        );
85
-        if ($grid_box === null || !$this->setGeometryEngine() || $this->geometry_engine == null) {
86
-            return null;
87
-        }
88
-        $features = $features_index['grid'][$grid_box[0]][$grid_box[1]];
89
-        foreach ($features as $feature) {
90
-            $geometry = $feature->getGeometry();
91
-            if (
92
-                $geometry !== null && $place_point->SRID() === $geometry->SRID() &&
93
-                $this->geometry_engine->contains($geometry, $place_point)
94
-            ) {
95
-                return $feature->getProperty($feature_property);
96
-            }
97
-        }
98
-        return null;
99
-    }
100
-
101
-    /**
102
-     * Return the XY coordinates in a bounded grid of the cell containing a specific point.
103
-     *
104
-     * @param Point $point Point to find
105
-     * @param Point $grid_NE North-East point of the bounded grid
106
-     * @param Point $grid_SW South-West point fo the bounded grid
107
-     * @param int $grid_columns Number of columns/rows in the grid
108
-     * @return int[]|NULL
109
-     */
110
-    protected function getGridCell(Point $point, Point $grid_NE, Point $grid_SW, int $grid_columns): ?array
111
-    {
112
-        list($x, $y) = $point->toArray();
113
-        list($x_max, $y_max) = $grid_NE->toArray();
114
-        list($x_min, $y_min) = $grid_SW->toArray();
115
-
116
-        $x_step = ($x_max - $x_min) / $grid_columns;
117
-        $y_step = ($y_max - $y_min) / $grid_columns;
118
-
119
-        if ($x_min <= $x && $x <= $x_max && $y_min <= $y && $y <= $y_max) {
120
-            return [
121
-                $x === $x_max ? $grid_columns - 1 : intval(($x - $x_min) / $x_step),
122
-                $y === $y_max ? $grid_columns - 1 : intval(($y - $y_min) / $y_step)
123
-            ];
124
-        }
125
-        return null;
126
-    }
127
-
128
-    /**
129
-     * Get an indexed array of the features of the map.
130
-     *
131
-     * {@internal The map is divided in a grid, eacg cell containing the features which bounding box overlaps that cell.
132
-     * The grid is computed once for each map, and cached.}
133
-     *
134
-     * @phpcs:ignore Generic.Files.LineLength.TooLong
135
-     * @return array{grid: array<int, array<int, \Brick\Geo\IO\GeoJSON\Feature[]>>, nb_columns: int, map_NE: \Brick\Geo\Point, map_SW: \Brick\Geo\Point, SRID: int}|NULL
136
-     */
137
-    protected function featuresIndex(): ?array
138
-    {
139
-        $cacheKey = $this->cacheKey();
140
-        if ($cacheKey === null) {
141
-            return null;
142
-        }
143
-        return Registry::cache()->array()->remember($cacheKey, function (): ?array {
144
-            $map_def = $this->data('map');
145
-            if (
146
-                !$this->setGeometryEngine()
147
-                || $map_def === null
148
-                || !($map_def instanceof MapDefinitionInterface)
149
-            ) {
150
-                return null;
151
-            }
152
-            $bounding_boxes = [];
153
-            $map_bounding_box = new BoundingBox();
154
-            $srid = 0;
155
-            foreach ($map_def->features() as $feature) {
156
-                $geometry = $feature->getGeometry();
157
-                if ($geometry === null) {
158
-                    continue;
159
-                }
160
-                $srid = $geometry->SRID();
161
-                $bounding_box = $geometry->getBoundingBox();
162
-                $bounding_boxes[] = [$feature, $bounding_box];
163
-                $map_bounding_box = $map_bounding_box->extendedWithBoundingBox($bounding_box);
164
-            }
165
-            $grid_columns = count($bounding_boxes);
166
-            $grid = array_fill(0, $grid_columns, array_fill(0, $grid_columns, []));
167
-            $map_NE = $map_bounding_box->getNorthEast();
168
-            $map_SW = $map_bounding_box->getSouthWest();
169
-            foreach ($bounding_boxes as $item) {
170
-                $grid_box_SW = $this->getGridCell($item[1]->getSouthWest(), $map_NE, $map_SW, $grid_columns) ?? [1, 1];
171
-                $grid_box_NE = $this->getGridCell($item[1]->getNorthEast(), $map_NE, $map_SW, $grid_columns) ?? [0, 0];
172
-                for ($i = $grid_box_SW[0]; $i <= $grid_box_NE[0]; $i++) {
173
-                    for ($j = $grid_box_SW[1]; $j <= $grid_box_NE[1]; $j++) {
174
-                        $grid[$i][$j][] = $item[0];
175
-                    }
176
-                }
177
-            }
178
-            return [
179
-                'grid'          =>  $grid,
180
-                'nb_columns'    =>  $grid_columns,
181
-                'map_NE'        =>  $map_NE,
182
-                'map_SW'        =>  $map_SW,
183
-                'SRID'          =>  $srid
184
-            ];
185
-        });
186
-    }
187
-
188
-    /**
189
-     * Set the Brick Geo Engine to use the database for geospatial computations.
190
-     * The engine is set only if it has not been set beforehand.
191
-     *
192
-     * @return bool
193
-     */
194
-    protected function setGeometryEngine(): bool
195
-    {
196
-        try {
197
-            if ($this->geometry_engine === null) {
198
-                $this->geometry_engine = new PDOEngine(DB::connection()->getPdo());
199
-            }
200
-            $point = Point::xy(1, 1);
201
-            return $this->geometry_engine->equals($point, $point);
202
-        } catch (Throwable $ex) {
203
-        }
204
-        return false;
205
-    }
206
-
207
-    /**
208
-     * Get the key to cache the indexed grid of features.
209
-     *
210
-     * @return string|NULL
211
-     */
212
-    protected function cacheKey(): ?string
213
-    {
214
-        if ($this->cache_key === null) {
215
-            $map_def = $this->data('map');
216
-            if ($map_def === null || !($map_def instanceof MapDefinitionInterface)) {
217
-                return null;
218
-            }
219
-            return spl_object_id($this) . '-map-' . $map_def->id();
220
-        }
221
-        return $this->cache_key;
222
-    }
39
+	use PlaceMapperTrait;
40
+
41
+	private ?string $cache_key = null;
42
+	private ?GeometryEngine $geometry_engine = null;
43
+
44
+	/**
45
+	 * {@inheritDoc}
46
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::title()
47
+	 */
48
+	public function title(): string
49
+	{
50
+		return I18N::translate('Mapping on place coordinates');
51
+	}
52
+
53
+	/**
54
+	 * {@inheritDoc}
55
+	 *
56
+	 * {@internal The Place is associated to a Point only.
57
+	 * PlaceLocation can calculate a BoundingBox.
58
+	 * Using a BoundingBox could make the mapping more complex and potentially arbitary.
59
+	 * Furthermore, when no coordinate is found for the place or its children, then it bubbles up to the parents.
60
+	 * This could create the unwanted side effect of a very large area to consider}
61
+	 *
62
+	 * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::map()
63
+	 */
64
+	public function map(Place $place, string $feature_property): ?string
65
+	{
66
+		$location = new PlaceLocation($place->gedcomName());
67
+		$longitude = $location->longitude();
68
+		$latitude = $location->latitude();
69
+		if ($longitude === null || $latitude === null) {
70
+			return null;
71
+		}
72
+
73
+		$features_index = $this->featuresIndex();
74
+		if ($features_index === null) {
75
+			return null;
76
+		}
77
+
78
+		$place_point = Point::xy($longitude, $latitude, $features_index['SRID']);
79
+		$grid_box = $this->getGridCell(
80
+			$place_point,
81
+			$features_index['map_NE'],
82
+			$features_index['map_SW'],
83
+			$features_index['nb_columns']
84
+		);
85
+		if ($grid_box === null || !$this->setGeometryEngine() || $this->geometry_engine == null) {
86
+			return null;
87
+		}
88
+		$features = $features_index['grid'][$grid_box[0]][$grid_box[1]];
89
+		foreach ($features as $feature) {
90
+			$geometry = $feature->getGeometry();
91
+			if (
92
+				$geometry !== null && $place_point->SRID() === $geometry->SRID() &&
93
+				$this->geometry_engine->contains($geometry, $place_point)
94
+			) {
95
+				return $feature->getProperty($feature_property);
96
+			}
97
+		}
98
+		return null;
99
+	}
100
+
101
+	/**
102
+	 * Return the XY coordinates in a bounded grid of the cell containing a specific point.
103
+	 *
104
+	 * @param Point $point Point to find
105
+	 * @param Point $grid_NE North-East point of the bounded grid
106
+	 * @param Point $grid_SW South-West point fo the bounded grid
107
+	 * @param int $grid_columns Number of columns/rows in the grid
108
+	 * @return int[]|NULL
109
+	 */
110
+	protected function getGridCell(Point $point, Point $grid_NE, Point $grid_SW, int $grid_columns): ?array
111
+	{
112
+		list($x, $y) = $point->toArray();
113
+		list($x_max, $y_max) = $grid_NE->toArray();
114
+		list($x_min, $y_min) = $grid_SW->toArray();
115
+
116
+		$x_step = ($x_max - $x_min) / $grid_columns;
117
+		$y_step = ($y_max - $y_min) / $grid_columns;
118
+
119
+		if ($x_min <= $x && $x <= $x_max && $y_min <= $y && $y <= $y_max) {
120
+			return [
121
+				$x === $x_max ? $grid_columns - 1 : intval(($x - $x_min) / $x_step),
122
+				$y === $y_max ? $grid_columns - 1 : intval(($y - $y_min) / $y_step)
123
+			];
124
+		}
125
+		return null;
126
+	}
127
+
128
+	/**
129
+	 * Get an indexed array of the features of the map.
130
+	 *
131
+	 * {@internal The map is divided in a grid, eacg cell containing the features which bounding box overlaps that cell.
132
+	 * The grid is computed once for each map, and cached.}
133
+	 *
134
+	 * @phpcs:ignore Generic.Files.LineLength.TooLong
135
+	 * @return array{grid: array<int, array<int, \Brick\Geo\IO\GeoJSON\Feature[]>>, nb_columns: int, map_NE: \Brick\Geo\Point, map_SW: \Brick\Geo\Point, SRID: int}|NULL
136
+	 */
137
+	protected function featuresIndex(): ?array
138
+	{
139
+		$cacheKey = $this->cacheKey();
140
+		if ($cacheKey === null) {
141
+			return null;
142
+		}
143
+		return Registry::cache()->array()->remember($cacheKey, function (): ?array {
144
+			$map_def = $this->data('map');
145
+			if (
146
+				!$this->setGeometryEngine()
147
+				|| $map_def === null
148
+				|| !($map_def instanceof MapDefinitionInterface)
149
+			) {
150
+				return null;
151
+			}
152
+			$bounding_boxes = [];
153
+			$map_bounding_box = new BoundingBox();
154
+			$srid = 0;
155
+			foreach ($map_def->features() as $feature) {
156
+				$geometry = $feature->getGeometry();
157
+				if ($geometry === null) {
158
+					continue;
159
+				}
160
+				$srid = $geometry->SRID();
161
+				$bounding_box = $geometry->getBoundingBox();
162
+				$bounding_boxes[] = [$feature, $bounding_box];
163
+				$map_bounding_box = $map_bounding_box->extendedWithBoundingBox($bounding_box);
164
+			}
165
+			$grid_columns = count($bounding_boxes);
166
+			$grid = array_fill(0, $grid_columns, array_fill(0, $grid_columns, []));
167
+			$map_NE = $map_bounding_box->getNorthEast();
168
+			$map_SW = $map_bounding_box->getSouthWest();
169
+			foreach ($bounding_boxes as $item) {
170
+				$grid_box_SW = $this->getGridCell($item[1]->getSouthWest(), $map_NE, $map_SW, $grid_columns) ?? [1, 1];
171
+				$grid_box_NE = $this->getGridCell($item[1]->getNorthEast(), $map_NE, $map_SW, $grid_columns) ?? [0, 0];
172
+				for ($i = $grid_box_SW[0]; $i <= $grid_box_NE[0]; $i++) {
173
+					for ($j = $grid_box_SW[1]; $j <= $grid_box_NE[1]; $j++) {
174
+						$grid[$i][$j][] = $item[0];
175
+					}
176
+				}
177
+			}
178
+			return [
179
+				'grid'          =>  $grid,
180
+				'nb_columns'    =>  $grid_columns,
181
+				'map_NE'        =>  $map_NE,
182
+				'map_SW'        =>  $map_SW,
183
+				'SRID'          =>  $srid
184
+			];
185
+		});
186
+	}
187
+
188
+	/**
189
+	 * Set the Brick Geo Engine to use the database for geospatial computations.
190
+	 * The engine is set only if it has not been set beforehand.
191
+	 *
192
+	 * @return bool
193
+	 */
194
+	protected function setGeometryEngine(): bool
195
+	{
196
+		try {
197
+			if ($this->geometry_engine === null) {
198
+				$this->geometry_engine = new PDOEngine(DB::connection()->getPdo());
199
+			}
200
+			$point = Point::xy(1, 1);
201
+			return $this->geometry_engine->equals($point, $point);
202
+		} catch (Throwable $ex) {
203
+		}
204
+		return false;
205
+	}
206
+
207
+	/**
208
+	 * Get the key to cache the indexed grid of features.
209
+	 *
210
+	 * @return string|NULL
211
+	 */
212
+	protected function cacheKey(): ?string
213
+	{
214
+		if ($this->cache_key === null) {
215
+			$map_def = $this->data('map');
216
+			if ($map_def === null || !($map_def instanceof MapDefinitionInterface)) {
217
+				return null;
218
+			}
219
+			return spl_object_id($this) . '-map-' . $map_def->id();
220
+		}
221
+		return $this->cache_key;
222
+	}
223 223
 }
Please login to merge, or discard this patch.
app/Module/Certificates/Model/Certificate.php 1 patch
Indentation   +189 added lines, -189 removed lines patch added patch discarded remove patch
@@ -25,193 +25,193 @@
 block discarded – undo
25 25
  */
26 26
 class Certificate
27 27
 {
28
-    /**
29
-     * Pattern to extract information from a file name.
30
-     * Specific to the author's workflow.
31
-     * @var string
32
-     */
33
-    private const FILENAME_PATTERN = '/^(?<year>\d{1,4})(\.(?<month>\d{1,2}))?(\.(?<day>\d{1,2}))?( (?<type>[A-Z]{1,2}))?\s(?<descr>.*)/'; //phpcs:ignore Generic.Files.LineLength.TooLong
34
-
35
-    private Tree $tree;
36
-    private string $path;
37
-    private ?string $city = null;
38
-    private ?string $basename = null;
39
-    private ?string $filename = null;
40
-    private ?string $extension = null;
41
-    private ?string $type = null;
42
-    private ?string $description = null;
43
-    private ?Date $date = null;
44
-
45
-    /**
46
-     * Contructor for Certificate
47
-     *
48
-     * @param Tree $tree
49
-     * @param string $path
50
-     */
51
-    public function __construct(Tree $tree, string $path)
52
-    {
53
-        $this->tree = $tree;
54
-        $this->path = $path;
55
-        $this->extractDataFromPath($path);
56
-    }
57
-
58
-    /**
59
-     * Populate fields from the filename, based on a predeterminate pattern.
60
-     * Logic specific to the author.
61
-     *
62
-     * @param string $path
63
-     */
64
-    protected function extractDataFromPath(string $path): void
65
-    {
66
-        $path_parts = pathinfo($this->gedcomPath());
67
-        $this->city = $path_parts['dirname'] ?? '';
68
-        $this->basename = $path_parts['basename'];
69
-        $this->filename = $path_parts['filename'];
70
-        $this->extension = strtoupper($path_parts['extension'] ?? '');
71
-
72
-        if (preg_match(self::FILENAME_PATTERN, $this->filename, $match) === 1) {
73
-            $this->type = $match['type'];
74
-            $this->description = $match['descr'];
75
-
76
-            $day = $match['day'] ?? '';
77
-            $month_date = DateTime::createFromFormat('m', $match['month'] ?? '');
78
-            $month = $month_date !== false ? strtoupper($month_date->format('M')) : '';
79
-            $year = $match['year'] ?? '';
80
-
81
-            $this->date = new Date(sprintf('%s %s %s', $day, $month, $year));
82
-        } else {
83
-            $this->description = $this->filename;
84
-        }
85
-    }
86
-
87
-    /**
88
-     * Get the family tree of the certificate
89
-     *
90
-     * @return Tree
91
-     */
92
-    public function tree(): Tree
93
-    {
94
-        return $this->tree;
95
-    }
96
-
97
-    /**
98
-     * Get the path of the certificate in the file system.
99
-     *
100
-     * @return string
101
-     */
102
-    public function path(): string
103
-    {
104
-        return $this->path;
105
-    }
106
-
107
-    /**
108
-     * The the path of the certificate, in a Gedcom canonical form.
109
-     *
110
-     * @return string
111
-     */
112
-    public function gedcomPath(): string
113
-    {
114
-        return str_replace('\\', '/', $this->path);
115
-    }
116
-
117
-    /**
118
-     * Get the certificate name.
119
-     *
120
-     * @return string
121
-     */
122
-    public function name(): string
123
-    {
124
-        return $this->filename ?? '';
125
-    }
126
-
127
-    /**
128
-     * Get the certificate file name.
129
-     *
130
-     * @return string
131
-     */
132
-    public function filename(): string
133
-    {
134
-        return $this->basename ?? '';
135
-    }
136
-
137
-    /**
138
-     * Get the certificate's city (the first level folder).
139
-     *
140
-     * @return string
141
-     */
142
-    public function city(): string
143
-    {
144
-        return $this->city ?? '';
145
-    }
146
-
147
-    /**
148
-     * Get the certificate's date. Extracted from the file name.
149
-     *
150
-     * @return Date
151
-     */
152
-    public function date(): Date
153
-    {
154
-        return $this->date ?? new Date('');
155
-    }
156
-
157
-    /**
158
-     * Get the certificate's type. Extracted from the file name.
159
-     *
160
-     * @return string
161
-     */
162
-    public function type(): string
163
-    {
164
-        return $this->type ?? '';
165
-    }
166
-
167
-    /**
168
-     * Get the certificate's description.  Extracted from the file name.
169
-     * @return string
170
-     */
171
-    public function description(): string
172
-    {
173
-        return $this->description ?? '';
174
-    }
175
-
176
-    /**
177
-     * Get the certificate's description to be used for sorting.
178
-     * This is based on surnames (at least 3 letters) found in the file name.
179
-     *
180
-     * @return string
181
-     */
182
-    public function sortDescription(): string
183
-    {
184
-        $sort_prefix = '';
185
-        if (preg_match_all('/\b([A-Z]{3,})\b/', $this->description(), $matches, PREG_SET_ORDER) >= 1) {
186
-            $sort_prefix = implode('_', array_map(function ($match) {
187
-                return $match[1];
188
-            }, $matches)) . '_';
189
-        }
190
-        return $sort_prefix . $this->description();
191
-    }
192
-
193
-    /**
194
-     * Get the certificate's MIME type.
195
-     *
196
-     * @return string
197
-     */
198
-    public function mimeType(): string
199
-    {
200
-        return Mime::TYPES[$this->extension] ?? Mime::DEFAULT_TYPE;
201
-    }
202
-
203
-    /**
204
-     * Get the base parameters to be used in url referencing the certificate.
205
-     *
206
-     * @param UrlObfuscatorService $url_obfuscator_service
207
-     * @return array{tree: string, cid: mixed}
208
-     */
209
-    public function urlParameters(UrlObfuscatorService $url_obfuscator_service = null): array
210
-    {
211
-        $url_obfuscator_service = $url_obfuscator_service ?? app(UrlObfuscatorService::class);
212
-        return [
213
-            'tree' => $this->tree->name(),
214
-            'cid' => $url_obfuscator_service->obfuscate($this->path)
215
-        ];
216
-    }
28
+	/**
29
+	 * Pattern to extract information from a file name.
30
+	 * Specific to the author's workflow.
31
+	 * @var string
32
+	 */
33
+	private const FILENAME_PATTERN = '/^(?<year>\d{1,4})(\.(?<month>\d{1,2}))?(\.(?<day>\d{1,2}))?( (?<type>[A-Z]{1,2}))?\s(?<descr>.*)/'; //phpcs:ignore Generic.Files.LineLength.TooLong
34
+
35
+	private Tree $tree;
36
+	private string $path;
37
+	private ?string $city = null;
38
+	private ?string $basename = null;
39
+	private ?string $filename = null;
40
+	private ?string $extension = null;
41
+	private ?string $type = null;
42
+	private ?string $description = null;
43
+	private ?Date $date = null;
44
+
45
+	/**
46
+	 * Contructor for Certificate
47
+	 *
48
+	 * @param Tree $tree
49
+	 * @param string $path
50
+	 */
51
+	public function __construct(Tree $tree, string $path)
52
+	{
53
+		$this->tree = $tree;
54
+		$this->path = $path;
55
+		$this->extractDataFromPath($path);
56
+	}
57
+
58
+	/**
59
+	 * Populate fields from the filename, based on a predeterminate pattern.
60
+	 * Logic specific to the author.
61
+	 *
62
+	 * @param string $path
63
+	 */
64
+	protected function extractDataFromPath(string $path): void
65
+	{
66
+		$path_parts = pathinfo($this->gedcomPath());
67
+		$this->city = $path_parts['dirname'] ?? '';
68
+		$this->basename = $path_parts['basename'];
69
+		$this->filename = $path_parts['filename'];
70
+		$this->extension = strtoupper($path_parts['extension'] ?? '');
71
+
72
+		if (preg_match(self::FILENAME_PATTERN, $this->filename, $match) === 1) {
73
+			$this->type = $match['type'];
74
+			$this->description = $match['descr'];
75
+
76
+			$day = $match['day'] ?? '';
77
+			$month_date = DateTime::createFromFormat('m', $match['month'] ?? '');
78
+			$month = $month_date !== false ? strtoupper($month_date->format('M')) : '';
79
+			$year = $match['year'] ?? '';
80
+
81
+			$this->date = new Date(sprintf('%s %s %s', $day, $month, $year));
82
+		} else {
83
+			$this->description = $this->filename;
84
+		}
85
+	}
86
+
87
+	/**
88
+	 * Get the family tree of the certificate
89
+	 *
90
+	 * @return Tree
91
+	 */
92
+	public function tree(): Tree
93
+	{
94
+		return $this->tree;
95
+	}
96
+
97
+	/**
98
+	 * Get the path of the certificate in the file system.
99
+	 *
100
+	 * @return string
101
+	 */
102
+	public function path(): string
103
+	{
104
+		return $this->path;
105
+	}
106
+
107
+	/**
108
+	 * The the path of the certificate, in a Gedcom canonical form.
109
+	 *
110
+	 * @return string
111
+	 */
112
+	public function gedcomPath(): string
113
+	{
114
+		return str_replace('\\', '/', $this->path);
115
+	}
116
+
117
+	/**
118
+	 * Get the certificate name.
119
+	 *
120
+	 * @return string
121
+	 */
122
+	public function name(): string
123
+	{
124
+		return $this->filename ?? '';
125
+	}
126
+
127
+	/**
128
+	 * Get the certificate file name.
129
+	 *
130
+	 * @return string
131
+	 */
132
+	public function filename(): string
133
+	{
134
+		return $this->basename ?? '';
135
+	}
136
+
137
+	/**
138
+	 * Get the certificate's city (the first level folder).
139
+	 *
140
+	 * @return string
141
+	 */
142
+	public function city(): string
143
+	{
144
+		return $this->city ?? '';
145
+	}
146
+
147
+	/**
148
+	 * Get the certificate's date. Extracted from the file name.
149
+	 *
150
+	 * @return Date
151
+	 */
152
+	public function date(): Date
153
+	{
154
+		return $this->date ?? new Date('');
155
+	}
156
+
157
+	/**
158
+	 * Get the certificate's type. Extracted from the file name.
159
+	 *
160
+	 * @return string
161
+	 */
162
+	public function type(): string
163
+	{
164
+		return $this->type ?? '';
165
+	}
166
+
167
+	/**
168
+	 * Get the certificate's description.  Extracted from the file name.
169
+	 * @return string
170
+	 */
171
+	public function description(): string
172
+	{
173
+		return $this->description ?? '';
174
+	}
175
+
176
+	/**
177
+	 * Get the certificate's description to be used for sorting.
178
+	 * This is based on surnames (at least 3 letters) found in the file name.
179
+	 *
180
+	 * @return string
181
+	 */
182
+	public function sortDescription(): string
183
+	{
184
+		$sort_prefix = '';
185
+		if (preg_match_all('/\b([A-Z]{3,})\b/', $this->description(), $matches, PREG_SET_ORDER) >= 1) {
186
+			$sort_prefix = implode('_', array_map(function ($match) {
187
+				return $match[1];
188
+			}, $matches)) . '_';
189
+		}
190
+		return $sort_prefix . $this->description();
191
+	}
192
+
193
+	/**
194
+	 * Get the certificate's MIME type.
195
+	 *
196
+	 * @return string
197
+	 */
198
+	public function mimeType(): string
199
+	{
200
+		return Mime::TYPES[$this->extension] ?? Mime::DEFAULT_TYPE;
201
+	}
202
+
203
+	/**
204
+	 * Get the base parameters to be used in url referencing the certificate.
205
+	 *
206
+	 * @param UrlObfuscatorService $url_obfuscator_service
207
+	 * @return array{tree: string, cid: mixed}
208
+	 */
209
+	public function urlParameters(UrlObfuscatorService $url_obfuscator_service = null): array
210
+	{
211
+		$url_obfuscator_service = $url_obfuscator_service ?? app(UrlObfuscatorService::class);
212
+		return [
213
+			'tree' => $this->tree->name(),
214
+			'cid' => $url_obfuscator_service->obfuscate($this->path)
215
+		];
216
+	}
217 217
 }
Please login to merge, or discard this patch.
app/Common/Hooks/AbstractHookCollector.php 1 patch
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -27,77 +27,77 @@
 block discarded – undo
27 27
  */
28 28
 abstract class AbstractHookCollector implements HookCollectorInterface, HookInterface
29 29
 {
30
-    /** @var Collection<int, array<THook>> $hooks */
31
-    protected Collection $hooks;
30
+	/** @var Collection<int, array<THook>> $hooks */
31
+	protected Collection $hooks;
32 32
 
33
-    private ModuleInterface $module;
33
+	private ModuleInterface $module;
34 34
 
35
-    /**
36
-     * Constructor for AbstractHookCollector
37
-     *
38
-     * @param ModuleInterface $module
39
-     */
40
-    public function __construct(ModuleInterface $module)
41
-    {
42
-        $this->hooks = new Collection();
43
-        $this->module = $module;
44
-    }
35
+	/**
36
+	 * Constructor for AbstractHookCollector
37
+	 *
38
+	 * @param ModuleInterface $module
39
+	 */
40
+	public function __construct(ModuleInterface $module)
41
+	{
42
+		$this->hooks = new Collection();
43
+		$this->module = $module;
44
+	}
45 45
 
46
-    /**
47
-     * {@inheritDoc}
48
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookInterface::module()
49
-     */
50
-    public function module(): ModuleInterface
51
-    {
52
-        return $this->module;
53
-    }
46
+	/**
47
+	 * {@inheritDoc}
48
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookInterface::module()
49
+	 */
50
+	public function module(): ModuleInterface
51
+	{
52
+		return $this->module;
53
+	}
54 54
 
55
-    /**
56
-     * {@inheritDoc}
57
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::name()
58
-     */
59
-    public function name(): string
60
-    {
61
-        return $this->module->name() . '-' .
62
-            mb_substr(str_replace('collector', '', mb_strtolower((new ReflectionClass($this))->getShortName())), 0, 64);
63
-    }
55
+	/**
56
+	 * {@inheritDoc}
57
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::name()
58
+	 */
59
+	public function name(): string
60
+	{
61
+		return $this->module->name() . '-' .
62
+			mb_substr(str_replace('collector', '', mb_strtolower((new ReflectionClass($this))->getShortName())), 0, 64);
63
+	}
64 64
 
65
-    /**
66
-     * {@inheritDoc}
67
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::title()
68
-     */
69
-    abstract public function title(): string;
65
+	/**
66
+	 * {@inheritDoc}
67
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::title()
68
+	 */
69
+	abstract public function title(): string;
70 70
 
71
-    /**
72
-     * {@inheritDoc}
73
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::description()
74
-     */
75
-    abstract public function description(): string;
71
+	/**
72
+	 * {@inheritDoc}
73
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::description()
74
+	 */
75
+	abstract public function description(): string;
76 76
 
77
-    /**
78
-     * {@inheritDoc}
79
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::hookInterface()
80
-     */
81
-    abstract public function hookInterface(): string;
77
+	/**
78
+	 * {@inheritDoc}
79
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::hookInterface()
80
+	 */
81
+	abstract public function hookInterface(): string;
82 82
 
83
-    /**
84
-     * {@inheritDoc}
85
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::register()
86
-     */
87
-    public function register(HookInterface $hook_instance, int $order): void
88
-    {
89
-        $this->hooks->put($order, array_merge($this->hooks->get($order, []), [$hook_instance]));
90
-    }
83
+	/**
84
+	 * {@inheritDoc}
85
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::register()
86
+	 */
87
+	public function register(HookInterface $hook_instance, int $order): void
88
+	{
89
+		$this->hooks->put($order, array_merge($this->hooks->get($order, []), [$hook_instance]));
90
+	}
91 91
 
92
-    /**
93
-     * {@inheritDoc}
94
-     * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::hooks()
95
-     *
96
-     * @return Collection<THook>
97
-     */
98
-    public function hooks(): Collection
99
-    {
100
-        /** @var Collection<THook> */
101
-        return $this->hooks->sortKeys()->flatten();
102
-    }
92
+	/**
93
+	 * {@inheritDoc}
94
+	 * @see \MyArtJaub\Webtrees\Contracts\Hooks\HookCollectorInterface::hooks()
95
+	 *
96
+	 * @return Collection<THook>
97
+	 */
98
+	public function hooks(): Collection
99
+	{
100
+		/** @var Collection<THook> */
101
+		return $this->hooks->sortKeys()->flatten();
102
+	}
103 103
 }
Please login to merge, or discard this patch.