| Total Complexity | 63 |
| Total Lines | 380 |
| Duplicated Lines | 0 % |
| Changes | 4 | ||
| Bugs | 0 | Features | 0 |
Complex classes like FunctionsPrintFacts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use FunctionsPrintFacts, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 49 | class FunctionsPrintFacts |
||
| 50 | { |
||
| 51 | /** |
||
| 52 | * print a source linked to a fact (2 SOUR) |
||
| 53 | * this function is called by the FunctionsPrintFacts::print_fact function and other functions to |
||
| 54 | * print any source information attached to the fact |
||
| 55 | * |
||
| 56 | * @param Tree $tree |
||
| 57 | * @param string $factrec The fact record to look for sources in |
||
| 58 | * @param int $level The level to look for sources at |
||
| 59 | * |
||
| 60 | * @return string HTML text |
||
| 61 | */ |
||
| 62 | public static function printFactSources(Tree $tree, string $factrec, int $level): string |
||
| 139 | } |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Print the links to media objects |
||
| 143 | * |
||
| 144 | * @param Tree $tree |
||
| 145 | * @param string $factrec |
||
| 146 | * @param int $level |
||
| 147 | * |
||
| 148 | * @return void |
||
| 149 | */ |
||
| 150 | public static function printMediaLinks(Tree $tree, string $factrec, int $level): void |
||
| 151 | { |
||
| 152 | $nlevel = $level + 1; |
||
|
|
|||
| 153 | if (preg_match_all("/$level OBJE @(.*)@/", $factrec, $omatch, PREG_SET_ORDER) === 0) { |
||
| 154 | return; |
||
| 155 | } |
||
| 156 | $objectNum = 0; |
||
| 157 | while ($objectNum < count($omatch)) { |
||
| 158 | $media_id = $omatch[$objectNum][1]; |
||
| 159 | $media = Registry::mediaFactory()->make($media_id, $tree); |
||
| 160 | if ($media) { |
||
| 161 | if ($media->canShow()) { |
||
| 162 | echo '<div class="d-flex align-items-center"><div class="p-1">'; |
||
| 163 | foreach ($media->mediaFiles() as $media_file) { |
||
| 164 | echo $media_file->displayImage(100, 100, 'contain', []); |
||
| 165 | } |
||
| 166 | echo '</div>'; |
||
| 167 | echo '<div>'; |
||
| 168 | echo '<a href="', e($media->url()), '">', $media->fullName(), '</a>'; |
||
| 169 | echo '<p>'; |
||
| 170 | |||
| 171 | foreach ($media->facts(['SOUR']) as $fact) { |
||
| 172 | echo view('fact-gedcom-fields', ['gedcom' => $fact->gedcom(), 'hierarchy' => [$media->tag()], 'tree' => $tree]); |
||
| 173 | } |
||
| 174 | |||
| 175 | foreach ($media->facts(['NOTE']) as $fact) { |
||
| 176 | echo view('fact-gedcom-fields', ['gedcom' => $fact->gedcom(), 'hierarchy' => [$media->tag()], 'tree' => $tree]); |
||
| 177 | } |
||
| 178 | |||
| 179 | echo '</div>'; //close div "media-display-title" |
||
| 180 | echo '</div>'; //close div "media-display" |
||
| 181 | } |
||
| 182 | } elseif ($tree->getPreference('HIDE_GEDCOM_ERRORS') === '1') { |
||
| 183 | echo '<p class="alert alert-danger">', $media_id, '</p>'; |
||
| 184 | } |
||
| 185 | $objectNum++; |
||
| 186 | } |
||
| 187 | } |
||
| 188 | |||
| 189 | /** |
||
| 190 | * Print a row for the sources tab on the individual page. |
||
| 191 | * |
||
| 192 | * @param Fact $fact |
||
| 193 | * @param int $level |
||
| 194 | * |
||
| 195 | * @return void |
||
| 196 | */ |
||
| 197 | public static function printMainSources(Fact $fact, int $level): void |
||
| 198 | { |
||
| 199 | $factrec = $fact->gedcom(); |
||
| 200 | $tree = $fact->record()->tree(); |
||
| 201 | |||
| 202 | $nlevel = $level + 1; |
||
| 203 | if ($fact->isPendingAddition()) { |
||
| 204 | $styleadd = 'wt-new'; |
||
| 205 | $can_edit = $level === 1 && $fact->canEdit(); |
||
| 206 | } elseif ($fact->isPendingDeletion()) { |
||
| 207 | $styleadd = 'wt-old'; |
||
| 208 | $can_edit = false; |
||
| 209 | } else { |
||
| 210 | $styleadd = ''; |
||
| 211 | $can_edit = $level === 1 && $fact->canEdit(); |
||
| 212 | } |
||
| 213 | |||
| 214 | // -- find source for each fact |
||
| 215 | preg_match_all('/(?:^|\n)(' . $level . ' SOUR (.*)(?:\n[' . $nlevel . '-9] .*)*)/', $fact->gedcom(), $matches, PREG_SET_ORDER); |
||
| 216 | |||
| 217 | foreach ($matches as $match) { |
||
| 218 | $srec = $match[1]; |
||
| 219 | $sid = $match[2]; |
||
| 220 | $source = Registry::sourceFactory()->make(trim($sid, '@'), $tree); |
||
| 221 | // Allow access to "1 SOUR @non_existent_source@", so it can be corrected/deleted |
||
| 222 | if (!$source || $source->canShow()) { |
||
| 223 | if ($level > 1) { |
||
| 224 | echo '<tr class="wt-level-two-source collapse">'; |
||
| 225 | } else { |
||
| 226 | echo '<tr>'; |
||
| 227 | } |
||
| 228 | echo '<th class="'; |
||
| 229 | if ($level > 1) { |
||
| 230 | echo 'rela '; |
||
| 231 | } |
||
| 232 | echo $styleadd, '">'; |
||
| 233 | echo $fact->label(); |
||
| 234 | if ($can_edit) { |
||
| 235 | echo view('fact-edit-links', ['fact' => $fact, 'url' => null]); |
||
| 236 | } |
||
| 237 | echo '</th>'; |
||
| 238 | echo '<td class="', $styleadd, '">'; |
||
| 239 | if ($source) { |
||
| 240 | echo '<a href="', e($source->url()), '">', $source->fullName(), '</a>'; |
||
| 241 | // 2 RESN tags. Note, there can be more than one, such as "privacy" and "locked" |
||
| 242 | if (preg_match_all("/\n2 RESN (.+)/", $factrec, $rmatches)) { |
||
| 243 | $label = Registry::elementFactory()->make($fact->tag() . ':RESN')->label(); |
||
| 244 | foreach ($rmatches[1] as $rmatch) { |
||
| 245 | echo '<br><span class="label">', $label, ':</span> <span class="field">'; |
||
| 246 | switch ($rmatch) { |
||
| 247 | case 'none': |
||
| 248 | // Note: "2 RESN none" is not valid gedcom, and the GUI will not let you add it. |
||
| 249 | // However, webtrees privacy rules will interpret it as "show an otherwise private fact to public". |
||
| 250 | echo '<i class="icon-resn-none"></i> ', I18N::translate('Show to visitors'); |
||
| 251 | break; |
||
| 252 | case 'privacy': |
||
| 253 | echo '<i class="icon-resn-privacy"></i> ', I18N::translate('Show to members'); |
||
| 254 | break; |
||
| 255 | case 'confidential': |
||
| 256 | echo '<i class="icon-resn-confidential"></i> ', I18N::translate('Show to managers'); |
||
| 257 | break; |
||
| 258 | case 'locked': |
||
| 259 | echo '<i class="icon-resn-locked"></i> ', I18N::translate('Only managers can edit'); |
||
| 260 | break; |
||
| 261 | default: |
||
| 262 | echo $rmatch; |
||
| 263 | break; |
||
| 264 | } |
||
| 265 | echo '</span>'; |
||
| 266 | } |
||
| 267 | } |
||
| 268 | echo self::printSourceStructure($tree, self::getSourceStructure($srec)); |
||
| 269 | echo '<div class="indent">'; |
||
| 270 | self::printMediaLinks($tree, $srec, $nlevel); |
||
| 271 | if ($nlevel === 2) { |
||
| 272 | self::printMediaLinks($tree, $source->gedcom(), 1); |
||
| 273 | } |
||
| 274 | echo FunctionsPrint::printFactNotes($tree, $srec, $nlevel); |
||
| 275 | echo '</div>'; |
||
| 276 | } else { |
||
| 277 | echo $sid; |
||
| 278 | } |
||
| 279 | echo '</td></tr>'; |
||
| 280 | } |
||
| 281 | } |
||
| 282 | } |
||
| 283 | |||
| 284 | /** |
||
| 285 | * Print SOUR structure |
||
| 286 | * This function prints the input array of SOUR sub-records built by the |
||
| 287 | * getSourceStructure() function. |
||
| 288 | * |
||
| 289 | * @param Tree $tree |
||
| 290 | * @param array<string|array<string>> $textSOUR |
||
| 291 | * |
||
| 292 | * @return string |
||
| 293 | */ |
||
| 294 | public static function printSourceStructure(Tree $tree, array $textSOUR): string |
||
| 295 | { |
||
| 296 | $html = ''; |
||
| 297 | |||
| 298 | if ($textSOUR['PAGE'] !== '') { |
||
| 299 | $html .= Registry::elementFactory()->make('INDI:SOUR:PAGE')->labelValue($textSOUR['PAGE'], $tree); |
||
| 300 | } |
||
| 301 | |||
| 302 | if ($textSOUR['EVEN'] !== '') { |
||
| 303 | $html .= Registry::elementFactory()->make('INDI:SOUR:EVEN')->labelValue($textSOUR['EVEN'], $tree); |
||
| 304 | |||
| 305 | if ($textSOUR['ROLE']) { |
||
| 306 | $html .= Registry::elementFactory()->make('INDI:SOUR:EVEN:ROLE')->labelValue($textSOUR['ROLE'], $tree); |
||
| 307 | } |
||
| 308 | } |
||
| 309 | |||
| 310 | if ($textSOUR['DATE'] !== '') { |
||
| 311 | $html .= Registry::elementFactory()->make('INDI:SOUR:DATA:DATE')->labelValue($textSOUR['DATE'], $tree); |
||
| 312 | } |
||
| 313 | |||
| 314 | foreach ($textSOUR['TEXT'] as $text) { |
||
| 315 | $html .= Registry::elementFactory()->make('INDI:SOUR:DATA:TEXT')->labelValue($text, $tree); |
||
| 316 | } |
||
| 317 | |||
| 318 | if ($textSOUR['QUAY'] !== '') { |
||
| 319 | $html .= Registry::elementFactory()->make('INDI:SOUR:QUAY')->labelValue($textSOUR['QUAY'], $tree); |
||
| 320 | } |
||
| 321 | |||
| 322 | return '<div class="indent">' . $html . '</div>'; |
||
| 323 | } |
||
| 324 | |||
| 325 | /** |
||
| 326 | * Extract SOUR structure from the incoming Source sub-record |
||
| 327 | * The output array is defined as follows: |
||
| 328 | * $textSOUR['PAGE'] = Source citation |
||
| 329 | * $textSOUR['EVEN'] = Event type |
||
| 330 | * $textSOUR['ROLE'] = Role in event |
||
| 331 | * $textSOUR['DATA'] = place holder (no text in this sub-record) |
||
| 332 | * $textSOUR['DATE'] = Entry recording date |
||
| 333 | * $textSOUR['TEXT'] = (array) Text from source |
||
| 334 | * $textSOUR['QUAY'] = Certainty assessment |
||
| 335 | * |
||
| 336 | * @param string $srec |
||
| 337 | * |
||
| 338 | * @return array<array<string>> |
||
| 339 | */ |
||
| 340 | public static function getSourceStructure(string $srec): array |
||
| 341 | { |
||
| 342 | // Set up the output array |
||
| 343 | $textSOUR = [ |
||
| 344 | 'PAGE' => '', |
||
| 345 | 'EVEN' => '', |
||
| 346 | 'ROLE' => '', |
||
| 347 | 'DATE' => '', |
||
| 348 | 'TEXT' => [], |
||
| 349 | 'QUAY' => '', |
||
| 350 | ]; |
||
| 351 | |||
| 352 | preg_match_all('/^\d (PAGE|EVEN|ROLE|DATE|TEXT|QUAY) ?(.*(\n\d CONT.*)*)$/m', $srec, $matches, PREG_SET_ORDER); |
||
| 353 | |||
| 354 | foreach ($matches as $match) { |
||
| 355 | $tag = $match[1]; |
||
| 356 | $value = $match[2]; |
||
| 357 | $value = preg_replace('/\n\d CONT ?/', "\n", $value); |
||
| 358 | |||
| 359 | if ($tag === 'TEXT') { |
||
| 360 | $textSOUR[$tag][] = $value; |
||
| 361 | } else { |
||
| 362 | $textSOUR[$tag] = $value; |
||
| 363 | } |
||
| 364 | } |
||
| 365 | |||
| 366 | return $textSOUR; |
||
| 367 | } |
||
| 368 | |||
| 369 | /** |
||
| 370 | * Print a row for the media tab on the individual page. |
||
| 371 | * |
||
| 372 | * @param Fact $fact |
||
| 373 | * @param int $level |
||
| 374 | * |
||
| 375 | * @return void |
||
| 376 | */ |
||
| 377 | public static function printMainMedia(Fact $fact, int $level): void |
||
| 429 | } |
||
| 430 | } |
||
| 431 | } |
||
| 432 | } |
||
| 433 |