xref: /webtrees/app/Http/RequestHandlers/ControlPanel.php (revision 5bfc689774bb9a6401271c4ed15a6d50652c991b)
10c0910bfSGreg Roach<?php
20c0910bfSGreg Roach
30c0910bfSGreg Roach/**
40c0910bfSGreg Roach * webtrees: online genealogy
5*5bfc6897SGreg Roach * Copyright (C) 2022 webtrees development team
60c0910bfSGreg Roach * This program is free software: you can redistribute it and/or modify
70c0910bfSGreg Roach * it under the terms of the GNU General Public License as published by
80c0910bfSGreg Roach * the Free Software Foundation, either version 3 of the License, or
90c0910bfSGreg Roach * (at your option) any later version.
100c0910bfSGreg Roach * This program is distributed in the hope that it will be useful,
110c0910bfSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
120c0910bfSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
130c0910bfSGreg Roach * GNU General Public License for more details.
140c0910bfSGreg Roach * You should have received a copy of the GNU General Public License
1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>.
160c0910bfSGreg Roach */
17fcfa147eSGreg Roach
180c0910bfSGreg Roachdeclare(strict_types=1);
190c0910bfSGreg Roach
200c0910bfSGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers;
210c0910bfSGreg Roach
220c0910bfSGreg Roachuse Fisharebest\Webtrees\Http\ViewResponseTrait;
230c0910bfSGreg Roachuse Fisharebest\Webtrees\I18N;
240c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\FamilyListModule;
250c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\IndividualListModule;
260c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\MediaListModule;
270c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleAnalyticsInterface;
280c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleBlockInterface;
290c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleChartInterface;
3064d12f7bSGreg Roachuse Fisharebest\Webtrees\Module\ModuleCustomInterface;
314da96842SGreg Roachuse Fisharebest\Webtrees\Module\ModuleCustomTagsInterface;
32ce42304aSGreg Roachuse Fisharebest\Webtrees\Module\ModuleDataFixInterface;
330c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleFooterInterface;
340c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleHistoricEventsInterface;
350c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleLanguageInterface;
360c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleListInterface;
37c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Module\ModuleMapAutocompleteInterface;
38c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Module\ModuleMapGeoLocationInterface;
39e3544cb2SGreg Roachuse Fisharebest\Webtrees\Module\ModuleMapLinkInterface;
40c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Module\ModuleMapProviderInterface;
410c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleMenuInterface;
420c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleReportInterface;
438a1a28d7SGreg Roachuse Fisharebest\Webtrees\Module\ModuleShareInterface;
440c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleSidebarInterface;
450c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleTabInterface;
460c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleThemeInterface;
470c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\NoteListModule;
480c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\RepositoryListModule;
490c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\SourceListModule;
50e72c24d6SGreg Roachuse Fisharebest\Webtrees\Module\SubmitterListModule;
51e72c24d6SGreg Roachuse Fisharebest\Webtrees\Note;
526b9cb339SGreg Roachuse Fisharebest\Webtrees\Registry;
53e72c24d6SGreg Roachuse Fisharebest\Webtrees\Repository;
546fd01894SGreg Roachuse Fisharebest\Webtrees\Services\AdminService;
550c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\HousekeepingService;
56a46dd5a6SGreg Roachuse Fisharebest\Webtrees\Services\MessageService;
570c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService;
580c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\ServerCheckService;
590c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\TreeService;
600c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\UpgradeService;
610c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\UserService;
62e72c24d6SGreg Roachuse Fisharebest\Webtrees\Submitter;
630c0910bfSGreg Roachuse Fisharebest\Webtrees\Webtrees;
640c0910bfSGreg Roachuse Illuminate\Database\Capsule\Manager as DB;
650c0910bfSGreg Roachuse Illuminate\Database\Query\Expression;
660c0910bfSGreg Roachuse Illuminate\Database\Query\JoinClause;
670c0910bfSGreg Roachuse Illuminate\Support\Collection;
680c0910bfSGreg Roachuse League\Flysystem\Filesystem;
69f7cf8a15SGreg Roachuse League\Flysystem\Local\LocalFilesystemAdapter;
700c0910bfSGreg Roachuse Psr\Http\Message\ResponseInterface;
710c0910bfSGreg Roachuse Psr\Http\Message\ServerRequestInterface;
720c0910bfSGreg Roachuse Psr\Http\Server\RequestHandlerInterface;
730c0910bfSGreg Roach
740c0910bfSGreg Roach/**
750c0910bfSGreg Roach * The control panel shows a summary of the site and links to admin functions.
760c0910bfSGreg Roach */
770c0910bfSGreg Roachclass ControlPanel implements RequestHandlerInterface
780c0910bfSGreg Roach{
790c0910bfSGreg Roach    use ViewResponseTrait;
800c0910bfSGreg Roach
81c9c6f2ecSGreg Roach    private AdminService $admin_service;
826fd01894SGreg Roach
83c9c6f2ecSGreg Roach    private HousekeepingService $housekeeping_service;
840c0910bfSGreg Roach
85a46dd5a6SGreg Roach    private MessageService $message_service;
86a46dd5a6SGreg Roach
87a46dd5a6SGreg Roach    private ModuleService $module_service;
88a46dd5a6SGreg Roach
89c9c6f2ecSGreg Roach    private ServerCheckService $server_check_service;
900c0910bfSGreg Roach
91c9c6f2ecSGreg Roach    private TreeService $tree_service;
920c0910bfSGreg Roach
93c9c6f2ecSGreg Roach    private UpgradeService $upgrade_service;
940c0910bfSGreg Roach
95c9c6f2ecSGreg Roach    private UserService $user_service;
960c0910bfSGreg Roach
970c0910bfSGreg Roach    /**
980c0910bfSGreg Roach     * ControlPanel constructor.
990c0910bfSGreg Roach     *
1006fd01894SGreg Roach     * @param AdminService        $admin_service
1010c0910bfSGreg Roach     * @param HousekeepingService $housekeeping_service
102a46dd5a6SGreg Roach     * @param MessageService      $message_service
1030c0910bfSGreg Roach     * @param ModuleService       $module_service
1040c0910bfSGreg Roach     * @param ServerCheckService  $server_check_service
1050c0910bfSGreg Roach     * @param TreeService         $tree_service
1060c0910bfSGreg Roach     * @param UpgradeService      $upgrade_service
1070c0910bfSGreg Roach     * @param UserService         $user_service
1080c0910bfSGreg Roach     */
1090c0910bfSGreg Roach    public function __construct(
1106fd01894SGreg Roach        AdminService $admin_service,
1110c0910bfSGreg Roach        HousekeepingService $housekeeping_service,
112a46dd5a6SGreg Roach        MessageService $message_service,
1130c0910bfSGreg Roach        ModuleService $module_service,
1140c0910bfSGreg Roach        ServerCheckService $server_check_service,
1150c0910bfSGreg Roach        TreeService $tree_service,
1160c0910bfSGreg Roach        UpgradeService $upgrade_service,
1170c0910bfSGreg Roach        UserService $user_service
118928b8592SGreg Roach    ) {
1196fd01894SGreg Roach        $this->admin_service        = $admin_service;
1200c0910bfSGreg Roach        $this->housekeeping_service = $housekeeping_service;
121a46dd5a6SGreg Roach        $this->message_service      = $message_service;
1226fd01894SGreg Roach        $this->module_service       = $module_service;
1230c0910bfSGreg Roach        $this->server_check_service = $server_check_service;
1240c0910bfSGreg Roach        $this->tree_service         = $tree_service;
1250c0910bfSGreg Roach        $this->upgrade_service      = $upgrade_service;
1260c0910bfSGreg Roach        $this->user_service         = $user_service;
1270c0910bfSGreg Roach    }
1280c0910bfSGreg Roach
1290c0910bfSGreg Roach    /**
1300c0910bfSGreg Roach     * @param ServerRequestInterface $request
1310c0910bfSGreg Roach     *
1320c0910bfSGreg Roach     * @return ResponseInterface
1330c0910bfSGreg Roach     */
1340c0910bfSGreg Roach    public function handle(ServerRequestInterface $request): ResponseInterface
1350c0910bfSGreg Roach    {
1360c0910bfSGreg Roach        $this->layout = 'layouts/administration';
1370c0910bfSGreg Roach
138f7cf8a15SGreg Roach        $filesystem      = new Filesystem(new LocalFilesystemAdapter(Webtrees::ROOT_DIR));
1390c0910bfSGreg Roach        $files_to_delete = $this->housekeeping_service->deleteOldWebtreesFiles($filesystem);
1400c0910bfSGreg Roach
14164d12f7bSGreg Roach        $custom_updates = $this->module_service
14264d12f7bSGreg Roach            ->findByInterface(ModuleCustomInterface::class)
14364d12f7bSGreg Roach            ->filter(static function (ModuleCustomInterface $module): bool {
14464d12f7bSGreg Roach                return version_compare($module->customModuleLatestVersion(), $module->customModuleVersion()) > 0;
14564d12f7bSGreg Roach            });
14664d12f7bSGreg Roach
1476fd01894SGreg Roach        $multiple_tree_threshold = $this->admin_service->multipleTreeThreshold();
1486b9cb339SGreg Roach        $gedcom_file_count       = $this->admin_service->gedcomFiles(Registry::filesystem()->data())->count();
1496fd01894SGreg Roach
1500c0910bfSGreg Roach        return $this->viewResponse('admin/control-panel', [
1510c0910bfSGreg Roach            'title'                             => I18N::translate('Control panel'),
1520c0910bfSGreg Roach            'server_errors'                     => $this->server_check_service->serverErrors(),
1530c0910bfSGreg Roach            'server_warnings'                   => $this->server_check_service->serverWarnings(),
1540c0910bfSGreg Roach            'latest_version'                    => $this->upgrade_service->latestVersion(),
1550c0910bfSGreg Roach            'all_users'                         => $this->user_service->all(),
1560c0910bfSGreg Roach            'administrators'                    => $this->user_service->administrators(),
1570c0910bfSGreg Roach            'managers'                          => $this->user_service->managers(),
1580c0910bfSGreg Roach            'moderators'                        => $this->user_service->moderators(),
1590c0910bfSGreg Roach            'unapproved'                        => $this->user_service->unapproved(),
1600c0910bfSGreg Roach            'unverified'                        => $this->user_service->unverified(),
161a46dd5a6SGreg Roach            'recipients'                        => $this->message_service->recipientTypes(),
1620c0910bfSGreg Roach            'all_trees'                         => $this->tree_service->all(),
1630c0910bfSGreg Roach            'changes'                           => $this->totalChanges(),
1640c0910bfSGreg Roach            'individuals'                       => $this->totalIndividuals(),
1650c0910bfSGreg Roach            'families'                          => $this->totalFamilies(),
1660c0910bfSGreg Roach            'sources'                           => $this->totalSources(),
1670c0910bfSGreg Roach            'media'                             => $this->totalMediaObjects(),
1680c0910bfSGreg Roach            'repositories'                      => $this->totalRepositories(),
1690c0910bfSGreg Roach            'notes'                             => $this->totalNotes(),
170e72c24d6SGreg Roach            'submitters'                        => $this->totalSubmitters(),
17160ef53afSGreg Roach            'individual_list_module'            => $this->module_service->findByInterface(IndividualListModule::class)->last(),
1720c0910bfSGreg Roach            'family_list_module'                => $this->module_service->findByInterface(FamilyListModule::class)->first(),
1730c0910bfSGreg Roach            'media_list_module'                 => $this->module_service->findByInterface(MediaListModule::class)->first(),
1740c0910bfSGreg Roach            'note_list_module'                  => $this->module_service->findByInterface(NoteListModule::class)->first(),
1750c0910bfSGreg Roach            'repository_list_module'            => $this->module_service->findByInterface(RepositoryListModule::class)->first(),
1760c0910bfSGreg Roach            'source_list_module'                => $this->module_service->findByInterface(SourceListModule::class)->first(),
177e72c24d6SGreg Roach            'submitter_list_module'             => $this->module_service->findByInterface(SubmitterListModule::class)->first(),
1780c0910bfSGreg Roach            'files_to_delete'                   => $files_to_delete,
1790c0910bfSGreg Roach            'all_modules_disabled'              => $this->module_service->all(true),
1800c0910bfSGreg Roach            'all_modules_enabled'               => $this->module_service->all(),
1810c0910bfSGreg Roach            'deleted_modules'                   => $this->module_service->deletedModules(),
1820c0910bfSGreg Roach            'analytics_modules_disabled'        => $this->module_service->findByInterface(ModuleAnalyticsInterface::class, true),
1830c0910bfSGreg Roach            'analytics_modules_enabled'         => $this->module_service->findByInterface(ModuleAnalyticsInterface::class),
1840c0910bfSGreg Roach            'block_modules_disabled'            => $this->module_service->findByInterface(ModuleBlockInterface::class, true),
1850c0910bfSGreg Roach            'block_modules_enabled'             => $this->module_service->findByInterface(ModuleBlockInterface::class),
1860c0910bfSGreg Roach            'chart_modules_disabled'            => $this->module_service->findByInterface(ModuleChartInterface::class, true),
1870c0910bfSGreg Roach            'chart_modules_enabled'             => $this->module_service->findByInterface(ModuleChartInterface::class),
18864d12f7bSGreg Roach            'custom_updates'                    => $custom_updates,
1894da96842SGreg Roach            'custom_tags_modules_disabled' => $this->module_service->findByInterface(ModuleCustomTagsInterface::class, true),
1904da96842SGreg Roach            'custom_tags_modules_enabled'  => $this->module_service->findByInterface(ModuleCustomTagsInterface::class),
191ce42304aSGreg Roach            'data_fix_modules_disabled'         => $this->module_service->findByInterface(ModuleDataFixInterface::class, true),
192ce42304aSGreg Roach            'data_fix_modules_enabled'          => $this->module_service->findByInterface(ModuleDataFixInterface::class),
1930c0910bfSGreg Roach            'other_modules'                     => $this->module_service->otherModules(true),
1940c0910bfSGreg Roach            'footer_modules_disabled'           => $this->module_service->findByInterface(ModuleFooterInterface::class, true),
1950c0910bfSGreg Roach            'footer_modules_enabled'            => $this->module_service->findByInterface(ModuleFooterInterface::class),
1960c0910bfSGreg Roach            'history_modules_disabled'          => $this->module_service->findByInterface(ModuleHistoricEventsInterface::class, true),
1970c0910bfSGreg Roach            'history_modules_enabled'           => $this->module_service->findByInterface(ModuleHistoricEventsInterface::class),
1980c0910bfSGreg Roach            'language_modules_disabled'         => $this->module_service->findByInterface(ModuleLanguageInterface::class, true),
1990c0910bfSGreg Roach            'language_modules_enabled'          => $this->module_service->findByInterface(ModuleLanguageInterface::class),
2000c0910bfSGreg Roach            'list_modules_disabled'             => $this->module_service->findByInterface(ModuleListInterface::class, true),
2010c0910bfSGreg Roach            'list_modules_enabled'              => $this->module_service->findByInterface(ModuleListInterface::class),
202c9c6f2ecSGreg Roach            'map_autocomplete_modules_disabled' => $this->module_service->findByInterface(ModuleMapAutocompleteInterface::class, true),
203c9c6f2ecSGreg Roach            'map_autocomplete_modules_enabled'  => $this->module_service->findByInterface(ModuleMapAutocompleteInterface::class),
204e3544cb2SGreg Roach            'map_link_modules_disabled'         => $this->module_service->findByInterface(ModuleMapLinkInterface::class, true),
205e3544cb2SGreg Roach            'map_link_modules_enabled'          => $this->module_service->findByInterface(ModuleMapLinkInterface::class),
206c9c6f2ecSGreg Roach            'map_provider_modules_disabled'     => $this->module_service->findByInterface(ModuleMapProviderInterface::class, true),
207c9c6f2ecSGreg Roach            'map_provider_modules_enabled'      => $this->module_service->findByInterface(ModuleMapProviderInterface::class),
208c9c6f2ecSGreg Roach            'map_search_modules_disabled'       => $this->module_service->findByInterface(ModuleMapGeoLocationInterface::class, true),
209c9c6f2ecSGreg Roach            'map_search_modules_enabled'        => $this->module_service->findByInterface(ModuleMapGeoLocationInterface::class),
2100c0910bfSGreg Roach            'menu_modules_disabled'             => $this->module_service->findByInterface(ModuleMenuInterface::class, true),
2110c0910bfSGreg Roach            'menu_modules_enabled'              => $this->module_service->findByInterface(ModuleMenuInterface::class),
2120c0910bfSGreg Roach            'report_modules_disabled'           => $this->module_service->findByInterface(ModuleReportInterface::class, true),
2130c0910bfSGreg Roach            'report_modules_enabled'            => $this->module_service->findByInterface(ModuleReportInterface::class),
2148a1a28d7SGreg Roach            'share_modules_disabled'            => $this->module_service->findByInterface(ModuleShareInterface::class, true),
2158a1a28d7SGreg Roach            'share_modules_enabled'             => $this->module_service->findByInterface(ModuleShareInterface::class),
2160c0910bfSGreg Roach            'sidebar_modules_disabled'          => $this->module_service->findByInterface(ModuleSidebarInterface::class, true),
2170c0910bfSGreg Roach            'sidebar_modules_enabled'           => $this->module_service->findByInterface(ModuleSidebarInterface::class),
2180c0910bfSGreg Roach            'tab_modules_disabled'              => $this->module_service->findByInterface(ModuleTabInterface::class, true),
2190c0910bfSGreg Roach            'tab_modules_enabled'               => $this->module_service->findByInterface(ModuleTabInterface::class),
2200c0910bfSGreg Roach            'theme_modules_disabled'            => $this->module_service->findByInterface(ModuleThemeInterface::class, true),
2210c0910bfSGreg Roach            'theme_modules_enabled'             => $this->module_service->findByInterface(ModuleThemeInterface::class),
2226fd01894SGreg Roach            'show_synchronize'                  => $gedcom_file_count >= $multiple_tree_threshold,
2230c0910bfSGreg Roach        ]);
2240c0910bfSGreg Roach    }
2250c0910bfSGreg Roach
2260c0910bfSGreg Roach    /**
2270c0910bfSGreg Roach     * Count the number of pending changes in each tree.
2280c0910bfSGreg Roach     *
22924f2a3afSGreg Roach     * @return array<string>
2300c0910bfSGreg Roach     */
2310c0910bfSGreg Roach    private function totalChanges(): array
2320c0910bfSGreg Roach    {
2330c0910bfSGreg Roach        return DB::table('gedcom')
2340c0910bfSGreg Roach            ->leftJoin('change', static function (JoinClause $join): void {
2350c0910bfSGreg Roach                $join
2360c0910bfSGreg Roach                    ->on('change.gedcom_id', '=', 'gedcom.gedcom_id')
2370c0910bfSGreg Roach                    ->where('change.status', '=', 'pending');
2380c0910bfSGreg Roach            })
2390c0910bfSGreg Roach            ->groupBy(['gedcom.gedcom_id'])
240eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(change_id) AS aggregate'), 'gedcom.gedcom_id')
2410c0910bfSGreg Roach            ->all();
2420c0910bfSGreg Roach    }
2430c0910bfSGreg Roach
2440c0910bfSGreg Roach    /**
2450c0910bfSGreg Roach     * Count the number of individuals in each tree.
2460c0910bfSGreg Roach     *
24736779af1SGreg Roach     * @return Collection<int,int>
2480c0910bfSGreg Roach     */
2490c0910bfSGreg Roach    private function totalIndividuals(): Collection
2500c0910bfSGreg Roach    {
2510c0910bfSGreg Roach        return DB::table('gedcom')
2520c0910bfSGreg Roach            ->leftJoin('individuals', 'i_file', '=', 'gedcom_id')
2530c0910bfSGreg Roach            ->groupBy(['gedcom_id'])
254eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(i_id) AS aggregate'), 'gedcom_id')
2550c0910bfSGreg Roach            ->map(static function (string $count) {
2560c0910bfSGreg Roach                return (int) $count;
2570c0910bfSGreg Roach            });
2580c0910bfSGreg Roach    }
2590c0910bfSGreg Roach
2600c0910bfSGreg Roach    /**
2610c0910bfSGreg Roach     * Count the number of families in each tree.
2620c0910bfSGreg Roach     *
26336779af1SGreg Roach     * @return Collection<int,int>
2640c0910bfSGreg Roach     */
2650c0910bfSGreg Roach    private function totalFamilies(): Collection
2660c0910bfSGreg Roach    {
2670c0910bfSGreg Roach        return DB::table('gedcom')
2680c0910bfSGreg Roach            ->leftJoin('families', 'f_file', '=', 'gedcom_id')
2690c0910bfSGreg Roach            ->groupBy(['gedcom_id'])
270eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(f_id) AS aggregate'), 'gedcom_id')
2710c0910bfSGreg Roach            ->map(static function (string $count) {
2720c0910bfSGreg Roach                return (int) $count;
2730c0910bfSGreg Roach            });
2740c0910bfSGreg Roach    }
2750c0910bfSGreg Roach
2760c0910bfSGreg Roach    /**
2770c0910bfSGreg Roach     * Count the number of sources in each tree.
2780c0910bfSGreg Roach     *
27936779af1SGreg Roach     * @return Collection<int,int>
2800c0910bfSGreg Roach     */
2810c0910bfSGreg Roach    private function totalSources(): Collection
2820c0910bfSGreg Roach    {
2830c0910bfSGreg Roach        return DB::table('gedcom')
2840c0910bfSGreg Roach            ->leftJoin('sources', 's_file', '=', 'gedcom_id')
2850c0910bfSGreg Roach            ->groupBy(['gedcom_id'])
286eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(s_id) AS aggregate'), 'gedcom_id')
2870c0910bfSGreg Roach            ->map(static function (string $count) {
2880c0910bfSGreg Roach                return (int) $count;
2890c0910bfSGreg Roach            });
2900c0910bfSGreg Roach    }
2910c0910bfSGreg Roach
2920c0910bfSGreg Roach    /**
2930c0910bfSGreg Roach     * Count the number of media objects in each tree.
2940c0910bfSGreg Roach     *
29536779af1SGreg Roach     * @return Collection<int,int>
2960c0910bfSGreg Roach     */
2970c0910bfSGreg Roach    private function totalMediaObjects(): Collection
2980c0910bfSGreg Roach    {
2990c0910bfSGreg Roach        return DB::table('gedcom')
3000c0910bfSGreg Roach            ->leftJoin('media', 'm_file', '=', 'gedcom_id')
3010c0910bfSGreg Roach            ->groupBy(['gedcom_id'])
302eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(m_id) AS aggregate'), 'gedcom_id')
3030c0910bfSGreg Roach            ->map(static function (string $count) {
3040c0910bfSGreg Roach                return (int) $count;
3050c0910bfSGreg Roach            });
3060c0910bfSGreg Roach    }
3070c0910bfSGreg Roach
3080c0910bfSGreg Roach    /**
30936779af1SGreg Roach     * Count the number of repositories in each tree.
3100c0910bfSGreg Roach     *
31136779af1SGreg Roach     * @return Collection<int,int>
3120c0910bfSGreg Roach     */
3130c0910bfSGreg Roach    private function totalRepositories(): Collection
3140c0910bfSGreg Roach    {
3150c0910bfSGreg Roach        return DB::table('gedcom')
3160c0910bfSGreg Roach            ->leftJoin('other', static function (JoinClause $join): void {
3170c0910bfSGreg Roach                $join
3180c0910bfSGreg Roach                    ->on('o_file', '=', 'gedcom_id')
319e72c24d6SGreg Roach                    ->where('o_type', '=', Repository::RECORD_TYPE);
3200c0910bfSGreg Roach            })
3210c0910bfSGreg Roach            ->groupBy(['gedcom_id'])
322eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(o_id) AS aggregate'), 'gedcom_id')
3230c0910bfSGreg Roach            ->map(static function (string $count) {
3240c0910bfSGreg Roach                return (int) $count;
3250c0910bfSGreg Roach            });
3260c0910bfSGreg Roach    }
3270c0910bfSGreg Roach
3280c0910bfSGreg Roach    /**
3290c0910bfSGreg Roach     * Count the number of notes in each tree.
3300c0910bfSGreg Roach     *
33136779af1SGreg Roach     * @return Collection<int,int>
3320c0910bfSGreg Roach     */
3330c0910bfSGreg Roach    private function totalNotes(): Collection
3340c0910bfSGreg Roach    {
3350c0910bfSGreg Roach        return DB::table('gedcom')
3360c0910bfSGreg Roach            ->leftJoin('other', static function (JoinClause $join): void {
3370c0910bfSGreg Roach                $join
3380c0910bfSGreg Roach                    ->on('o_file', '=', 'gedcom_id')
339e72c24d6SGreg Roach                    ->where('o_type', '=', Note::RECORD_TYPE);
340e72c24d6SGreg Roach            })
341e72c24d6SGreg Roach            ->groupBy(['gedcom_id'])
342eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(o_id) AS aggregate'), 'gedcom_id')
343e72c24d6SGreg Roach            ->map(static function (string $count) {
344e72c24d6SGreg Roach                return (int) $count;
345e72c24d6SGreg Roach            });
346e72c24d6SGreg Roach    }
347e72c24d6SGreg Roach
348e72c24d6SGreg Roach    /**
349e72c24d6SGreg Roach     * Count the number of submitters in each tree.
350e72c24d6SGreg Roach     *
35136779af1SGreg Roach     * @return Collection<int,int>
352e72c24d6SGreg Roach     */
353e72c24d6SGreg Roach    private function totalSubmitters(): Collection
354e72c24d6SGreg Roach    {
355e72c24d6SGreg Roach        return DB::table('gedcom')
356e72c24d6SGreg Roach            ->leftJoin('other', static function (JoinClause $join): void {
357e72c24d6SGreg Roach                $join
358e72c24d6SGreg Roach                    ->on('o_file', '=', 'gedcom_id')
359e72c24d6SGreg Roach                    ->where('o_type', '=', Submitter::RECORD_TYPE);
3600c0910bfSGreg Roach            })
3610c0910bfSGreg Roach            ->groupBy(['gedcom_id'])
362eb8ab1e1SGreg Roach            ->pluck(new Expression('COUNT(o_id) AS aggregate'), 'gedcom_id')
3630c0910bfSGreg Roach            ->map(static function (string $count) {
3640c0910bfSGreg Roach                return (int) $count;
3650c0910bfSGreg Roach            });
3660c0910bfSGreg Roach    }
3670c0910bfSGreg Roach}
368