Completed
Push — master ( 1b8465...90e1da )
by mw
20:08
created

SRFTimeline::handlePropertyValue()   F

Complexity

Conditions 24
Paths 416

Size

Total Lines 91
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 600

Importance

Changes 0
Metric Value
dl 0
loc 91
ccs 0
cts 49
cp 0
rs 3.4846
c 0
b 0
f 0
cc 24
eloc 50
nc 416
nop 13
crap 600

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Print query results in interactive timelines.
4
 *
5
 * @file SRF_Timeline.php
6
 * @ingroup SemanticResultFormats
7
 *
8
 * @author Markus Krötzsch
9
 *
10
 * FIXME: this code is just insane; rewrite from 0 is probably the only way to get it right
11
 */
12
13
/**
14
 * Result printer for timeline data.
15
 * @ingroup SemanticResultFormats
16
 */
17
class SRFTimeline extends SMWResultPrinter {
18
19
	protected $m_tlstart = '';  // name of the start-date property if any
20
	protected $m_tlend = '';  // name of the end-date property if any
21
	protected $m_tlsize = ''; // CSS-compatible size (such as 400px)
22
	protected $m_tlbands = ''; // array of band IDs (MONTH, YEAR, ...)
23
	protected $m_tlpos = ''; // position identifier (start, end, today, middle)
24
	protected $mTemplate;
25
	protected $mNamedArgs;
26
27
	/**
28
	 * @see SMWResultPrinter::handleParameters
29
	 *
30
	 * @since 1.6.3
31
	 *
32
	 * @param array $params
33
	 * @param $outputmode
34
	 */
35
	protected function handleParameters( array $params, $outputmode ) {
36
		parent::handleParameters( $params, $outputmode );
37
38
		$this->mTemplate = trim( $params['template'] );
39
		$this->mNamedArgs = $params['named args'];
40
		$this->m_tlstart = smwfNormalTitleDBKey( $params['timelinestart'] );
41
		$this->m_tlend = smwfNormalTitleDBKey( $params['timelineend'] );
42
		$this->m_tlbands = $params['timelinebands'];
43
		$this->m_tlpos = strtolower( trim( $params['timelineposition'] ) );
44
45
			// str_replace makes sure this is only one value, not mutliple CSS fields (prevent CSS attacks)
46
			// / FIXME: this is either unsafe or redundant, since Timeline is Wiki-compatible. If the JavaScript makes user inputs to CSS then it is bad even if we block this injection path.
47
		$this->m_tlsize = htmlspecialchars( str_replace( ';', ' ', strtolower( $params['timelinesize'] ) ) );
48
	}
49
50
	public function getName() {
51
		// Give grep a chance to find the usages:
52
		// srf_printername_timeline, srf_printername_eventline
53
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
54
	}
55
56
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
57
58
		SMWOutputs::requireHeadItem( SMW_HEADER_STYLE );
59
		SMWOutputs::requireResource( 'ext.srf.timeline' );
60
61
		$isEventline = 'eventline' == $this->mFormat;
62
		$id = uniqid();
63
64
		if ( !$isEventline && ( $this->m_tlstart == '' ) ) { // seek defaults
65
			foreach ( $res->getPrintRequests() as $pr ) {
66
				if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) && ( $pr->getTypeID() == '_dat' ) ) {
67
					$dataValue = $pr->getData();
68
69
					$date_value = $dataValue->getDataItem()->getLabel();
70
71
					if ( ( $this->m_tlend == '' ) && ( $this->m_tlstart != '' ) &&
72
					     ( $this->m_tlstart != $date_value ) ) {
73
						$this->m_tlend = $date_value;
74
					} elseif ( ( $this->m_tlstart == '' ) && ( $this->m_tlend != $date_value ) ) {
75
						$this->m_tlstart = $date_value;
76
					}
77
				}
78
			}
79
		}
80
81
		// print header
82
		$result = "<div id=\"smwtimeline-$id\" class=\"smwtimeline is-disabled\" style=\"height: $this->m_tlsize\">";
83
		$result .= '<span class="smw-overlay-spinner medium" style="top:40%; transform: translate(-50%, -50%);"></span>';
84
85
		foreach ( $this->m_tlbands as $band ) {
0 ignored issues
show
Bug introduced by
The expression $this->m_tlbands of type string is not traversable.
Loading history...
86
			$result .= '<span class="smwtlband" style="display:none;">' . htmlspecialchars( $band ) . '</span>';
87
			// just print any "band" given, the JavaScript will figure out what to make of it
88
		}
89
90
		// print all result rows
91
		if ( ( $this->m_tlstart != '' ) || $isEventline ) {
92
			$result .= $this->getEventsHTML( $res, $outputmode, $isEventline );
93
		}
94
		// no further results displayed ...
95
96
		// print footer
97
		$result .= '</div>';
98
99
		// yes, our code can be viewed as HTML if requested, no more parsing needed
100
		$this->isHTML = $outputmode == SMW_OUTPUT_HTML;
101
102
		return $result;
103
	}
104
105
	/**
106
	 * Returns the HTML for the events.
107
	 *
108
	 * @since 1.5.3
109
	 *
110
	 * @param SMWQueryResult $res
111
	 * @param $outputmode
112
	 * @param boolean $isEventline
113
	 *
114
	 * @return string
115
	 */
116
	protected function getEventsHTML( SMWQueryResult $res, $outputmode, $isEventline ) {
117
		global $curarticle, $cururl; // why not, code flow has reached max insanity already
118
119
		$positions = []; // possible positions, collected to select one for centering
120
		$curcolor = 0; // color cycling is used for eventline
121
122
		$result = '';
123
124
		$output = false; // true if output for the popup was given on current line
125
		if ( $isEventline ) $events = []; // array of events that are to be printed
126
127
		while ( $row = $res->getNext() ) { // Loop over the objcts (pages)
128
			$hastime = false; // true as soon as some startdate value was found
129
			$hastitle = false; // true as soon as some label for the event was found
130
			$curdata = ''; // current *inner* print data (within some event span)
131
			$curmeta = ''; // current event meta data
132
			$cururl = '';
133
			$curarticle = ''; // label of current article, if it was found; needed only for eventline labeling
134
			$first_col = true;
135
136
			if ( $this->mTemplate != '' ) {
137
				$this->hasTemplates = true;
138
				$template_text = '';
139
				$wikitext = '';
0 ignored issues
show
Unused Code introduced by
$wikitext is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
140
				$i = 0;
141
			}
142
143
			foreach ( $row as $field ) { // Loop over the returned properties
144
				$first_value = true;
145
				$pr = $field->getPrintRequest();
146
				$dataValue = $pr->getData();
147
148
				if ( $dataValue == '' ) {
149
					$date_value = null;
150
				}
151
				else {
152
					$date_value = $dataValue->getDataItem()->getLabel();
153
				}
154
155
				while ( ( $object = $field->getNextDataValue() ) !== false ) { // Loop over property values
156
					$event = $this->handlePropertyValue(
157
						$object, $outputmode, $pr, $first_col, $hastitle, $hastime,
158
						$first_value, $isEventline, $curmeta, $curdata, $date_value, $output, $positions
159
					);
160
161
					if ( $this->mTemplate != '')
162
					{
163
						$template_text .= '|' . ( $this->mNamedArgs ? '?' . $field->getPrintRequest()->getLabel() : $i + 1 ) . '=';
0 ignored issues
show
Bug introduced by
The variable $template_text does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $i does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
164
						if ( !$first_value ) {
165
							$template_text .= ', ';
166
						}
167
						$template_text .= $object->getShortText( SMW_OUTPUT_WIKI, $this->getLinker( $first_value ) );
168
						$i++;
169
					}
170
171
					if ( $event !== false ) {
172
						$events[] = $event;
0 ignored issues
show
Bug introduced by
The variable $events does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
173
					}
174
175
					$first_value = false;
176
				}
177
178
				if ( $output ) {
179
					$curdata .= '<br />';
180
				}
181
182
				$output = false;
183
				$first_col = false;
184
			}
185
186
			if ( $this->mTemplate != '')
187
			{
188
				$curdata = '{{' . $this->mTemplate . $template_text . '}}';
189
			}
190
191
			if ( $hastime ) {
192
				$result .= Html::rawElement(
193
					'span',
194
					[ 'class' => 'smwtlevent', 'style' => 'display:none;' ],
195
					$curmeta . Html::element(
196
						'span',
197
						[ 'class' => 'smwtlcoloricon' ],
198
						$curcolor
199
					) . $curdata
200
				);
201
			}
202
203
			if ( $isEventline ) {
204
				foreach ( $events as $event ) {
205
					$result .= '<span class="smwtlevent" style="display:none;" ><span class="smwtlstart">' . $event[0] . '</span><span class="smwtlurl">' . str_replace( ' ', '_', $curarticle ) . '</span><span class="smwtlcoloricon">' . $curcolor . '</span>';
206
					if ( $curarticle != '' ) $result .= '<span class="smwtlprefix">' . $curarticle . ' </span>';
207
					$result .=  $curdata . '</span>';
208
					$positions[$event[2]] = $event[0];
209
				}
210
				$events = [];
211
				$curcolor = ( $curcolor + 1 ) % 10;
212
			}
213
		}
214
215
		if ( count( $positions ) > 0 ) {
216
			ksort( $positions );
217
			$positions = array_values( $positions );
218
219
			switch ( $this->m_tlpos ) {
220
				case 'start':
221
					$result .= '<span class="smwtlposition" style="display:none;" >' . $positions[0] . '</span>';
222
					break;
223
				case 'end':
224
					$result .= '<span class="smwtlposition" style="display:none;" >' . $positions[count( $positions ) - 1] . '</span>';
225
					break;
226
				case 'today': break; // default
227
				case 'middle': default:
228
					$result .= '<span class="smwtlposition" style="display:none;" >' . $positions[ceil( count( $positions ) / 2 ) - 1] . '</span>';
229
					break;
230
			}
231
		}
232
233
		return $result;
234
	}
235
236
	/**
237
	 * Hanldes a single property value. Returns an array with data for a single event or false.
238
	 *
239
	 * FIXME: 13 arguments, of which a whole bunch are byref... not a good design :)
240
	 *
241
	 * @since 1.5.3
242
	 *
243
	 * @param SMWDataValue $object
244
	 * @param $outputmode
245
	 * @param SMWPrintRequest $pr
246
	 * @param boolean $first_col
247
	 * @param boolean &$hastitle
248
	 * @param boolean &$hastime
249
	 * @param boolean $first_value
250
	 * @param boolean $isEventline
251
	 * @param string &$curmeta
252
	 * @param string &$curdata
253
	 * @param &$date_value
254
	 * @param boolean &$output
255
	 * @param array &$positions
256
	 *
257
	 * @return false or array
258
	 */
259
	protected function handlePropertyValue( SMWDataValue $object, $outputmode, SMWPrintRequest $pr, $first_col,
260
		&$hastitle, &$hastime, $first_value, $isEventline, &$curmeta, &$curdata, $date_value, &$output, array &$positions ) {
261
			global $curarticle, $cururl;
262
263
		$event = false;
264
265
		$l = $this->getLinker( $first_col );
266
267
		if ( !$hastitle && $object->getTypeID() != '_wpg' ) { // "linking" non-pages in title positions confuses timeline scripts, don't try this
268
			$l = null;
269
		}
270
271
		if ( $object->getTypeID() == '_wpg' ) { // use shorter "LongText" for wikipage
272
			$objectlabel = $object->getLongText( $outputmode, $l );
273
		} else {
274
			$objectlabel = $object->getShortText( $outputmode, $l );
275
		}
276
277
		$urlobject =  ( $l !== null );
278
		$header = '';
279
280
		if ( $first_value ) {
281
			// find header for current value:
282
			if ( $this->mShowHeaders && ( '' != $pr->getLabel() ) ) {
283
				$header = $pr->getText( $outputmode, $this->mLinker ) . ': ';
284
			}
285
286
			// is this a start date?
287
			if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) &&
288
			     ( $date_value == $this->m_tlstart ) ) {
289
				// FIXME: Timeline scripts should support XSD format explicitly. They
290
				// currently seem to implement iso8601 which deviates from XSD in cases.
291
				// NOTE: We can assume $object to be an SMWDataValue in this case.
292
				$curmeta .= Html::element(
293
					'span',
294
					[ 'class' => 'smwtlstart' ],
295
					$object->getXMLSchemaDate()
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getXMLSchemaDate() does only exist in the following sub-classes of SMWDataValue: SMWTimeValue. 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...
296
				);
297
				$positions[$object->getHash()] = $object->getXMLSchemaDate();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getXMLSchemaDate() does only exist in the following sub-classes of SMWDataValue: SMWTimeValue. 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...
298
				$hastime = true;
299
			}
300
301
			// is this the end date?
302
			if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) &&
303
			     ( $date_value == $this->m_tlend ) ) {
304
				// NOTE: We can assume $object to be an SMWDataValue in this case.
305
				$curmeta .= Html::element(
306
					'span',
307
					[ 'class' => 'smwtlend' ],
308
					$object->getXMLSchemaDate( false )
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getXMLSchemaDate() does only exist in the following sub-classes of SMWDataValue: SMWTimeValue. 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...
309
				);
310
			}
311
312
			// find title for displaying event
313
			if ( !$hastitle ) {
314
				$curmeta .= Html::element(
315
					'span',
316
					[
317
						'class' => $urlobject ? 'smwtlurl' : 'smwtltitle'
318
					],
319
					$objectlabel
320
				);
321
322
				if ( $pr->getMode() == SMWPrintRequest::PRINT_THIS ) {
323
					$curarticle = $object->getShortText( $outputmode, false );
324
					$cururl = $object->getTitle()->getFullUrl();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getTitle() does only exist in the following sub-classes of SMWDataValue: SMWWikiPageValue. 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...
325
				}
326
327
				// NOTE: type Title of $object implied
328
				$hastitle = true;
329
			}
330
		} elseif ( $output ) {
331
			// it *can* happen that output is false here, if the subject was not printed (fixed subject query) and mutliple items appear in the first row
332
			$curdata .= ', ';
333
		}
334
335
		if ( !$first_col || !$first_value || $isEventline ) {
336
			$curdata .= $header . $objectlabel;
337
			$output = true;
338
		}
339
340
		if ( $isEventline && ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) && ( $pr->getTypeID() == '_dat' ) && ( '' != $pr->getLabel() ) && ( $date_value != $this->m_tlstart ) && ( $date_value != $this->m_tlend ) ) {
341
			$event = [
342
				$object->getXMLSchemaDate(),
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getXMLSchemaDate() does only exist in the following sub-classes of SMWDataValue: SMWTimeValue. 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...
343
				$pr->getLabel(),
344
				$object->getDataItem()->getSortKey(),
345
			];
346
		}
347
348
		return $event;
349
	}
350
351
	/**
352
	 * @see SMWResultPrinter::getParamDefinitions
353
	 *
354
	 * @since 1.8
355
	 *
356
	 * @param $definitions array of IParamDefinition
357
	 *
358
	 * @return array of IParamDefinition|array
359
	 */
360
	public function getParamDefinitions( array $definitions ) {
361
		$params = parent::getParamDefinitions( $definitions );
362
363
		$params['timelinesize'] = [
364
			'default' => '300px',
365
			'message' => 'srf_paramdesc_timelinesize',
366
		];
367
368
		$params['timelineposition'] = [
369
			'default' => 'middle',
370
			'message' => 'srf_paramdesc_timelineposition',
371
			'values' => [ 'start', 'middle', 'end', 'today' ],
372
		];
373
374
		$params['timelinestart'] = [
375
			'default' => '',
376
			'message' => 'srf_paramdesc_timelinestart',
377
		];
378
379
		$params['timelineend'] = [
380
			'default' => '',
381
			'message' => 'srf_paramdesc_timelineend',
382
		];
383
384
		$params['timelinebands'] = [
385
			'islist' => true,
386
			'default' => [ 'MONTH', 'YEAR' ],
387
			'message' => 'srf_paramdesc_timelinebands',
388
			'values' => [ 'MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH', 'YEAR', 'DECADE' ],
389
		];
390
391
		$params['template'] = [
392
			'message' => 'smw-paramdesc-template',
393
			'default' => '',
394
		];
395
396
		$params['named args'] = [
397
			'type' => 'boolean',
398
			'message' => 'smw-paramdesc-named_args',
399
			'default' => false,
400
		];
401
402
403
		return $params;
404
	}
405
406
}
407