Passed
Push — master ( 466fee...8256f4 )
by Greg
06:43 queued 01:19
created

ListController   F

Complexity

Total Complexity 78

Size/Duplication

Total Lines 697
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 390
c 2
b 0
f 0
dl 0
loc 697
rs 2.16
wmc 78

17 Methods

Rating   Name   Duplication   Size   Complexity  
A familyList() 0 3 1
A individualList() 0 3 1
A __construct() 0 4 1
A submitterList() 0 11 1
A allFolders() 0 19 1
F individualOrFamilyList() 0 294 52
A allRepositories() 0 8 1
B allMedia() 0 51 6
A repositoryList() 0 11 1
A noteList() 0 11 1
A mediaList() 0 59 3
A givenNameInitial() 0 7 2
A allSubmitters() 0 8 1
A allNotes() 0 8 1
A allSources() 0 7 1
A sourceList() 0 11 1
A surnameInitial() 0 9 3

How to fix   Complexity   

Complex Class

Complex classes like ListController 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 ListController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Http\Controllers;
21
22
use Fisharebest\Webtrees\Functions\FunctionsPrintLists;
23
use Fisharebest\Webtrees\GedcomRecord;
24
use Fisharebest\Webtrees\GedcomTag;
25
use Fisharebest\Webtrees\I18N;
26
use Fisharebest\Webtrees\Media;
27
use Fisharebest\Webtrees\Module\ModuleListInterface;
28
use Fisharebest\Webtrees\Note;
29
use Fisharebest\Webtrees\Repository;
30
use Fisharebest\Webtrees\Services\IndividualListService;
31
use Fisharebest\Webtrees\Services\LocalizationService;
32
use Fisharebest\Webtrees\Session;
33
use Fisharebest\Webtrees\Source;
34
use Fisharebest\Webtrees\Submitter;
35
use Fisharebest\Webtrees\Tree;
36
use Illuminate\Database\Capsule\Manager as DB;
37
use Illuminate\Database\Query\Builder;
38
use Illuminate\Database\Query\JoinClause;
39
use Illuminate\Support\Collection;
40
use League\Flysystem\FilesystemInterface;
41
use Psr\Http\Message\ResponseInterface;
42
use Psr\Http\Message\ServerRequestInterface;
43
44
use function assert;
45
46
/**
47
 * Controller for lists of GEDCOM records.
48
 */
49
class ListController extends AbstractBaseController
50
{
51
    /** @var IndividualListService */
52
    private $individual_list_service;
53
54
    /** @var LocalizationService */
55
    private $localization_service;
56
    
57
            
58
    /**
59
     * ListController constructor.
60
     *
61
     * @param IndividualListService $individual_list_service
62
     * @param LocalizationService   $localization_service
63
     */
64
    public function __construct(IndividualListService $individual_list_service, LocalizationService $localization_service)
65
    {
66
        $this->individual_list_service = $individual_list_service;
67
        $this->localization_service    = $localization_service;
68
    }
69
70
    /**
71
     * Show a list of all individual or family records.
72
     *
73
     * @param ServerRequestInterface   $request
74
     * @param ModuleListInterface|null $moduleListInterface
75
     *
76
     * @return ResponseInterface
77
     */
78
    public function familyList(ServerRequestInterface $request, ?ModuleListInterface $moduleListInterface): ResponseInterface
79
    {
80
        return $this->individualOrFamilyList($request, true, $moduleListInterface);
81
    }
82
83
    /**
84
     * Show a list of all individual or family records.
85
     *
86
     * @param ServerRequestInterface   $request
87
     * @param ModuleListInterface|null $moduleListInterface
88
     *
89
     * @return ResponseInterface
90
     */
91
    public function individualList(ServerRequestInterface $request, ?ModuleListInterface $moduleListInterface): ResponseInterface
92
    {
93
        return $this->individualOrFamilyList($request, false, $moduleListInterface);
94
    }
95
96
    /**
97
     * @param ServerRequestInterface   $request
98
     * @param bool                     $families
99
     * @param ModuleListInterface|null $moduleListInterface
100
     *
101
     * @return ResponseInterface
102
     */
103
    public function individualOrFamilyList(ServerRequestInterface $request, bool $families, ?ModuleListInterface $moduleListInterface): ResponseInterface
104
    {
105
        $tree = $request->getAttribute('tree');
106
        assert($tree instanceof Tree);
107
108
        $user = $request->getAttribute('user');
109
110
        // This action can show lists of both families and individuals.
111
        //route is assumed to be 'module'
112
        $module = $request->getAttribute('module');
113
        $action = $request->getAttribute('action');
114
        
115
        ob_start();
116
117
        // We show three different lists: initials, surnames and individuals
118
119
        // All surnames beginning with this letter where "@"=unknown and ","=none
120
        $alpha = $request->getQueryParams()['alpha'] ?? '';
121
122
        // All individuals with this surname
123
        $surname = $request->getQueryParams()['surname'] ??  '';
124
125
        // All individuals
126
        $show_all = $request->getQueryParams()['show_all'] ?? 'no';
127
128
        // Long lists can be broken down by given name
129
        $show_all_firstnames = $request->getQueryParams()['show_all_firstnames'] ?? 'no';
130
        if ($show_all_firstnames === 'yes') {
131
            $falpha = '';
132
        } else {
133
            // All first names beginning with this letter
134
            $falpha = $request->getQueryParams()['falpha'] ?? '';
135
        }
136
137
        $show_marnm = $request->getQueryParams()['show_marnm'] ?? '';
138
        switch ($show_marnm) {
139
            case 'no':
140
            case 'yes':
141
                $user->setPreference($families ? 'family-list-marnm' : 'individual-list-marnm', $show_marnm);
142
                break;
143
            default:
144
                $show_marnm = $user->getPreference($families ? 'family-list-marnm' : 'individual-list-marnm');
145
        }
146
147
        // Make sure selections are consistent.
148
        // i.e. can’t specify show_all and surname at the same time.
149
        if ($show_all === 'yes') {
150
            if ($show_all_firstnames === 'yes') {
151
                $alpha   = '';
152
                $surname = '';
153
                $legend  = I18N::translate('All');
154
                $params  = [
155
                    'tree'      => $tree->name(),
156
                    'show_all' => 'yes',
157
                ];
158
                $show    = 'indi';
159
            } elseif ($falpha !== '') {
160
                $alpha   = '';
161
                $surname = '';
162
                $legend  = I18N::translate('All') . ', ' . e($falpha) . '…';
163
                $params  = [
164
                    'tree'      => $tree->name(),
165
                    'show_all' => 'yes',
166
                ];
167
                $show    = 'indi';
168
            } else {
169
                $alpha   = '';
170
                $surname = '';
171
                $legend  = I18N::translate('All');
172
                $params  = [
173
                    'tree'      => $tree->name(),
174
                    'show_all' => 'yes',
175
                ];
176
                $show    = $request->getQueryParams()['show'] ?? 'surn';
177
            }
178
        } elseif ($surname !== '') {
179
            $alpha    = $this->localization_service->initialLetter($surname, I18N::locale()); // so we can highlight the initial letter
180
            $show_all = 'no';
181
            if ($surname === '@N.N.') {
182
                $legend = I18N::translateContext('Unknown surname', '…');
183
            } else {
184
                // The surname parameter is a root/canonical form.
185
                // Display it as the actual surname
186
                $legend = implode('/', array_keys($this->individual_list_service->surnames($surname, $alpha, $show_marnm === 'yes', $families, I18N::locale())));
187
            }
188
            $params = [
189
                'tree'     => $tree->name(),
190
                'surname' => $surname,
191
                'falpha'  => $falpha,
192
            ];
193
            switch ($falpha) {
194
                case '':
195
                    break;
196
                case '@':
197
                    $legend .= ', ' . I18N::translateContext('Unknown given name', '…');
198
                    break;
199
                default:
200
                    $legend .= ', ' . e($falpha) . '…';
201
                    break;
202
            }
203
            $show = 'indi'; // SURN list makes no sense here
204
        } elseif ($alpha === '@') {
205
            $show_all = 'no';
206
            $legend   = I18N::translateContext('Unknown surname', '…');
207
            $params   = [
208
                'alpha' => $alpha,
209
                'tree'   => $tree->name(),
210
            ];
211
            $show     = 'indi'; // SURN list makes no sense here
212
        } elseif ($alpha === ',') {
213
            $show_all = 'no';
214
            $legend   = I18N::translate('None');
215
            $params   = [
216
                'alpha' => $alpha,
217
                'tree'   => $tree->name(),
218
            ];
219
            $show     = 'indi'; // SURN list makes no sense here
220
        } elseif ($alpha !== '') {
221
            $show_all = 'no';
222
            $legend   = e($alpha) . '…';
223
            $params   = [
224
                'alpha' => $alpha,
225
                'tree'   => $tree->name(),
226
            ];
227
            $show     = $request->getQueryParams()['show'] ?? 'surn';
228
        } else {
229
            $show_all = 'no';
230
            $legend   = '…';
231
            $params   = [
232
                'tree' => $tree->name(),
233
            ];
234
            $show     = 'none'; // Don't show lists until something is chosen
235
        }
236
        $legend = '<span dir="auto">' . $legend . '</span>';
237
238
        if ($families) {
239
            $title = I18N::translate('Families') . ' — ' . $legend;
240
        } else {
241
            $title = I18N::translate('Individuals') . ' — ' . $legend;
242
        } ?>
243
        <div class="d-flex flex-column wt-page-options wt-page-options-individual-list d-print-none">
244
            <ul class="d-flex flex-wrap list-unstyled justify-content-center wt-initials-list wt-initials-list-surname">
245
246
                <?php foreach ($this->individual_list_service->surnameAlpha($show_marnm === 'yes', $families, I18N::locale()) as $letter => $count) : ?>
247
                    <li class="wt-initials-list-item d-flex">
248
                        <?php if ($count > 0) : ?>
249
                            <a href="<?= e(route('module', ['module' => $module, 'action' => $action, 'alpha' => $letter, 'tree' => $tree->name()])) ?>" class="wt-initial px-1<?= $letter === $alpha ? ' active' : '' ?> '" title="<?= I18N::number($count) ?>"><?= $this->surnameInitial((string) $letter) ?></a>
250
                        <?php else : ?>
251
                            <span class="wt-initial px-1 text-muted"><?= $this->surnameInitial((string) $letter) ?></span>
252
253
                        <?php endif ?>
254
                    </li>
255
                <?php endforeach ?>
256
257
                <?php if (Session::has('initiated')) : ?>
258
                    <!-- Search spiders don't get the "show all" option as the other links give them everything. -->
259
                    <li class="wt-initials-list-item d-flex">
260
                        <a class="wt-initial px-1<?= $show_all === 'yes' ? ' active' : '' ?>" href="<?= e(route('module', ['module' => $module, 'action' => $action, 'show_all' => 'yes'] + $params)) ?>"><?= I18N::translate('All') ?></a>
261
                    </li>
262
                <?php endif ?>
263
            </ul>
264
265
            <!-- Search spiders don't get an option to show/hide the surname sublists, nor does it make sense on the all/unknown/surname views -->
266
            <?php if ($show !== 'none' && Session::has('initiated')) : ?>
267
                <?php if ($show_marnm === 'yes') : ?>
268
                    <p>
269
                        <a href="<?= e(route('module', ['module' => $module, 'action' => $action, 'show' => $show, 'show_marnm' => 'no'] + $params)) ?>">
270
                            <?= I18N::translate('Exclude individuals with “%s” as a married name', $legend) ?>
271
                        </a>
272
                    </p>
273
                <?php else : ?>
274
                    <p>
275
                        <a href="<?= e(route('module', ['module' => $module, 'action' => $action, 'show' => $show, 'show_marnm' => 'yes'] + $params)) ?>">
276
                            <?= I18N::translate('Include individuals with “%s” as a married name', $legend) ?>
277
                        </a>
278
                    </p>
279
                <?php endif ?>
280
281
                <?php if ($alpha !== '@' && $alpha !== ',' && $surname === '') : ?>
282
                    <?php if ($show === 'surn') : ?>
283
                        <p>
284
                            <a href="<?= e(route('module', ['module' => $module, 'action' => $action, 'show' => 'indi', 'show_marnm' => 'no'] + $params)) ?>">
285
                                <?= I18N::translate('Show the list of individuals') ?>
286
                            </a>
287
                        </p>
288
                    <?php else : ?>
289
                        <p>
290
                            <a href="<?= e(route('module', ['module' => $module, 'action' => $action, 'show' => 'surn', 'show_marnm' => 'no'] + $params)) ?>">
291
                                <?= I18N::translate('Show the list of surnames') ?>
292
                            </a>
293
                        </p>
294
                    <?php endif ?>
295
                <?php endif ?>
296
            <?php endif ?>
297
        </div>
298
299
        <div class="wt-page-content">
300
            <?php
301
302
            if ($show === 'indi' || $show === 'surn') {
303
                $surns = $this->individual_list_service->surnames($surname, $alpha, $show_marnm === 'yes', $families, I18N::locale());
304
                if ($show === 'surn') {
305
                    // Show the surname list
306
                    switch ($tree->getPreference('SURNAME_LIST_STYLE')) {
307
                        case 'style1':
308
                            echo FunctionsPrintLists::surnameList($surns, 3, true, $moduleListInterface, $tree);
309
                            break;
310
                        case 'style3':
311
                            echo FunctionsPrintLists::surnameTagCloud($surns, $moduleListInterface, true, $tree);
312
                            break;
313
                        case 'style2':
314
                        default:
315
                            echo view('lists/surnames-table', [
316
                                'surnames' => $surns,
317
                                'families' => $families,
318
                                'module'   => $moduleListInterface,
319
                                'tree'     => $tree,
320
                            ]);
321
                            break;
322
                    }
323
                } else {
324
                    // Show the list
325
                    $count = 0;
326
                    foreach ($surns as $surnames) {
327
                        foreach ($surnames as $total) {
328
                            $count += $total;
329
                        }
330
                    }
331
                    // Don't sublists short lists.
332
                    if ($count < $tree->getPreference('SUBLIST_TRIGGER_I')) {
333
                        $falpha = '';
334
                    } else {
335
                        $givn_initials = $this->individual_list_service->givenAlpha($surname, $alpha, $show_marnm === 'yes', $families, I18N::locale());
336
                        // Break long lists by initial letter of given name
337
                        if ($surname !== '' || $show_all === 'yes') {
338
                            if ($show_all === 'no') {
339
                                echo '<h2 class="wt-page-title">', I18N::translate('Individuals with surname %s', $legend), '</h2>';
340
                            }
341
                            // Don't show the list until we have some filter criteria
342
                            $show = ($falpha !== '' || $show_all_firstnames === 'yes') ? 'indi' : 'none';
343
                            $list = [];
344
                            echo '<ul class="d-flex flex-wrap list-unstyled justify-content-center wt-initials-list wt-initials-list-given-names">';
345
                            foreach ($givn_initials as $givn_initial => $given_count) {
346
                                echo '<li class="wt-initials-list-item d-flex">';
347
                                if ($given_count > 0) {
348
                                    if ($show === 'indi' && $givn_initial === $falpha && $show_all_firstnames === 'no') {
349
                                        echo '<a class="wt-initial px-1 active" href="' . e(route('module', ['module' => $module, 'action' => $action, 'falpha' => $givn_initial] + $params)) . '" title="' . I18N::number($given_count) . '">' . $this->givenNameInitial((string) $givn_initial) . '</a>';
350
                                    } else {
351
                                        echo '<a class="wt-initial px-1" href="' . e(route('module', ['module' => $module, 'action' => $action, 'falpha' => $givn_initial] + $params)) . '" title="' . I18N::number($given_count) . '">' . $this->givenNameInitial((string) $givn_initial) . '</a>';
352
                                    }
353
                                } else {
354
                                    echo '<span class="wt-initial px-1 text-muted">' . $this->givenNameInitial((string) $givn_initial) . '</span>';
355
                                }
356
                                echo '</li>';
357
                            }
358
                            // Search spiders don't get the "show all" option as the other links give them everything.
359
                            if (Session::has('initiated')) {
360
                                echo '<li class="wt-initials-list-item d-flex">';
361
                                if ($show_all_firstnames === 'yes') {
362
                                    echo '<span class="wt-initial px-1 warning">' . I18N::translate('All') . '</span>';
363
                                } else {
364
                                    echo '<a class="wt-initial px-1" href="' . e(route('module', ['module' => $module, 'action' => $action, 'show_all_firstnames' => 'yes'] + $params)) . '" title="' . I18N::number($count) . '">' . I18N::translate('All') . '</a>';
365
                                }
366
                                echo '</li>';
367
                            }
368
                            echo '</ul>';
369
                            echo '<p class="text-center alpha_index">', implode(' | ', $list), '</p>';
370
                        }
371
                    }
372
                    if ($show === 'indi') {
373
                        if (!$families) {
374
                            echo view('lists/individuals-table', [
375
                                'individuals' => $this->individual_list_service->individuals($surname, $alpha, $falpha, $show_marnm === 'yes', false, I18N::locale()),
376
                                'sosa'        => false,
377
                                'tree'        => $tree,
378
                            ]);
379
                        } else {
380
                            echo view('lists/families-table', [
381
                                'families' => $this->individual_list_service->families($surname, $alpha, $falpha, $show_marnm === 'yes', I18N::locale()),
382
                                'tree'     => $tree,
383
                            ]);
384
                        }
385
                    }
386
                }
387
            } ?>
388
        </div>
389
        <?php
390
391
        $html = ob_get_clean();
392
393
        return $this->viewResponse('modules/individual-list/page', [
394
            'content' => $html,
395
            'title'   => $title,
396
            'tree'    => $tree,
397
        ]);
398
    }
399
400
    /**
401
     * Show a list of all media records.
402
     *
403
     * @param ServerRequestInterface $request
404
     *
405
     * @return ResponseInterface
406
     */
407
    public function mediaList(ServerRequestInterface $request): ResponseInterface
408
    {
409
        $tree = $request->getAttribute('tree');
410
        assert($tree instanceof Tree);
411
412
        $data_filesystem = $request->getAttribute('filesystem.data');
413
        assert($data_filesystem instanceof FilesystemInterface);
414
415
        $module    = $request->getAttribute('module');
416
        $action    = $request->getAttribute('action');
417
        $params    = $request->getQueryParams();
418
        $formats   = GedcomTag::getFileFormTypes();
419
        $action2   = $params['action2'] ?? '';
420
        $page      = (int) ($params['page'] ?? 1);
421
        $max       = (int) ($params['max'] ?? 20);
422
        $folder    = $params['folder'] ?? '';
423
        $filter    = $params['filter'] ?? '';
424
        $subdirs   = $params['subdirs'] ?? '';
425
        $form_type = $params['form_type'] ?? '';
426
427
        $folders = $this->allFolders($tree);
428
429
        if ($action2 === '1') {
430
            $media_objects = $this->allMedia(
431
                $tree,
432
                $folder,
433
                $subdirs === '1' ? 'include' : 'exclude',
434
                'title',
435
                $filter,
436
                $form_type
437
            );
438
        } else {
439
            $media_objects = [];
440
        }
441
442
        // Pagination
443
        $count = count($media_objects);
444
        $pages = (int) (($count + $max - 1) / $max);
445
        $page  = max(min($page, $pages), 1);
446
447
        $media_objects = array_slice($media_objects, ($page - 1) * $max, $max);
448
449
        return $this->viewResponse('modules/media-list/page', [
450
            'count'           => $count,
451
            'filter'          => $filter,
452
            'folder'          => $folder,
453
            'folders'         => $folders,
454
            'formats'         => $formats,
455
            'form_type'       => $form_type,
456
            'max'             => $max,
457
            'media_objects'   => new Collection($media_objects),
458
            'page'            => $page,
459
            'pages'           => $pages,
460
            'subdirs'         => $subdirs,
461
            'title'           => I18N::translate('Media'),
462
            'tree'            => $tree,
463
            'module'          => $module,
464
            'action'          => $action,
465
            'data_filesystem' => $data_filesystem,
466
        ]);
467
    }
468
469
    /**
470
     * Show a list of all note records.
471
     *
472
     * @param ServerRequestInterface $request
473
     *
474
     * @return ResponseInterface
475
     */
476
    public function noteList(ServerRequestInterface $request): ResponseInterface
477
    {
478
        $tree = $request->getAttribute('tree');
479
        assert($tree instanceof Tree);
480
481
        $notes = $this->allNotes($tree);
482
483
        return $this->viewResponse('modules/note-list/page', [
484
            'notes' => $notes,
485
            'title' => I18N::translate('Shared notes'),
486
            'tree'  => $tree,
487
        ]);
488
    }
489
490
    /**
491
     * Show a list of all repository records.
492
     *
493
     * @param ServerRequestInterface $request
494
     *
495
     * @return ResponseInterface
496
     */
497
    public function repositoryList(ServerRequestInterface $request): ResponseInterface
498
    {
499
        $tree = $request->getAttribute('tree');
500
        assert($tree instanceof Tree);
501
502
        $repositories = $this->allRepositories($tree);
503
504
        return $this->viewResponse('modules/repository-list/page', [
505
            'repositories' => $repositories,
506
            'title'        => I18N::translate('Repositories'),
507
            'tree'         => $tree,
508
        ]);
509
    }
510
511
    /**
512
     * Show a list of all source records.
513
     *
514
     * @param ServerRequestInterface $request
515
     *
516
     * @return ResponseInterface
517
     */
518
    public function sourceList(ServerRequestInterface $request): ResponseInterface
519
    {
520
        $tree = $request->getAttribute('tree');
521
        assert($tree instanceof Tree);
522
523
        $sources = $this->allSources($tree);
524
525
        return $this->viewResponse('modules/source-list/page', [
526
            'sources' => $sources,
527
            'title'   => I18N::translate('Sources'),
528
            'tree'    => $tree,
529
        ]);
530
    }
531
532
    /**
533
     * Show a list of all submitter records.
534
     *
535
     * @param ServerRequestInterface $request
536
     *
537
     * @return ResponseInterface
538
     */
539
    public function submitterList(ServerRequestInterface $request): ResponseInterface
540
    {
541
        $tree = $request->getAttribute('tree');
542
        assert($tree instanceof Tree);
543
544
        $submitters = $this->allSubmitters($tree);
545
546
        return $this->viewResponse('modules/submitter-list/page', [
547
            'submitters'   => $submitters,
548
            'title'        => I18N::translate('Submitters'),
549
            'tree'         => $tree,
550
        ]);
551
    }
552
553
    /**
554
     * Generate a list of all the folders in a current tree.
555
     *
556
     * @param Tree $tree
557
     *
558
     * @return string[]
559
     */
560
    private function allFolders(Tree $tree): array
561
    {
562
        $folders = DB::table('media_file')
563
            ->where('m_file', '=', $tree->id())
564
            ->where('multimedia_file_refn', 'NOT LIKE', 'http:%')
565
            ->where('multimedia_file_refn', 'NOT LIKE', 'https:%')
566
            ->where('multimedia_file_refn', 'LIKE', '%/%')
567
            ->pluck('multimedia_file_refn', 'multimedia_file_refn')
568
            ->map(static function (string $path): string {
569
                return dirname($path);
570
            })
571
            ->unique()
572
            ->sort()
573
            ->all();
574
575
        // Ensure we have an empty (top level) folder.
576
        array_unshift($folders, '');
577
578
        return array_combine($folders, $folders);
579
    }
580
581
    /**
582
     * Generate a list of all the media objects matching the criteria in a current tree.
583
     *
584
     * @param Tree   $tree       find media in this tree
585
     * @param string $folder     folder to search
586
     * @param string $subfolders either "include" or "exclude"
587
     * @param string $sort       either "file" or "title"
588
     * @param string $filter     optional search string
589
     * @param string $form_type  option OBJE/FILE/FORM/TYPE
590
     *
591
     * @return Media[]
592
     */
593
    private function allMedia(Tree $tree, string $folder, string $subfolders, string $sort, string $filter, string $form_type): array
594
    {
595
        $query = DB::table('media')
596
            ->join('media_file', static function (JoinClause $join): void {
597
                $join
598
                    ->on('media_file.m_file', '=', 'media.m_file')
599
                    ->on('media_file.m_id', '=', 'media.m_id');
600
            })
601
            ->where('media.m_file', '=', $tree->id())
602
            ->distinct();
603
604
        // Match all external files, and whatever folders were specified
605
        $query->where(static function (Builder $query) use ($folder, $subfolders): void {
606
            $query
607
                ->where('multimedia_file_refn', 'LIKE', 'http:%')
608
                ->orWhere('multimedia_file_refn', 'LIKE', 'https:%')
609
                ->orWhere(static function (Builder $query) use ($folder, $subfolders): void {
610
                    $query->where('multimedia_file_refn', 'LIKE', $folder . '%');
611
                    if ($subfolders === 'exclude') {
612
                        $query->where('multimedia_file_refn', 'NOT LIKE', $folder . '/%/%');
613
                    }
614
                });
615
        });
616
617
        // Apply search terms
618
        if ($filter !== '') {
619
            $query->where(static function (Builder $query) use ($filter): void {
620
                $query
621
                    ->whereContains('multimedia_file_refn', $filter)
622
                    ->whereContains('descriptive_title', $filter, 'or');
623
            });
624
        }
625
626
        if ($form_type) {
627
            $query->where('source_media_type', '=', $form_type);
628
        }
629
630
        switch ($sort) {
631
            case 'file':
632
                $query->orderBy('multimedia_file_refn');
633
                break;
634
            case 'title':
635
                $query->orderBy('descriptive_title');
636
                break;
637
        }
638
639
        return $query
640
            ->get()
641
            ->map(Media::rowMapper($tree))
642
            ->filter(GedcomRecord::accessFilter())
643
            ->all();
644
    }
645
646
    /**
647
     * Find all the note records in a tree.
648
     *
649
     * @param Tree $tree
650
     *
651
     * @return Collection<Note>
652
     */
653
    private function allNotes(Tree $tree): Collection
654
    {
655
        return DB::table('other')
656
            ->where('o_file', '=', $tree->id())
657
            ->where('o_type', '=', Note::RECORD_TYPE)
658
            ->get()
659
            ->map(Note::rowMapper($tree))
660
            ->filter(GedcomRecord::accessFilter());
661
    }
662
663
    /**
664
     * Find all the repository record in a tree.
665
     *
666
     * @param Tree $tree
667
     *
668
     * @return Collection<Repository>
669
     */
670
    private function allRepositories(Tree $tree): Collection
671
    {
672
        return DB::table('other')
673
            ->where('o_file', '=', $tree->id())
674
            ->where('o_type', '=', Repository::RECORD_TYPE)
675
            ->get()
676
            ->map(Repository::rowMapper($tree))
677
            ->filter(GedcomRecord::accessFilter());
678
    }
679
680
    /**
681
     * Find all the source records in a tree.
682
     *
683
     * @param Tree $tree
684
     *
685
     * @return Collection<Source>
686
     */
687
    private function allSources(Tree $tree): Collection
688
    {
689
        return DB::table('sources')
690
            ->where('s_file', '=', $tree->id())
691
            ->get()
692
            ->map(Source::rowMapper($tree))
693
            ->filter(GedcomRecord::accessFilter());
694
    }
695
696
    /**
697
     * Find all the submitter record in a tree.
698
     *
699
     * @param Tree $tree
700
     *
701
     * @return Collection<Submitter>
702
     */
703
    private function allSubmitters(Tree $tree): Collection
704
    {
705
        return DB::table('other')
706
            ->where('o_file', '=', $tree->id())
707
            ->where('o_type', '=', Submitter::RECORD_TYPE)
708
            ->get()
709
            ->map(Submitter::rowMapper($tree))
710
            ->filter(GedcomRecord::accessFilter());
711
    }
712
713
    /**
714
     * Some initial letters have a special meaning
715
     *
716
     * @param string $initial
717
     *
718
     * @return string
719
     */
720
    private function givenNameInitial(string $initial): string
721
    {
722
        switch ($initial) {
723
            case '@':
724
                return I18N::translateContext('Unknown given name', '…');
725
            default:
726
                return e($initial);
727
        }
728
    }
729
730
    /**
731
     * Some initial letters have a special meaning
732
     *
733
     * @param string $initial
734
     *
735
     * @return string
736
     */
737
    private function surnameInitial(string $initial): string
738
    {
739
        switch ($initial) {
740
            case '@':
741
                return I18N::translateContext('Unknown surname', '…');
742
            case ',':
743
                return I18N::translate('None');
744
            default:
745
                return e($initial);
746
        }
747
    }
748
}
749