xref: /webtrees/app/Module/HitCountFooterModule.php (revision 7413816e6dd2d50e569034fb804f3dce7471bb94)
133c34396SGreg Roach<?php
23976b470SGreg Roach
333c34396SGreg Roach/**
433c34396SGreg Roach * webtrees: online genealogy
5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team
633c34396SGreg Roach * This program is free software: you can redistribute it and/or modify
733c34396SGreg Roach * it under the terms of the GNU General Public License as published by
833c34396SGreg Roach * the Free Software Foundation, either version 3 of the License, or
933c34396SGreg Roach * (at your option) any later version.
1033c34396SGreg Roach * This program is distributed in the hope that it will be useful,
1133c34396SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
1233c34396SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1333c34396SGreg Roach * GNU General Public License for more details.
1433c34396SGreg 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/>.
1633c34396SGreg Roach */
17fcfa147eSGreg Roach
1833c34396SGreg Roachdeclare(strict_types=1);
1933c34396SGreg Roach
2033c34396SGreg Roachnamespace Fisharebest\Webtrees\Module;
2133c34396SGreg Roach
22*6f4ec3caSGreg Roachuse Fisharebest\Webtrees\DB;
238bfab638SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\FamilyPage;
248bfab638SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\IndividualPage;
258bfab638SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MediaPage;
268bfab638SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\NotePage;
278bfab638SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\RepositoryPage;
288bfab638SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SourcePage;
291e1acee3SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SubmitterPage;
308e0e1b25SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\TreePage;
318e0e1b25SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\UserPage;
3233c34396SGreg Roachuse Fisharebest\Webtrees\I18N;
3333c34396SGreg Roachuse Fisharebest\Webtrees\Session;
3433c34396SGreg Roachuse Fisharebest\Webtrees\Tree;
35b55cbc6bSGreg Roachuse Fisharebest\Webtrees\Validator;
366ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface;
376ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
386ccdf4f0SGreg Roachuse Psr\Http\Server\MiddlewareInterface;
396ccdf4f0SGreg Roachuse Psr\Http\Server\RequestHandlerInterface;
4033c34396SGreg Roach
4133c34396SGreg Roach/**
420c8c69d4SGreg Roach * Class HitCountFooterModule - show the number of page hits in the footer.
4333c34396SGreg Roach */
440c8c69d4SGreg Roachclass HitCountFooterModule extends AbstractModule implements ModuleFooterInterface, MiddlewareInterface
4533c34396SGreg Roach{
4633c34396SGreg Roach    use ModuleFooterTrait;
4733c34396SGreg Roach
48f1d4b4a2SGreg Roach    // Which routes do we count?
4933c34396SGreg Roach    // For historical reasons, we record the names of the original webtrees script and parameter.
5033c34396SGreg Roach    protected const PAGE_NAMES = [
518bfab638SGreg Roach        FamilyPage::class     => 'family.php',
528bfab638SGreg Roach        IndividualPage::class => 'individual.php',
538bfab638SGreg Roach        MediaPage::class      => 'mediaviewer.php',
548bfab638SGreg Roach        NotePage::class       => 'note.php',
558bfab638SGreg Roach        RepositoryPage::class => 'repo.php',
568bfab638SGreg Roach        SourcePage::class     => 'source.php',
571e1acee3SGreg Roach        SubmitterPage::class  => 'submitter',
588e0e1b25SGreg Roach        TreePage::class       => 'index.php',
598e0e1b25SGreg Roach        UserPage::class       => 'index.php',
6033c34396SGreg Roach    ];
6133c34396SGreg Roach
6233c746f1SGreg Roach    // Count of visits to the current page
6333c746f1SGreg Roach    protected int $page_hits = 0;
6433c34396SGreg Roach
6533c34396SGreg Roach    /**
66d4c04956SGreg Roach     * How should this module be labelled on tabs, footers, etc.?
67d4c04956SGreg Roach     *
68d4c04956SGreg Roach     * @return string
69d4c04956SGreg Roach     */
70d4c04956SGreg Roach    public function title(): string
71d4c04956SGreg Roach    {
72d4c04956SGreg Roach        /* I18N: Name of a module */
73d4c04956SGreg Roach        return I18N::translate('Hit counters');
74d4c04956SGreg Roach    }
75d4c04956SGreg Roach
76d4c04956SGreg Roach    public function description(): string
77d4c04956SGreg Roach    {
78d4c04956SGreg Roach        /* I18N: Description of the “Hit counters” module */
79d4c04956SGreg Roach        return I18N::translate('Count the visits to each page');
80d4c04956SGreg Roach    }
81d4c04956SGreg Roach
82d4c04956SGreg Roach    /**
8333c34396SGreg Roach     * The default position for this footer.  It can be changed in the control panel.
8433c34396SGreg Roach     *
8533c34396SGreg Roach     * @return int
8633c34396SGreg Roach     */
8733c34396SGreg Roach    public function defaultFooterOrder(): int
8833c34396SGreg Roach    {
8933c34396SGreg Roach        return 3;
9033c34396SGreg Roach    }
9133c34396SGreg Roach
9233c34396SGreg Roach    /**
9333c34396SGreg Roach     * A footer, to be added at the bottom of every page.
9433c34396SGreg Roach     *
95a992e8c1SGreg Roach     * @param ServerRequestInterface $request
960c8c69d4SGreg Roach     *
9733c34396SGreg Roach     * @return string
9833c34396SGreg Roach     */
99a992e8c1SGreg Roach    public function getFooter(ServerRequestInterface $request): string
10033c34396SGreg Roach    {
1010c8c69d4SGreg Roach        if ($this->page_hits === 0) {
10233c34396SGreg Roach            return '';
10333c34396SGreg Roach        }
10433c34396SGreg Roach
10533c34396SGreg Roach        $digits = '<span class="odometer">' . I18N::digits($this->page_hits) . '</span>';
10633c34396SGreg Roach
10733c34396SGreg Roach        return view('modules/hit-counter/footer', [
10833c34396SGreg Roach            'hit_counter' => I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $this->page_hits, $digits),
10933c34396SGreg Roach        ]);
11033c34396SGreg Roach    }
11133c34396SGreg Roach
11233c34396SGreg Roach    /**
1136ccdf4f0SGreg Roach     * @param ServerRequestInterface  $request
1146ccdf4f0SGreg Roach     * @param RequestHandlerInterface $handler
1156ccdf4f0SGreg Roach     *
1166ccdf4f0SGreg Roach     * @return ResponseInterface
1176ccdf4f0SGreg Roach     */
1186ccdf4f0SGreg Roach    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
1196ccdf4f0SGreg Roach    {
120b55cbc6bSGreg Roach        $route = Validator::attributes($request)->route();
121b55cbc6bSGreg Roach        $tree  = Validator::attributes($request)->treeOptional();
122b55cbc6bSGreg Roach        $user  = Validator::attributes($request)->user();
1236ccdf4f0SGreg Roach
1246ccdf4f0SGreg Roach        if ($tree instanceof Tree && $tree->getPreference('SHOW_COUNTER')) {
125de2aa325SGreg Roach            $page_name = self::PAGE_NAMES[$route->name] ?? '';
1266ccdf4f0SGreg Roach
127de2aa325SGreg Roach            switch ($route->name) {
1288bfab638SGreg Roach                case FamilyPage::class:
1298bfab638SGreg Roach                case IndividualPage::class:
1308bfab638SGreg Roach                case MediaPage::class:
1318bfab638SGreg Roach                case NotePage::class:
1328bfab638SGreg Roach                case RepositoryPage::class:
1338bfab638SGreg Roach                case SourcePage::class:
1341e1acee3SGreg Roach                case SubmitterPage::class:
135b55cbc6bSGreg Roach                    $xref = Validator::attributes($request)->isXref()->string('xref');
136b55cbc6bSGreg Roach                    $this->page_hits = $this->countHit($tree, $page_name, $xref);
1376ccdf4f0SGreg Roach                    break;
1386ccdf4f0SGreg Roach
1398e0e1b25SGreg Roach                case TreePage::class:
1406ccdf4f0SGreg Roach                    $this->page_hits = $this->countHit($tree, $page_name, 'gedcom:' . $tree->id());
1416ccdf4f0SGreg Roach                    break;
1426ccdf4f0SGreg Roach
1438e0e1b25SGreg Roach                case UserPage::class:
1446ccdf4f0SGreg Roach                    $this->page_hits = $this->countHit($tree, $page_name, 'user:' . $user->id());
1456ccdf4f0SGreg Roach                    break;
1466ccdf4f0SGreg Roach            }
1476ccdf4f0SGreg Roach        }
1486ccdf4f0SGreg Roach
1496ccdf4f0SGreg Roach        return $handler->handle($request);
1506ccdf4f0SGreg Roach    }
1516ccdf4f0SGreg Roach
1526ccdf4f0SGreg Roach    /**
15333c34396SGreg Roach     * Increment the page count.
15433c34396SGreg Roach     *
1550c8c69d4SGreg Roach     * @param Tree   $tree
15633c34396SGreg Roach     * @param string $page
15733c34396SGreg Roach     * @param string $parameter
15833c34396SGreg Roach     *
15933c34396SGreg Roach     * @return int
16033c34396SGreg Roach     */
1610c8c69d4SGreg Roach    protected function countHit(Tree $tree, string $page, string $parameter): int
16233c34396SGreg Roach    {
16333c34396SGreg Roach        // Don't increment the counter while we stay on the same page.
16433c34396SGreg Roach        if (
16533c34396SGreg Roach            Session::get('last_page_name') === $page &&
166a992e8c1SGreg Roach            Session::get('last_page_parameter') === $parameter &&
167a992e8c1SGreg Roach            Session::get('last_gedcom_id') === $tree->id()
16833c34396SGreg Roach        ) {
1690c8c69d4SGreg Roach            return (int) Session::get('last_count');
17033c34396SGreg Roach        }
17133c34396SGreg Roach
17233c34396SGreg Roach        $count = (int) DB::table('hit_counter')
1730c8c69d4SGreg Roach            ->where('gedcom_id', '=', $tree->id())
17433c34396SGreg Roach            ->where('page_name', '=', $page)
17533c34396SGreg Roach            ->where('page_parameter', '=', $parameter)
1768491737aSGreg Roach            ->value('page_count');
17733c34396SGreg Roach
17833c34396SGreg Roach        $count++;
17933c34396SGreg Roach
18033c34396SGreg Roach        DB::table('hit_counter')->updateOrInsert([
1810c8c69d4SGreg Roach            'gedcom_id'      => $tree->id(),
18233c34396SGreg Roach            'page_name'      => $page,
18333c34396SGreg Roach            'page_parameter' => $parameter,
18433c34396SGreg Roach        ], [
18533c34396SGreg Roach            'page_count' => $count,
18633c34396SGreg Roach        ]);
18733c34396SGreg Roach
1880c8c69d4SGreg Roach        Session::put('last_gedcom_id', $tree->id());
18933c34396SGreg Roach        Session::put('last_page_name', $page);
19033c34396SGreg Roach        Session::put('last_page_parameter', $parameter);
19133c34396SGreg Roach        Session::put('last_count', $count);
19233c34396SGreg Roach
19333c34396SGreg Roach        return $count;
19433c34396SGreg Roach    }
19533c34396SGreg Roach}
196