Completed
Push — 1.7 ( cdf6c4...82f31b )
by
unknown
10:24
created

individual.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * webtrees: online genealogy
4
 * Copyright (C) 2017 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
 */
16
namespace Fisharebest\Webtrees;
17
18
/**
19
 * Defined in session.php
20
 *
21
 * @global Tree $WT_TREE
22
 */
23
global $WT_TREE;
24
25
use Fisharebest\Webtrees\Controller\IndividualController;
26
use Fisharebest\Webtrees\Functions\FunctionsDate;
27
use Fisharebest\Webtrees\Functions\FunctionsDb;
28
use Fisharebest\Webtrees\Functions\FunctionsPrint;
29
30
define('WT_SCRIPT_NAME', 'individual.php');
31
require './includes/session.php';
32
33
$pid    = Filter::get('pid', WT_REGEX_XREF);
34
$record = Individual::getInstance($pid, $WT_TREE);
35
if (!$record) {
36
	$record = Individual::getInstance(FunctionsDb::findRin($pid), $WT_TREE);
37
}
38
$controller = new IndividualController($record);
39
40
if ($controller->record && $controller->record->canShow()) {
41
	if (Filter::get('action') == 'ajax') {
42
		$controller->ajaxRequest();
43
44
		return;
45
	}
46
	// Generate the sidebar content *before* we display the page header,
47
	// as the clippings cart needs to have write access to the session.
48
	$sidebar_html = $controller->getSideBarContent();
49
50
	if ($controller->record->isPendingDeletion()) {
51
		if (Auth::isModerator($controller->record->getTree())) {
52
			FlashMessages::addMessage(/* I18N: %1$s is “accept”, %2$s is “reject”. These are links. */ I18N::translate(
53
				'This individual has been deleted. You should review the deletion and then %1$s or %2$s it.',
54
				'<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'accept') . '</a>',
55
				'<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'reject') . '</a>'
56
			) . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning');
57
		} elseif (Auth::isEditor($controller->record->getTree())) {
58
			FlashMessages::addMessage(I18N::translate('This individual has been deleted. The deletion will need to be reviewed by a moderator.') . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning');
59
		}
60
	} elseif ($controller->record->isPendingAddtion()) {
61
		if (Auth::isModerator($controller->record->getTree())) {
62
			FlashMessages::addMessage(/* I18N: %1$s is “accept”, %2$s is “reject”. These are links. */ I18N::translate(
63
				'This individual has been edited. You should review the changes and then %1$s or %2$s them.',
64
				'<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the changes and then accept or reject them.', 'accept') . '</a>',
65
				'<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the changes and then accept or reject them.', 'reject') . '</a>'
66
			) . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning');
67
		} elseif (Auth::isEditor($controller->record->getTree())) {
68
			FlashMessages::addMessage(I18N::translate('This individual has been edited. The changes need to be reviewed by a moderator.') . ' ' . FunctionsPrint::helpLink('pending_changes'), 'warning');
69
		}
70
	}
71
	$controller->pageHeader();
72
} elseif ($controller->record && $controller->record->canShowName()) {
73
	// Just show the name.
74
	$controller->pageHeader();
75
	echo '<h2>', $controller->record->getFullName(), '</h2>';
76
	echo '<p>', I18N::translate('The details of this individual are private.'), '</p>';
77
78
	return;
79
} else {
80
	FlashMessages::addMessage(I18N::translate('This individual does not exist or you do not have permission to view it.'), 'danger');
81
	http_response_code(404);
82
	$controller->pageHeader();
83
84
	return;
85
}
86
87
$controller->addInlineJavascript('
88
var WT_INDIVIDUAL = (function () {
89
90
	var instance,
91
		jQseparator = jQuery("#separator"),
92
		jQsidebar = jQuery ("#sidebar");
93
94
	function init() {
95
		jQuery ("#header_accordion1").accordion ({
96
			active: 0,
97
			heightStyle: "content",
98
			collapsible: true
99
		});
100
101
		jQuery ("#tabs").tabs ({
102
			// Remember the currently selected tab between pages.
103
			active: sessionStorage.getItem("indi-tab"),
104
			activate: function (event, ui) {
105
				sessionStorage.setItem("indi-tab", jQuery(this).tabs("option", "active"));
106
			},
107
			// Only load each tab once
108
			beforeLoad: function (event, ui) {
109
				if (ui.tab.data ("loaded")) {
110
					event.preventDefault ();
111
					return;
112
				}
113
				jQuery (ui.panel.selector).append (\'<div class="loading-image"></div>\');
114
				ui.jqXHR.success (function () {
115
					ui.tab.data ("loaded", true);
116
				});
117
			}
118
		});
119
120
		if (jQsidebar.length) { // Have we got a sidebar ?
121
			// toggle sidebar visibility
122
			jQuery ("#main").on ("click", "#separator", function (e) {
123
				e.preventDefault ();
124
				jQsidebar.animate ({width: "toggle"}, {
125
					duration: 300,
126
					done: function () {
127
						sessionStorage.setItem("hide-sb", jQsidebar.is(":hidden"));
128
						jQseparator.toggleClass("separator-hidden separator-visible");
129
					}
130
				});
131
			});
132
133
			// Set initial sidebar state
134
			if (sessionStorage.getItem("hide-sb") === "true") {
135
				jQsidebar.hide ();
136
				jQseparator.addClass("separator-hidden");
137
			} else {
138
				jQsidebar.show ();
139
				jQseparator.addClass("separator-visible");
140
			}
141
		}
142
	}
143
144
	return {
145
		getInstance: function () {
146
			if (!instance) {
147
				instance = init ();
148
			}
149
			return instance;
150
		}
151
	};
152
}) ();
153
WT_INDIVIDUAL.getInstance ();
154
');
155
156
// ===================================== header area
157
echo
158
	'<div id="main">', //overall page container
159
	'<div id="indi_left">',
160
	'<div id="indi_header">';
161
if ($controller->record->canShow()) {
162
	// Highlight image or silhouette
163
	echo '<div id="indi_mainimage">', $controller->record->displayImage(), '</div>';
164
	echo '<div id="header_accordion1">'; // contain accordions for names
165
	echo '<h3 class="name_one ', $controller->getPersonStyle($controller->record), '"><span>', $controller->record->getFullName(), '</span>'; // First name accordion header
166
	$bdate = $controller->record->getBirthDate();
167
	$ddate = $controller->record->getDeathDate();
168
	echo '<span class="header_age">';
169
	if ($bdate->isOK() && !$controller->record->isDead()) {
170
		// If living display age
171
		echo GedcomTag::getLabelValue('AGE', FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($bdate, new Date(strtoupper(date('d M Y'))))), $controller->record, 'span');
172
	} elseif ($bdate->isOK() && $ddate->isOK()) {
173
		// If dead, show age at death
174
		echo GedcomTag::getLabelValue('AGE', FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($bdate, $ddate)), $controller->record, 'span');
175
	}
176
	echo '</span>';
177
	// Display summary birth/death info.
178
	echo '<span id="dates">', $controller->record->getLifeSpan(), '</span>';
179
180
	// Display gender icon
181
	foreach ($controller->record->getFacts() as $fact) {
182
		if ($fact->getTag() == 'SEX') {
183
			$controller->printSexRecord($fact);
184
		}
185
	}
186
	echo '</h3>'; // close first name accordion header
187
188
	// Display name details
189
	foreach ($controller->record->getFacts() as $fact) {
190
		if ($fact->getTag() == 'NAME') {
191
			$controller->printNameRecord($fact);
192
		}
193
	}
194
195
	echo '</div>'; // close header_accordion1
196
}
197
echo '</div>'; // close #indi_header
198
// ===================================== main content tabs
199
foreach ($controller->tabs as $tab) {
200
	echo $tab->getPreLoadContent();
201
}
202
echo '<div id="tabs">';
203
echo '<ul>';
204
foreach ($controller->tabs as $tab) {
205
	if ($tab->isGrayedOut()) {
206
		$greyed_out = 'rela';
207
	} else {
208
		$greyed_out = '';
209
	}
210
	if ($tab->hasTabContent()) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Fisharebest\Webtrees\Module\AbstractModule as the method hasTabContent() does only exist in the following sub-classes of Fisharebest\Webtrees\Module\AbstractModule: Fisharebest\Webtrees\Module\AlbumModule, Fisharebest\Webtrees\Module\GoogleMapsModule, Fisharebest\Webtrees\Mod...ndividualFactsTabModule, Fisharebest\Webtrees\Module\InteractiveTreeModule, Fisharebest\Webtrees\Module\MediaTabModule, Fisharebest\Webtrees\Module\NotesTabModule, Fisharebest\Webtrees\Module\RelativesTabModule, Fisharebest\Webtrees\Module\SourcesTabModule, Fisharebest\Webtrees\Module\StoriesModule. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
211
		echo '<li class="' . $greyed_out . '"><a';
212
		if ($tab->canLoadAjax()) {
213
			// AJAX tabs load only when selected
214
			echo ' href="' . $controller->record->getHtmlUrl(), '&amp;action=ajax&amp;module=', $tab->getName() . '"';
215
			echo ' rel="nofollow"';
216
		} else {
217
			// Non-AJAX tabs load immediately
218
			echo ' href="#', $tab->getName() . '"';
219
		}
220
		echo ' title="', $tab->getDescription(), '">', $tab->getTitle(), '</a></li>';
221
	}
222
}
223
echo '</ul>';
224
foreach ($controller->tabs as $tab) {
225
	if ($tab->hasTabContent()) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Fisharebest\Webtrees\Module\AbstractModule as the method hasTabContent() does only exist in the following sub-classes of Fisharebest\Webtrees\Module\AbstractModule: Fisharebest\Webtrees\Module\AlbumModule, Fisharebest\Webtrees\Module\GoogleMapsModule, Fisharebest\Webtrees\Mod...ndividualFactsTabModule, Fisharebest\Webtrees\Module\InteractiveTreeModule, Fisharebest\Webtrees\Module\MediaTabModule, Fisharebest\Webtrees\Module\NotesTabModule, Fisharebest\Webtrees\Module\RelativesTabModule, Fisharebest\Webtrees\Module\SourcesTabModule, Fisharebest\Webtrees\Module\StoriesModule. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
226
		if (!$tab->canLoadAjax()) {
227
			echo '<div id="', $tab->getName(), '">', $tab->getTabContent(), '</div>';
228
		}
229
	}
230
}
231
echo
232
	'</div>', // close #tabs
233
	'</div>'; //close indi_left
234
	if ($sidebar_html) {
235
		echo '<div id="separator" style="cursor:pointer;"></div>' . $sidebar_html;
236
	}
237
	echo '</div>'; // close #main
238