xref: /webtrees/app/Module/HitCountFooterModule.php (revision a34b54dc84837d4fd1e3b55dfaf41e1761acb658)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2019 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16declare(strict_types=1);
17
18namespace Fisharebest\Webtrees\Module;
19
20use Fisharebest\Webtrees\Contracts\UserInterface;
21use Fisharebest\Webtrees\I18N;
22use Fisharebest\Webtrees\Session;
23use Fisharebest\Webtrees\Tree;
24use Fisharebest\Webtrees\User;
25use Illuminate\Database\Capsule\Manager as DB;
26use Symfony\Component\HttpFoundation\Request;
27
28/**
29 * Class HitCountFooterModule - show the popular sites in the footer.
30 */
31class HitCountFooterModule extends AbstractModule implements ModuleFooterInterface
32{
33    use ModuleFooterTrait;
34
35    // Which pages/routes do we count?
36    // For historical reasons, we record the names of the original webtrees script and parameter.
37    protected const PAGE_NAMES = [
38        'family'     => 'family.php',
39        'individual' => 'individual.php',
40        'media'      => 'mediaviewer.php',
41        'note'       => 'note.php',
42        'repository' => 'repo.php',
43        'source'     => 'source.php',
44        'tree-page'  => 'index.php',
45        'user-page'  => 'index.php',
46    ];
47
48    /** @var Request */
49    protected $request;
50
51    /** @var Tree|null */
52    protected $tree;
53
54    /** @var User */
55    protected $user;
56
57    /** @var int */
58    protected $page_hits = 0;
59
60    /**
61     * Dependency injection.
62     *
63     * @param Tree|null     $tree
64     * @param UserInterface $user
65     * @param Request       $request
66     */
67    public function __construct(?Tree $tree, UserInterface $user, Request $request)
68    {
69        $this->tree    = $tree;
70        $this->user    = $user;
71        $this->request = $request;
72
73        if ($this->tree !== null && $this->tree->getPreference('SHOW_COUNTER')) {
74            $route = $request->get('route');
75
76            $page_name = self::PAGE_NAMES[$route] ?? '';
77
78            switch ($route) {
79                case 'family':
80                case 'individual':
81                case 'media':
82                case 'note':
83                case 'repository':
84                case 'source':
85                    $this->page_hits = $this->countHit($page_name, $request->get('xref', ''));
86                    break;
87
88                case 'tree-page':
89                    $this->page_hits = $this->countHit($page_name, 'gedcom:' . $this->tree->id());
90                    break;
91
92                case 'user-page':
93                    $this->page_hits = $this->countHit($page_name, 'user:' . $this->user->id());
94                    break;
95            }
96        }
97    }
98
99    /**
100     * How should this module be labelled on tabs, footers, etc.?
101     *
102     * @return string
103     */
104    public function title(): string
105    {
106        /* I18N: Name of a module */
107        return I18N::translate('Hit counters');
108    }
109
110    /**
111     * A sentence describing what this module does.
112     *
113     * @return string
114     */
115    public function description(): string
116    {
117        /* I18N: Description of the “Hit counters” module */
118        return I18N::translate('Count the visits to each page');
119    }
120
121    /**
122     * The default position for this footer.  It can be changed in the control panel.
123     *
124     * @return int
125     */
126    public function defaultFooterOrder(): int
127    {
128        return 3;
129    }
130
131    /**
132     * A footer, to be added at the bottom of every page.
133     *
134     * @return string
135     */
136    public function getFooter(): string
137    {
138        if ($this->tree === null || $this->page_hits === 0) {
139            return '';
140        }
141
142        $digits = '<span class="odometer">' . I18N::digits($this->page_hits) . '</span>';
143
144        return view('modules/hit-counter/footer', [
145            'hit_counter' => I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $this->page_hits, $digits),
146        ]);
147    }
148
149    /**
150     * Increment the page count.
151     *
152     * @param string $page
153     * @param string $parameter
154     *
155     * @return int
156     */
157    protected function countHit($page, $parameter): int
158    {
159        if ($this->tree === null) {
160            return 0;
161        }
162
163        $gedcom_id = $this->tree->id();
164
165        // Don't increment the counter while we stay on the same page.
166        if (
167            Session::get('last_gedcom_id') === $gedcom_id &&
168            Session::get('last_page_name') === $page &&
169            Session::get('last_page_parameter') === $parameter
170        ) {
171            return Session::get('last_count');
172        }
173
174        $count = (int) DB::table('hit_counter')
175            ->where('gedcom_id', '=', $this->tree->id())
176            ->where('page_name', '=', $page)
177            ->where('page_parameter', '=', $parameter)
178            ->value('page_count');
179
180        $count++;
181
182        DB::table('hit_counter')->updateOrInsert([
183            'gedcom_id'      => $this->tree->id(),
184            'page_name'      => $page,
185            'page_parameter' => $parameter,
186        ], [
187            'page_count' => $count,
188        ]);
189
190        Session::put('last_gedcom_id', $gedcom_id);
191        Session::put('last_page_name', $page);
192        Session::put('last_page_parameter', $parameter);
193        Session::put('last_count', $count);
194
195        return $count;
196    }
197}
198