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

SRFTimeline::getResultText()   C

Complexity

Conditions 14
Paths 8

Size

Total Lines 48
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 210

Importance

Changes 0
Metric Value
dl 0
loc 48
ccs 0
cts 31
cp 0
rs 5.0498
c 0
b 0
f 0
cc 14
eloc 24
nc 8
nop 2
crap 210

How to fix   Complexity   

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:

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