xref: /webtrees/app/Module/HitCountFooterModule.php (revision 4f2a4a627d63c93a33f6182088741daec764bf4b)
133c34396SGreg Roach<?php
233c34396SGreg Roach/**
333c34396SGreg Roach * webtrees: online genealogy
433c34396SGreg Roach * Copyright (C) 2019 webtrees development team
533c34396SGreg Roach * This program is free software: you can redistribute it and/or modify
633c34396SGreg Roach * it under the terms of the GNU General Public License as published by
733c34396SGreg Roach * the Free Software Foundation, either version 3 of the License, or
833c34396SGreg Roach * (at your option) any later version.
933c34396SGreg Roach * This program is distributed in the hope that it will be useful,
1033c34396SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
1133c34396SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1233c34396SGreg Roach * GNU General Public License for more details.
1333c34396SGreg Roach * You should have received a copy of the GNU General Public License
1433c34396SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
1533c34396SGreg Roach */
1633c34396SGreg Roachdeclare(strict_types=1);
1733c34396SGreg Roach
1833c34396SGreg Roachnamespace Fisharebest\Webtrees\Module;
1933c34396SGreg Roach
20e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
2133c34396SGreg Roachuse Fisharebest\Webtrees\I18N;
2233c34396SGreg Roachuse Fisharebest\Webtrees\Session;
2333c34396SGreg Roachuse Fisharebest\Webtrees\Tree;
2433c34396SGreg Roachuse Illuminate\Database\Capsule\Manager as DB;
256ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface;
266ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
276ccdf4f0SGreg Roachuse Psr\Http\Server\MiddlewareInterface;
286ccdf4f0SGreg Roachuse Psr\Http\Server\RequestHandlerInterface;
2933c34396SGreg Roach
3033c34396SGreg Roach/**
310c8c69d4SGreg Roach * Class HitCountFooterModule - show the number of page hits in the footer.
3233c34396SGreg Roach */
330c8c69d4SGreg Roachclass HitCountFooterModule extends AbstractModule implements ModuleFooterInterface, MiddlewareInterface
3433c34396SGreg Roach{
3533c34396SGreg Roach    use ModuleFooterTrait;
3633c34396SGreg Roach
3733c34396SGreg Roach    // Which pages/routes do we count?
3833c34396SGreg Roach    // For historical reasons, we record the names of the original webtrees script and parameter.
3933c34396SGreg Roach    protected const PAGE_NAMES = [
4033c34396SGreg Roach        'family'     => 'family.php',
4133c34396SGreg Roach        'individual' => 'individual.php',
4233c34396SGreg Roach        'media'      => 'mediaviewer.php',
4333c34396SGreg Roach        'note'       => 'note.php',
4433c34396SGreg Roach        'repository' => 'repo.php',
4533c34396SGreg Roach        'source'     => 'source.php',
4633c34396SGreg Roach        'tree-page'  => 'index.php',
4733c34396SGreg Roach        'user-page'  => 'index.php',
4833c34396SGreg Roach    ];
4933c34396SGreg Roach
500c8c69d4SGreg Roach    /** @var int Count of visits to the current page */
5133c34396SGreg Roach    protected $page_hits = 0;
5233c34396SGreg Roach
5333c34396SGreg Roach    /**
54d4c04956SGreg Roach     * How should this module be labelled on tabs, footers, etc.?
55d4c04956SGreg Roach     *
56d4c04956SGreg Roach     * @return string
57d4c04956SGreg Roach     */
58d4c04956SGreg Roach    public function title(): string
59d4c04956SGreg Roach    {
60d4c04956SGreg Roach        /* I18N: Name of a module */
61d4c04956SGreg Roach        return I18N::translate('Hit counters');
62d4c04956SGreg Roach    }
63d4c04956SGreg Roach
64d4c04956SGreg Roach    /**
65d4c04956SGreg Roach     * A sentence describing what this module does.
66d4c04956SGreg Roach     *
67d4c04956SGreg Roach     * @return string
68d4c04956SGreg Roach     */
69d4c04956SGreg Roach    public function description(): string
70d4c04956SGreg Roach    {
71d4c04956SGreg Roach        /* I18N: Description of the “Hit counters” module */
72d4c04956SGreg Roach        return I18N::translate('Count the visits to each page');
73d4c04956SGreg Roach    }
74d4c04956SGreg Roach
75d4c04956SGreg Roach    /**
7633c34396SGreg Roach     * The default position for this footer.  It can be changed in the control panel.
7733c34396SGreg Roach     *
7833c34396SGreg Roach     * @return int
7933c34396SGreg Roach     */
8033c34396SGreg Roach    public function defaultFooterOrder(): int
8133c34396SGreg Roach    {
8233c34396SGreg Roach        return 3;
8333c34396SGreg Roach    }
8433c34396SGreg Roach
8533c34396SGreg Roach    /**
8633c34396SGreg Roach     * A footer, to be added at the bottom of every page.
8733c34396SGreg Roach     *
880c8c69d4SGreg Roach     * @param Tree|null $tree
890c8c69d4SGreg Roach     *
9033c34396SGreg Roach     * @return string
9133c34396SGreg Roach     */
920c8c69d4SGreg Roach    public function getFooter(?Tree $tree): string
9333c34396SGreg Roach    {
940c8c69d4SGreg Roach        if ($this->page_hits === 0) {
9533c34396SGreg Roach            return '';
9633c34396SGreg Roach        }
9733c34396SGreg Roach
9833c34396SGreg Roach        $digits = '<span class="odometer">' . I18N::digits($this->page_hits) . '</span>';
9933c34396SGreg Roach
10033c34396SGreg Roach        return view('modules/hit-counter/footer', [
10133c34396SGreg Roach            'hit_counter' => I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $this->page_hits, $digits),
10233c34396SGreg Roach        ]);
10333c34396SGreg Roach    }
10433c34396SGreg Roach
10533c34396SGreg Roach    /**
1066ccdf4f0SGreg Roach     * @param ServerRequestInterface  $request
1076ccdf4f0SGreg Roach     * @param RequestHandlerInterface $handler
1086ccdf4f0SGreg Roach     *
1096ccdf4f0SGreg Roach     * @return ResponseInterface
1106ccdf4f0SGreg Roach     */
1116ccdf4f0SGreg Roach    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
1126ccdf4f0SGreg Roach    {
1136ccdf4f0SGreg Roach        $tree = app(Tree::class);
1146ccdf4f0SGreg Roach
1156ccdf4f0SGreg Roach        if ($tree instanceof Tree && $tree->getPreference('SHOW_COUNTER')) {
116*4f2a4a62SGreg Roach            $route = $request->getQueryParams()['route'] ?? '';
1176ccdf4f0SGreg Roach
1186ccdf4f0SGreg Roach            $page_name = self::PAGE_NAMES[$route] ?? '';
1196ccdf4f0SGreg Roach
1206ccdf4f0SGreg Roach            switch ($route) {
1216ccdf4f0SGreg Roach                case 'family':
1226ccdf4f0SGreg Roach                case 'individual':
1236ccdf4f0SGreg Roach                case 'media':
1246ccdf4f0SGreg Roach                case 'note':
1256ccdf4f0SGreg Roach                case 'repository':
1266ccdf4f0SGreg Roach                case 'source':
127*4f2a4a62SGreg Roach                    $this->page_hits = $this->countHit($tree, $page_name, $request->getQueryParams()['xref'] ?? '');
1286ccdf4f0SGreg Roach                    break;
1296ccdf4f0SGreg Roach
1306ccdf4f0SGreg Roach                case 'tree-page':
1316ccdf4f0SGreg Roach                    $this->page_hits = $this->countHit($tree, $page_name, 'gedcom:' . $tree->id());
1326ccdf4f0SGreg Roach                    break;
1336ccdf4f0SGreg Roach
1346ccdf4f0SGreg Roach                case 'user-page':
1356ccdf4f0SGreg Roach                    $user            = app(UserInterface::class);
1366ccdf4f0SGreg Roach                    $this->page_hits = $this->countHit($tree, $page_name, 'user:' . $user->id());
1376ccdf4f0SGreg Roach                    break;
1386ccdf4f0SGreg Roach            }
1396ccdf4f0SGreg Roach        }
1406ccdf4f0SGreg Roach
1416ccdf4f0SGreg Roach        return $handler->handle($request);
1426ccdf4f0SGreg Roach    }
1436ccdf4f0SGreg Roach
1446ccdf4f0SGreg Roach    /**
14533c34396SGreg Roach     * Increment the page count.
14633c34396SGreg Roach     *
1470c8c69d4SGreg Roach     * @param Tree   $tree
14833c34396SGreg Roach     * @param string $page
14933c34396SGreg Roach     * @param string $parameter
15033c34396SGreg Roach     *
15133c34396SGreg Roach     * @return int
15233c34396SGreg Roach     */
1530c8c69d4SGreg Roach    protected function countHit(Tree $tree, string $page, string $parameter): int
15433c34396SGreg Roach    {
15533c34396SGreg Roach        // Don't increment the counter while we stay on the same page.
15633c34396SGreg Roach        if (
1570c8c69d4SGreg Roach            Session::get('last_gedcom_id') === $tree->id() &&
15833c34396SGreg Roach            Session::get('last_page_name') === $page &&
15933c34396SGreg Roach            Session::get('last_page_parameter') === $parameter
16033c34396SGreg Roach        ) {
1610c8c69d4SGreg Roach            return (int) Session::get('last_count');
16233c34396SGreg Roach        }
16333c34396SGreg Roach
16433c34396SGreg Roach        $count = (int) DB::table('hit_counter')
1650c8c69d4SGreg Roach            ->where('gedcom_id', '=', $tree->id())
16633c34396SGreg Roach            ->where('page_name', '=', $page)
16733c34396SGreg Roach            ->where('page_parameter', '=', $parameter)
1688491737aSGreg Roach            ->value('page_count');
16933c34396SGreg Roach
17033c34396SGreg Roach        $count++;
17133c34396SGreg Roach
17233c34396SGreg Roach        DB::table('hit_counter')->updateOrInsert([
1730c8c69d4SGreg Roach            'gedcom_id'      => $tree->id(),
17433c34396SGreg Roach            'page_name'      => $page,
17533c34396SGreg Roach            'page_parameter' => $parameter,
17633c34396SGreg Roach        ], [
17733c34396SGreg Roach            'page_count' => $count,
17833c34396SGreg Roach        ]);
17933c34396SGreg Roach
1800c8c69d4SGreg Roach        Session::put('last_gedcom_id', $tree->id());
18133c34396SGreg Roach        Session::put('last_page_name', $page);
18233c34396SGreg Roach        Session::put('last_page_parameter', $parameter);
18333c34396SGreg Roach        Session::put('last_count', $count);
18433c34396SGreg Roach
18533c34396SGreg Roach        return $count;
18633c34396SGreg Roach    }
18733c34396SGreg Roach}
188