Completed
Pull Request — master (#926)
by Mark
21:38 queued 09:30
created

individual.php (7 issues)

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) 2016 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 && $WT_TREE->getPreference('USE_RIN')) {
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
	$controller->pageHeader();
51
	if ($controller->record->isPendingDeletion()) {
52
		if (Auth::isModerator($controller->record->getTree())) {
53
			echo
54
				'<p class="ui-state-highlight">',
55
				/* I18N: %1$s is “accept”, %2$s is “reject”. These are links. */ I18N::translate(
56
					'This individual has been deleted. You should review the deletion and then %1$s or %2$s it.',
57
					'<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'accept') . '</a>',
58
					'<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'reject') . '</a>'
59
				),
60
				' ', FunctionsPrint::helpLink('pending_changes'),
61
				'</p>';
62
		} elseif (Auth::isEditor($controller->record->getTree())) {
63
			echo
64
				'<p class="ui-state-highlight">',
65
				I18N::translate('This individual has been deleted. The deletion will need to be reviewed by a moderator.'),
66
				' ', FunctionsPrint::helpLink('pending_changes'),
67
				'</p>';
68
		}
69
	} elseif ($controller->record->isPendingAddtion()) {
70
		if (Auth::isModerator($controller->record->getTree())) {
71
			echo
72
				'<p class="ui-state-highlight">',
73
				/* I18N: %1$s is “accept”, %2$s is “reject”. These are links. */ I18N::translate(
74
					'This individual has been edited. You should review the changes and then %1$s or %2$s them.',
75
					'<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the changes and then accept or reject them.', 'accept') . '</a>',
76
					'<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the changes and then accept or reject them.', 'reject') . '</a>'
77
				),
78
				' ', FunctionsPrint::helpLink('pending_changes'),
79
				'</p>';
80
		} elseif (Auth::isEditor($controller->record->getTree())) {
81
			echo
82
				'<p class="ui-state-highlight">',
83
				I18N::translate('This individual has been edited. The changes need to be reviewed by a moderator.'),
84
				' ', FunctionsPrint::helpLink('pending_changes'),
85
				'</p>';
86
		}
87
	}
88
} elseif ($controller->record && $controller->record->canShowName()) {
89
	// Just show the name.
90
	$controller->pageHeader();
91
	echo '<h2>', $controller->record->getFullName(), '</h2>';
92
	echo '<p class="ui-state-highlight">', I18N::translate('The details of this individual are private.'), '</p>';
93
94
	return;
95
} else {
96
	http_response_code(404);
97
	$controller->pageHeader();
98
	echo '<p class="ui-state-error">', I18N::translate('This individual does not exist or you do not have permission to view it.'), '</p>';
99
100
	return;
101
}
102
103
$controller->addInlineJavascript('
104
var WT_INDIVIDUAL = (function () {
105
106
	var instance,
107
		jQseparator = jQuery("#separator"),
108
		jQsidebar = jQuery ("#sidebar");
109
110
	function init() {
111
		jQuery ("#header_accordion1").accordion ({
112
			active: 0,
113
			heightStyle: "content",
114
			collapsible: true
115
		});
116
117
		jQuery ("#tabs").tabs ({
118
			// Remember the currently selected tab between pages.
119
			active: sessionStorage.getItem("indi-tab"),
120
			activate: function (event, ui) {
121
				sessionStorage.setItem("indi-tab", jQuery(this).tabs("option", "active"));
122
			},
123
			// Only load each tab once
124
			beforeLoad: function (event, ui) {
125
				if (ui.tab.data ("loaded")) {
126
					event.preventDefault ();
127
					return;
128
				}
129
				jQuery (ui.panel.selector).append (\'<div class="loading-image"></div>\');
130
				ui.jqXHR.success (function () {
131
					ui.tab.data ("loaded", true);
132
				});
133
			}
134
		});
135
136
		if (jQsidebar.length) { // Have we got a sidebar ?
137
			// toggle sidebar visibility
138
			jQuery ("#main").on ("click", "#separator", function (e) {
139
				e.preventDefault ();
140
				jQsidebar.animate ({width: "toggle"}, {
141
					duration: 300,
142
					done: function () {
143
						sessionStorage.setItem("hide-sb", jQsidebar.is(":hidden"));
144
						jQseparator.toggleClass("separator-hidden separator-visible");
145
					}
146
				});
147
			});
148
149
			// Set initial sidebar state
150
			if (sessionStorage.getItem("hide-sb") === "true") {
151
				jQsidebar.hide ();
152
				jQseparator.addClass("separator-hidden");
153
			} else {
154
				jQsidebar.show ();
155
				jQseparator.addClass("separator-visible");
156
			}
157
		}
158
	}
159
160
	return {
161
		getInstance: function () {
162
			if (!instance) {
163
				instance = init ();
164
			}
165
			return instance;
166
		}
167
	};
168
}) ();
169
WT_INDIVIDUAL.getInstance ();
170
');
171
172
// ===================================== header area
173
echo
174
	'<div id="main">', //overall page container
175
	'<div id="indi_left">',
176
	'<div id="indi_header">';
177
if ($controller->record->canShow()) {
178
	// Highlight image or silhouette
179
	echo '<div id="indi_mainimage">', $controller->record->displayImage(), '</div>';
180
	echo '<div id="header_accordion1">'; // contain accordions for names
181
	echo '<h3 class="name_one ', $controller->getPersonStyle($controller->record), '"><span>', $controller->record->getFullName(), '</span>'; // First name accordion header
182
	$bdate = $controller->record->getBirthDate();
183
	$ddate = $controller->record->getDeathDate();
184
	echo '<span class="header_age">';
185
	if ($bdate->isOK() && !$controller->record->isDead()) {
186
		// If living display age
187
		echo GedcomTag::getLabelValue('AGE', FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($bdate), true), $controller->record, 'span');
188
	} elseif ($bdate->isOK() && $ddate->isOK()) {
189
		// If dead, show age at death
190
		echo GedcomTag::getLabelValue('AGE', FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($bdate, $ddate), false), $controller->record, 'span');
191
	}
192
	echo '</span>';
193
	// Display summary birth/death info.
194
	echo '<span id="dates">', $controller->record->getLifeSpan(), '</span>';
195
196
	// Display gender icon
197
	foreach ($controller->record->getFacts() as $fact) {
198
		if ($fact->getTag() == 'SEX') {
199
			$controller->printSexRecord($fact);
200
		}
201
	}
202
	echo '</h3>'; // close first name accordion header
203
204
	// Display name details
205
	foreach ($controller->record->getFacts() as $fact) {
206
		if ($fact->getTag() == 'NAME') {
207
			$controller->printNameRecord($fact);
208
		}
209
	}
210
211
	echo '</div>'; // close header_accordion1
212
}
213
echo '</div>'; // close #indi_header
214
// ===================================== main content tabs
215
foreach ($controller->tabs as $tab) {
216
	echo $tab->getPreLoadContent();
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 getPreLoadContent() 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...
217
}
218
echo '<div id="tabs">';
219
echo '<ul>';
220
foreach ($controller->tabs as $tab) {
221
	if ($tab->isGrayedOut()) {
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 isGrayedOut() 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...
222
		$greyed_out = 'rela';
223
	} else {
224
		$greyed_out = '';
225
	}
226
	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...
227
		echo '<li class="' . $greyed_out . '"><a';
228
		if ($tab->canLoadAjax()) {
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 canLoadAjax() 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...
229
			// AJAX tabs load only when selected
230
			echo ' href="' . $controller->record->getHtmlUrl(), '&amp;action=ajax&amp;module=', $tab->getName() . '"';
231
			echo ' rel="nofollow"';
232
		} else {
233
			// Non-AJAX tabs load immediately
234
			echo ' href="#', $tab->getName() . '"';
235
		}
236
		echo ' title="', $tab->getDescription(), '">', $tab->getTitle(), '</a></li>';
237
	}
238
}
239
echo '</ul>';
240
foreach ($controller->tabs as $tab) {
241
	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...
242
		if (!$tab->canLoadAjax()) {
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 canLoadAjax() 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...
243
			echo '<div id="', $tab->getName(), '">', $tab->getTabContent(), '</div>';
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 getTabContent() 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...
244
		}
245
	}
246
}
247
echo
248
	'</div>', // close #tabs
249
	'</div>'; //close indi_left
250
	if ($sidebar_html) {
251
		echo '<div id="separator" title="' . I18N::translate('Click here to open or close the sidebar') . '"></div>' . //clickable element to open/close sidebar
252
		$sidebar_html;
253
	}
254
	echo '</div>'; // close #main
255
256