1<?php 2 3declare(strict_types=1); 4 5use Fisharebest\Webtrees\I18N; 6use Fisharebest\Webtrees\Registry; 7use Fisharebest\Webtrees\Source; 8use Fisharebest\Webtrees\Tree; 9use Illuminate\Database\Capsule\Manager as DB; 10use Illuminate\Database\Query\Expression; 11use Illuminate\Database\Query\JoinClause; 12use Illuminate\Support\Collection; 13 14/** 15 * @var Collection<int,Source> $sources 16 * @var Tree $tree 17 */ 18 19?> 20 21<?php 22// Count the number of linked records. These numbers include private records. 23// It is not good to bypass privacy, but many servers do not have the resources 24// to process privacy for every record in the tree 25$count_individuals = DB::table('individuals') 26 ->join('link', static function (JoinClause $join): void { 27 $join->on('l_from', '=', 'i_id'); 28 $join->on('l_file', '=', 'i_file'); 29 }) 30 ->where('l_type', '=', 'SOUR') 31 ->where('l_file', '=', $tree->id()) 32 ->groupBy(['l_to']) 33 ->pluck(new Expression('COUNT(*) AS total'), 'l_to') 34 ->map(static fn ($n) => (int) $n) 35 ->all(); 36 37$count_families = DB::table('families') 38 ->join('link', static function (JoinClause $join): void { 39 $join->on('l_from', '=', 'f_id'); 40 $join->on('l_file', '=', 'f_file'); 41 }) 42 ->where('l_type', '=', 'SOUR') 43 ->where('l_file', '=', $tree->id()) 44 ->groupBy(['l_to']) 45 ->pluck(new Expression('COUNT(*) AS total'), 'l_to') 46 ->map(static fn ($n) => (int) $n) 47 ->all(); 48 49$count_media = DB::table('media') 50 ->join('link', static function (JoinClause $join): void { 51 $join->on('l_from', '=', 'm_id'); 52 $join->on('l_file', '=', 'm_file'); 53 }) 54 ->where('l_type', '=', 'SOUR') 55 ->where('l_file', '=', $tree->id()) 56 ->groupBy(['l_to']) 57 ->pluck(new Expression('COUNT(*) AS total'), 'l_to') 58 ->map(static fn ($n) => (int) $n) 59 ->all(); 60 61$count_notes = DB::table('other') 62 ->join('link', static function (JoinClause $join): void { 63 $join->on('l_from', '=', 'o_id'); 64 $join->on('l_file', '=', 'o_file'); 65 }) 66 ->where('o_type', '=', 'NOTE') 67 ->where('l_type', '=', 'SOUR') 68 ->where('l_file', '=', $tree->id()) 69 ->groupBy(['l_to']) 70 ->pluck(new Expression('COUNT(*) AS total'), 'l_to') 71 ->map(static fn ($n) => (int) $n) 72 ->all(); 73?> 74 75<table 76 class="table table-bordered table-sm wt-table-source datatables d-none" 77 <?= view('lists/datatables-attributes') ?> 78 data-columns="<?= e(json_encode([ 79 ['type' => 'html'], 80 null, 81 null, 82 null, 83 ['visible' => array_sum($count_individuals) > 0], 84 ['visible' => array_sum($count_families) > 0], 85 ['visible' => array_sum($count_media) > 0], 86 ['visible' => array_sum($count_notes) > 0], 87 ['visible' => (bool) $tree->getPreference('SHOW_LAST_CHANGE'), 'searchable' => false], 88 ], JSON_THROW_ON_ERROR)) ?>" 89> 90 <caption class="visually-hidden"> 91 <?= $caption ?? I18N::translate('Sources') ?> 92 </caption> 93 94 <thead> 95 <tr> 96 <th><?= I18N::translate('Title') ?></th> 97 <th class="d-none d-md-table-cell"><?= I18N::translate('Abbreviation') ?></th> 98 <th class="d-none d-md-table-cell"><?= I18N::translate('Author') ?></th> 99 <th class="d-none d-md-table-cell"><?= I18N::translate('Publication') ?></th> 100 <th><?= I18N::translate('Individuals') ?></th> 101 <th><?= I18N::translate('Families') ?></th> 102 <th><?= I18N::translate('Media objects') ?></th> 103 <th><?= I18N::translate('Shared notes') ?></th> 104 <th><?= I18N::translate('Last change') ?></th> 105 </tr> 106 </thead> 107 108 <tbody> 109 <?php foreach ($sources as $source) : ?> 110 <tr class="<?= $source->isPendingAddition() ? 'wt-new' : '' ?> <?= $source->isPendingDeletion() ? 'wt-old' : '' ?>"> 111 <!-- Title --> 112 <td data-sort="<?= e($source->sortName()) ?>"> 113 <a href="<?= e($source->url()) ?>"> 114 <?= $source->fullName() ?> 115 </a> 116 </td> 117 118 <!-- Abbreviation --> 119 <td class="d-none d-md-table-cell"> 120 <?= e($source->facts(['ABBR'])->isNotEmpty() ? $source->facts(['ABBR'])->first()->value() : '') ?> 121 </td> 122 123 <!-- Author --> 124 <td class="d-none d-md-table-cell"> 125 <?= e($source->facts(['AUTH'])->isNotEmpty() ? $source->facts(['AUTH'])->first()->value() : '') ?> 126 </td> 127 128 <!-- Publisher --> 129 <td class="d-none d-md-table-cell"> 130 <?= Registry::elementFactory()->make('SOUR:PUBL')->value($source->facts(['PUBL'])->isNotEmpty() ? $source->facts(['PUBL'])->first()->value() : '', $tree) ?> 131 </td> 132 133 <!-- Count of linked individuals --> 134 <td class="text-center" data-sort="<?= $count_individuals[$source->xref()] ?? 0 ?>"> 135 <?= I18N::number($count_individuals[$source->xref()] ?? 0) ?> 136 </td> 137 138 <!-- Count of linked families --> 139 <td class="text-center" data-sort="<?= $count_families[$source->xref()] ?? 0 ?>"> 140 <?= I18N::number($count_families[$source->xref()] ?? 0) ?> 141 </td> 142 143 <!-- Count of linked media objects --> 144 <td class="text-center" data-sort="<?= $count_media[$source->xref()] ?? 0 ?>"> 145 <?= I18N::number($count_media[$source->xref()] ?? 0) ?> 146 </td> 147 148 <!-- Count of linked notes --> 149 <td class="text-center" data-sort="<?= $count_notes[$source->xref()] ?? 0 ?>"> 150 <?= I18N::number($count_notes[$source->xref()] ?? 0) ?> 151 </td> 152 153 <!-- Last change --> 154 <td data-sort="<?= $source->lastChangeTimestamp()->timestamp() ?>"> 155 <?= view('components/datetime', ['timestamp' => $source->lastChangeTimestamp()]) ?> 156 </td> 157 </tr> 158 <?php endforeach ?> 159 </tbody> 160</table> 161