Completed
Push — master ( f310e1...4b8553 )
by mw
199:55 queued 164:55
created

SMWWikiPageValue::setQueryParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
use SMW\ApplicationFactory;
4
use SMW\DIProperty;
5
use SMW\Localizer;
6
use SMW\Message;
7
8
/**
9
 * @ingroup SMWDataValues
10
 */
11
12
/**
13
 * This datavalue implements special processing suitable for defining
14
 * wikipages as values of properties.
15
 *
16
 * The class can support general wiki pages, or pages of a fixed
17
 * namespace, Whether a namespace is fixed is decided based on the
18
 * type ID when the object is constructed.
19
 *
20
 * The short display simulates the behavior of the MediaWiki "pipe trick"
21
 * but always includes fragments. This can be overwritten by setting a
22
 * caption, which is also done by default when generating a value from user
23
 * input. The long display always includes all relevant information. Only if a
24
 * fixed namespace is used for the datatype, the namespace prefix is omitted.
25
 * This behavior has changed in SMW 1.7: up to this time, short displays have
26
 * always inlcuded the namespace and long displays used the pipe trick, leading
27
 * to a paradoxical confusion of "long" and "short".
28
 *
29
 * @author Nikolas Iwan
30
 * @author Markus Krötzsch
31
 * @ingroup SMWDataValues
32
 */
33
class SMWWikiPageValue extends SMWDataValue {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
34
35
	/**
36
	 * Fragment text for user-specified title. Not stored, but kept for
37
	 * printout on page.
38
	 * @var string
39
	 */
40
	protected $m_fragment = '';
41
42
	/**
43
	 * Full titletext with prefixes, including interwiki prefix.
44
	 * Set to empty string if not computed yet.
45
	 * @var string
46
	 */
47
	protected $m_prefixedtext = '';
48
49
	/**
50
	 * Cache for the related MW page ID.
51
	 * Set to -1 if not computed yet.
52
	 * @var integer
53
	 */
54
	protected $m_id = -1;
55
56
	/**
57
	 * Cache for the related MW title object.
58
	 * Set to null if not computed yet.
59
	 * @var Title
60
	 */
61
	protected $m_title = null;
62
63
	/**
64
	 * If this has a value other than NS_MAIN, the datavalue will only
65
	 * accept pages in this namespace. This field is initialized when
66
	 * creating the object (based on the type id or base on the preference
67
	 * of some subclass); it is not usually changed afterwards.
68
	 * @var integer
69
	 */
70
	protected $m_fixNamespace = NS_MAIN;
71
72
	/**
73
	 * @var array
74
	 */
75
	protected $linkAttributes = array();
76
77 238
	/**
78 238
	 * @var array
79
	 */
80 238
	protected $queryParameters = array();
81
82
	public function __construct( $typeid ) {
83 238
		parent::__construct( $typeid );
84 5
		switch ( $typeid ) {
85 5
			case '__typ':
86 237
				$this->m_fixNamespace = SMW_NS_TYPE;
87 40
			break;
88 40
			case '_wpp' : case '__sup':
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
89 232
				$this->m_fixNamespace = SMW_NS_PROPERTY;
90
			break;
91
			case '_wpc' : case '__suc': case '__sin':
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
92
				$this->m_fixNamespace = NS_CATEGORY;
93 232
			break;
94
			case '_wpf' : case '__spf':
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
95 238
				$this->m_fixNamespace = SF_NS_FORM;
96
			break;
97 167
			default: // case '_wpg':
98 167
				$this->m_fixNamespace = NS_MAIN;
99
		}
100
	}
101
102 167
	protected function parseUserValue( $value ) {
103
		global $wgContLang;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
104
105
		// support inputs like " [[Test]] ";
106 167
		// note that this only works in pages if $smwgLinksInValues is set to true
107 15
		$value = ltrim( rtrim( $value, ' ]' ), ' [' );
108
109
		// #1066, Manipulate the output only for when the value has no caption
110 167
		// assigned and only if a single :Foo is being present, ::Foo is not permitted
111 167
		if ( $this->m_caption === false && isset( $value[2] ) && $value[0] === ':' && $value[1] !== ':' ) {
112
			$value = substr( $value, 1 );
113
		}
114 167
115 1
		if ( $this->m_caption === false ) {
116
			$this->m_caption = $value;
117
		}
118
119
		if ( $value === '' ) {
120
			return $this->addErrorMsg( array( 'smw-datavalue-wikipage-empty' ), Message::ESCAPED );
121
		}
122
123 167
		// #1701 If the DV is part of a Description and an approximate search
124 17
		// (e.g. ~foo* / ~Foo*) then use the value as-is and avoid being
125 1
		// transformed by the Title object
126
		// If the vaue contains a valid NS then use the Title to create a correct
127 16
		// instance to distinguish [[~Foo*]] from [[Help:~Foo*]]
128
		if ( $this->getOption( self::OPT_QUERY_COMP_CONTEXT ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getOption(self::OPT_QUERY_COMP_CONTEXT) of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
129
			if ( ( $title = Title::newFromText( $value ) ) !== null && $title->getNamespace() !== NS_MAIN ) {
130
				return $this->m_dataitem = SMWDIWikiPage::newFromTitle( $title );
131 167
			} else {
132
				return $this->m_dataitem = new SMWDIWikiPage( $value, NS_MAIN );
133
			}
134
		}
135
136
		if ( $value[0] == '#' ) {
137
			if ( is_null( $this->m_contextPage ) ) {
138
				$this->addErrorMsg( array( 'smw-datavalue-wikipage-missing-fragment-context', $value ) );
139
				return;
140
			} else {
141 167
				$this->m_title = Title::makeTitle( $this->m_contextPage->getNamespace(),
142
					$this->m_contextPage->getDBkey(), substr( $value, 1 ),
143
					$this->m_contextPage->getInterwiki() );
144
			}
145 167
		} else {
146 4
			$this->m_title = Title::newFromText( $value, $this->m_fixNamespace );
147 167
		}
148 167
149
		/// TODO: Escape the text so users can see punctuation problems (bug 11666).
150
		if ( is_null( $this->m_title ) ) {
151 167
			$this->addErrorMsg( array( 'smw-datavalue-wikipage-invalid-title', $value ) );
152 167
		} elseif ( ( $this->m_fixNamespace != NS_MAIN ) &&
153 167
			 ( $this->m_fixNamespace != $this->m_title->getNamespace() ) ) {
154 167
			$this->addErrorMsg( array( 'smw_wrong_namespace', $wgContLang->getNsText( $this->m_fixNamespace ) ) );
155
		} else {
156 167
			$this->m_fragment = str_replace( ' ', '_', $this->m_title->getFragment() );
157
			$this->m_prefixedtext = '';
158
			$this->m_id = -1; // unset id
159
			$this->m_dataitem = SMWDIWikiPage::newFromTitle( $this->m_title, $this->m_typeid );
0 ignored issues
show
Unused Code introduced by
The call to SMWDIWikiPage::newFromTitle() has too many arguments starting with $this->m_typeid.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
160
		}
161
	}
162
163 184
	/**
164
	 * @see SMWDataValue::loadDataItem()
165 184
	 * @param $dataitem SMWDataItem
166
	 * @return boolean
167
	 */
168
	protected function loadDataItem( SMWDataItem $dataItem ) {
169
170 184
		if ( $dataItem->getDIType() == SMWDataItem::TYPE_CONTAINER ) {
171
			// might throw an exception, we just pass it through
172
			$dataItem = $dataItem->getSemanticData()->getSubject();
173
		}
174 184
175 184
		if ( $dataItem->getDIType() !== SMWDataItem::TYPE_WIKIPAGE ) {
176 184
			return false;
177 184
		}
178 184
179 184
		$this->m_dataitem = $dataItem;
180 184
		$this->m_id = -1;
181
		$this->m_title = null;
182 184
		$this->m_fragment = $dataItem->getSubobjectName();
183 184
		$this->m_prefixedtext = '';
184
		$this->m_caption = false; // this class can handle this
0 ignored issues
show
Documentation Bug introduced by
The property $m_caption was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
185
		$this->linkAttributes = array();
186
187
		if ( ( $this->m_fixNamespace != NS_MAIN ) &&
188
			( $this->m_fixNamespace != $dataItem->getNamespace() ) ) {
189
				$this->addErrorMsg(
190
					array(
191
						'smw_wrong_namespace',
192 184
						Localizer::getInstance()->getNamespaceTextById( $this->m_fixNamespace )
193
					)
194
				);
195
		}
196
197
		return true;
198
	}
199
200 129
	/**
201 129
	 * @since 2.4
202 129
	 *
203
	 * @param array $linkAttributes
204
	 */
205
	public function setLinkAttributes( array $linkAttributes ) {
206
		$this->linkAttributes = $linkAttributes;
207
	}
208
209
	/**
210
	 * @since 2.5
211
	 *
212
	 * @param array $queryParameters
213
	 */
214
	public function setQueryParameters( array $queryParameters ) {
215
		$this->queryParameters = $queryParameters;
216
	}
217
218
	/**
219
	 * Display the value on a wiki page. This is used to display the value
220
	 * in the place where it was annotated on a wiki page. The desired
221
	 * behavior is that the display in this case looks as if no property
222
	 * annotation had been given, i.e. an annotation [[property::page|foo]]
223
	 * should display like [[page|foo]] in MediaWiki. But this should lead
224
	 * to a link, not to a category assignment. This means that:
225
	 *
226
	 * (1) If Image: is used (instead of Media:) then let MediaWiki embed
227
	 * the image.
228 133
	 *
229
	 * (2) If Category: is used, treat it as a page and link to it (do not
230 133
	 * categorize the page)
231 128
	 *
232 133
	 * (3) Preserve everything given after "|" for display (caption, image
233 37
	 * parameters, ...)
234
	 *
235
	 * (4) Use the (default) caption for display. When the value comes from
236 128
	 * user input, this includes the full value that one would also see in
237 5
	 * MediaWiki.
238 5
	 *
239 5
	 * @param $linked mixed generate links if not null or false
240
	 * @return string
241 125
	 */
242 125
	public function getShortWikiText( $linked = null ) {
243
244
		if ( is_null( $linked ) || $linked === false ||
245 128
			$this->m_outformat == '-' || !$this->isValid() ||
246 50
			$this->m_caption === '' ) {
247
			return $this->m_caption !== false ? $this->m_caption : $this->getWikiValue();
248 121
		}
249
250
		if ( $this->m_dataitem->getNamespace() == NS_FILE && $this->m_dataitem->getInterwiki() === '' ) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getNamespace() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getInterwiki() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
251 128
			$linkEscape = '';
252 11
			$options = $this->m_outformat === false ? 'frameless|border|text-top|' : str_replace( ';', '|', \Sanitizer::removeHTMLtags( $this->m_outformat ) );
253
			$defaultCaption = '|' . $this->getShortCaptionText() . '|' . $options;
254
		} else {
255 128
			$linkEscape = ':';
256 11
			$defaultCaption = '|' . $this->getShortCaptionText();
257 11
		}
258 11
259
		if ( $this->m_caption === false ) {
260
			$link = '[[' . $linkEscape . $this->getWikiLinkTarget() . $defaultCaption . ']]';
261
		} else {
262
			$link = '[[' . $linkEscape . $this->getWikiLinkTarget() . '|' . $this->m_caption . ']]';
263 128
		}
264
265
		if ( $this->m_fragment !== '' ) {
266
			$this->linkAttributes['class'] = 'smw-subobject-entity';
267
		}
268
269
		if ( $this->linkAttributes !== array() ) {
270
			$link = \Html::rawElement(
271
				'span',
272
				$this->linkAttributes,
273 14
				$link
274
			);
275 14
		}
276
277
		return $link;
278
	}
279
280 14
	/**
281 14
	 * Display the value as in getShortWikiText() but create HTML.
282 14
	 * The only difference is that images are not embedded.
283
	 *
284
	 * @param Linker $linker mixed the Linker object to use or null if no linking is desired
285 14
	 * @return string
286 14
	 */
287
	public function getShortHTMLText( $linker = null ) {
288 2
289 2
		if ( $this->m_fragment !== '' ) {
290
			$this->linkAttributes['class'] = 'smw-subobject-entity';
291
		}
292 14
293 14
		// init the Title object, may reveal hitherto unnoticed errors:
294
		if ( !is_null( $linker ) && $linker !== false &&
295 14
				$this->m_caption !== '' && $this->m_outformat != '-' ) {
296
			$this->getTitle();
297
		}
298
299 14
		if ( is_null( $linker ) || $linker === false || !$this->isValid() ||
300 14
				$this->m_outformat == '-' || $this->m_caption === '' ) {
301
302 14
			$caption = $this->m_caption === false ? $this->getWikiValue() : $this->m_caption;
303
			return \Sanitizer::removeHTMLtags( $caption );
304
		}
305
306
		$caption = $this->m_caption === false ? $this->getShortCaptionText() : $this->m_caption;
307
		$caption =  \Sanitizer::removeHTMLtags( $caption );
308
309
		if ( $this->getNamespace() == NS_MEDIA ) { // this extra case *is* needed
310
			return $linker->makeMediaLinkObj( $this->getTitle(), $caption );
311
		}
312
313
		return $linker->link(
314 23
			$this->getTitle(),
315 23
			$caption,
316
			$this->linkAttributes,
317
			$this->queryParameters
318
		);
319 23
	}
320 9
321 17
	/**
322
	 * Display the "long" value on a wiki page. This behaves largely like
323
	 * getShortWikiText() but does not use the caption. Instead, it always
324
	 * takes the long display form (wiki value).
325
	 *
326
	 * @param $linked mixed if true the result will be linked
327
	 * @return string
328
	 */
329
	public function getLongWikiText( $linked = null ) {
330 17
		if ( !$this->isValid() ) {
331
			return $this->getErrorText();
332 17
		}
333
334
		if ( is_null( $linked ) || $linked === false || $this->m_outformat == '-' ) {
335
			return $this->getWikiValue();
336 17
		} elseif ( $this->m_dataitem->getNamespace() == NS_FILE && $this->m_dataitem->getInterwiki() === '' ) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getNamespace() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getInterwiki() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
337
			// Embed images and other files
338
			// Note that the embedded file links to the image, hence needs no additional link text.
339
			// There should not be a linebreak after an impage, just like there is no linebreak after
340
			// other values (whether formatted or not).
341
			return '[[' . $this->getWikiLinkTarget() . '|' .
342
				$this->getLongCaptionText() . '|frameless|border|text-top]]';
343
		}
344 17
345
		$link = '[[:' . $this->getWikiLinkTarget() . '|' . $this->getLongCaptionText() . ']]';
346
347
		if ( $this->m_fragment !== '' ) {
348
			$this->linkAttributes['class'] = 'smw-subobject-entity';
349
		}
350
351
		if ( $this->linkAttributes !== array() ) {
352
			$link = \Html::rawElement(
353
				'span',
354 6
				$this->linkAttributes,
355
				$link
356 6
			);
357 1
		}
358
359
		return $link;
360
	}
361 6
362 6
	/**
363
	 * Display the "long" value in HTML. This behaves largely like
364
	 * getLongWikiText() but does not embed images.
365 6
	 *
366
	 * @param $linker mixed if a Linker is given, the result will be linked
367
	 * @return string
368
	 */
369 6
	public function getLongHTMLText( $linker = null ) {
370
371 6
		if ( $this->m_fragment !== '' ) {
372
			$this->linkAttributes['class'] = 'smw-subobject-entity';
373
		}
374
375
		// init the Title object, may reveal hitherto unnoticed errors:
376
		if ( !is_null( $linker ) && ( $this->m_outformat != '-' ) ) {
377 6
			$this->getTitle();
378 6
		}
379 6
380 6
		if ( !$this->isValid() ) {
381
			return $this->getErrorText();
382
		}
383
384
		if ( $linker === null|| $linker === false || $this->m_outformat == '-' ) {
385
			return  \Sanitizer::removeHTMLtags( $this->getWikiValue() );
386
		} elseif ( $this->getNamespace() == NS_MEDIA ) { // this extra case is really needed
387
			return $linker->makeMediaLinkObj( $this->getTitle(),
388
				 \Sanitizer::removeHTMLtags( $this->getLongCaptionText() ) );
389
		}
390
391
		// all others use default linking, no embedding of images here
392
		return $linker->link(
393
			$this->getTitle(),
394 111
			 \Sanitizer::removeHTMLtags( $this->getLongCaptionText() ),
395 111
			$this->linkAttributes,
396 111
			$this->queryParameters
397
		);
398
	}
399
400
	/**
401
	 * Return a string that could be used in an in-page property assignment
402
	 * for setting this value. This does not include initial ":" for
403
	 * escaping things like Category: links since the property value does
404
	 * not include such escapes either. Fragment information is included.
405
	 * Namespaces are omitted if a fixed namespace is used, since they are
406
	 * not needed in this case when making a property assignment.
407
	 *
408
	 * @return string
409
	 */
410 1
	public function getWikiValue() {
411 1
		return ( $this->m_fixNamespace == NS_MAIN ? $this->getPrefixedText() : $this->getText() ) .
412 1
			( $this->m_fragment !== '' ? "#{$this->m_fragment}" : '' );
413
	}
414
415
	public function getHash() {
416
		return $this->isValid() ? $this->getPrefixedText() : implode( "\t", $this->getErrors() );
417
	}
418
419
	/**
420
	 * Create links to mapping services based on a wiki-editable message.
421
	 * The parameters available to the message are:
422
	 * $1: urlencoded article name (no namespace)
423
	 *
424
	 * @return array
425
	 */
426
	protected function getServiceLinkParams() {
427
		if ( $this->isValid() ) {
428
			return array( rawurlencode( str_replace( '_', ' ', $this->m_dataitem->getDBkey() ) ) );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getDBkey() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
Bug Best Practice introduced by
The return type of return array(rawurlencod...ataitem->getDBkey()))); (string[]) is incompatible with the return type of the parent method SMWDataValue::getServiceLinkParams of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
429
		} else {
430 14
			return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type of the parent method SMWDataValue::getServiceLinkParams of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
431 14
		}
432 14
	}
433
434 14
///// special interface for wiki page values
435
436
	/**
437
	 * Return according Title object or null if no valid value was set.
438
	 * null can be returned even if this object returns true for isValid(),
439
	 * since the latter function does not check whether MediaWiki can really
440
	 * make a Title out of the given data.
441
	 * However, isValid() will return false *after* this function failed in
442
	 * trying to create a title.
443
	 *
444 14
	 * @return Title
445
	 */
446
	public function getTitle() {
447
		if ( ( $this->isValid() ) && is_null( $this->m_title ) ) {
448
			$this->m_title = $this->m_dataitem->getTitle();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getTitle() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
449
450
			if ( is_null( $this->m_title ) ) { // should not normally happen, but anyway ...
451
				$this->addErrorMsg(
452
					array(
453
						'smw_notitle',
454
						Localizer::getInstance()->getNamespaceTextById( $this->m_dataitem->getNamespace() ) . ':' . $this->m_dataitem->getDBkey()
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getNamespace() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getDBkey() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
455
					)
456
				);
457
			}
458
		}
459
460
		return $this->m_title;
461
	}
462
463
	/**
464
	 * Get MediaWiki's ID for this value or 0 if not available.
465 14
	 *
466 14
	 * @return integer
467
	 */
468
	public function getArticleID() {
469
		if ( $this->m_id === false ) {
470
			$this->m_id = !is_null( $this->getTitle() ) ? $this->m_title->getArticleID() : 0;
471
		}
472
473
		return $this->m_id;
474
	}
475
476
	/**
477
	 * Get namespace constant for this value.
478
	 *
479
	 * @return integer
480
	 */
481
	public function getNamespace() {
482
		return $this->m_dataitem->getNamespace();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getNamespace() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
483
	}
484
485
	/**
486 170
	 * Get DBKey for this value. Subclasses that allow for values that do not
487 170
	 * correspond to wiki pages may choose a DB key that is not a legal title
488
	 * DB key but rather another suitable internal ID. Thus it is not suitable
489
	 * to use this method in places where only MediaWiki Title keys are allowed.
490
	 *
491
	 * @return string
492
	 */
493
	public function getDBkey() {
494
		return $this->m_dataitem->getDBkey();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getDBkey() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
495
	}
496 167
497
	/**
498 167
	 * Get text label for this value, just like Title::getText().
499 15
	 *
500
	 * @return string
501
	 */
502 167
	public function getText() {
503
		return str_replace( '_', ' ', $this->m_dataitem->getDBkey() );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getDBkey() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
504 167
	}
505 167
506 167
	/**
507 167
	 * Get the prefixed text for this value, including a localized namespace
508 167
	 * prefix.
509
	 *
510
	 * @return string
511 167
	 */
512
	public function getPrefixedText() {
513
514
		if ( $this->m_prefixedtext !== '' ) {
515
			return $this->m_prefixedtext;
516
		}
517
518
		$this->m_prefixedtext = 'NO_VALID_VALUE';
519
520
		if ( $this->isValid() ) {
521
			$nstext = Localizer::getInstance()->getNamespaceTextById( $this->m_dataitem->getNamespace() );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getNamespace() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
522
			$this->m_prefixedtext =
523
				( $this->m_dataitem->getInterwiki() !== '' ? $this->m_dataitem->getInterwiki() . ':' : '' ) .
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getInterwiki() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
524
				( $nstext !== '' ? "$nstext:" : '' ) . $this->getText();
525
		}
526
527
		return $this->m_prefixedtext;
528
	}
529
530 1
	/**
531
	 * Get interwiki prefix or empty string.
532 1
	 *
533
	 * @return string
534
	 */
535
	public function getInterwiki() {
536 1
		return $this->m_dataitem->getInterwiki();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getInterwiki() does only exist in the following sub-classes of SMWDataItem: SMWDIWikiPage, SMW\DIWikiPage. 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...
537
	}
538 1
539 1
	/**
540
	 * DataValue::getPreferredCaption
541
	 *
542 1
	 * @since 2.4
543
	 *
544
	 * @return string
545
	 */
546
	public function getPreferredCaption() {
547
548
		if ( ( $preferredCaption = parent::getPreferredCaption() ) !== '' && $preferredCaption !== false ) {
549
			return $preferredCaption;
550
		}
551
552
		$preferredCaption = $this->getDisplayTitle();
553
554
		if ( $preferredCaption === '' ) {
555 129
			$preferredCaption = $this->getText();
556 129
		}
557 1
558
		return $preferredCaption;
559 129
	}
560
561
	/**
562 129
	 * Get a short caption used to label this value. In particular, this
563 121
	 * omits namespace and interwiki prefixes (similar to the MediaWiki
564
	 * "pipe trick"). Fragments are included unless they start with an
565
	 * underscore (used for generated fragment names that are not helpful
566 51
	 * for users and that might change easily).
567
	 *
568 51
	 * @since 1.7
569 51
	 * @return string
570
	 */
571
	protected function getShortCaptionText() {
572 51
		if ( $this->m_fragment !== '' && $this->m_fragment[0] != '_' ) {
573
			$fragmentText = '#' . $this->m_fragment;
574
		} else {
575
			$fragmentText = '';
576
		}
577
578
		if ( $this->m_caption && $this->m_caption !== '' ) {
579
			return $this->m_caption;
580
		}
581
582
		$displayTitle = $this->getDisplayTitle();
583
584
		if ( $displayTitle === '' ) {
585 23
			$displayTitle = $this->getText();
586 23
		}
587 1
588
		return $displayTitle . $fragmentText;
589 23
	}
590
591
	/**
592 23
	 * Get a long caption used to label this value. In particular, this
593 13
	 * includes namespace and interwiki prefixes, while fragments are only
594
	 * included if they do not start with an underscore (used for generated
595
	 * fragment names that are not helpful for users and that might change
596 10
	 * easily).
597
	 *
598 10
	 * @since 1.7
599 10
	 * @return string
600
	 */
601
	protected function getLongCaptionText() {
602 10
		if ( $this->m_fragment !== '' && $this->m_fragment[0] != '_' ) {
603
			$fragmentText = '#' . $this->m_fragment;
604
		} else {
605
			$fragmentText = '';
606
		}
607
608
		if ( $this->m_caption && $this->m_caption !== '' ) {
609
			return $this->m_caption;
610
		}
611
612
		$displayTitle = $this->getDisplayTitle();
613 133
614 133
		if ( $displayTitle === '' ) {
615 133
			$displayTitle = $this->m_fixNamespace == NS_MAIN ? $this->getPrefixedText() : $this->getText();
616
		}
617
618
		return $displayTitle . $fragmentText;
619
	}
620
621
	/**
622
	 * Compute a text that can be used in wiki text to link to this
623
	 * datavalue. Processing includes some escaping and adding the
624
	 * fragment.
625
	 *
626
	 * @since 1.7
627
	 * @return string
628
	 */
629
	protected function getWikiLinkTarget() {
630
		return str_replace( "'", '&#x0027;', $this->getPrefixedText() ) .
631
			( $this->m_fragment !== '' ? "#{$this->m_fragment}" : '' );
632
	}
633
634 109
	/**
635
	 * Find the sortkey for this object.
636 109
	 *
637 5
	 * @deprecated Use SMWStore::getWikiPageSortKey(). Will vanish before SMW 1.7
638
	 *
639
	 * @return string sortkey
640 105
	 */
641
	public function getSortKey() {
642
		return ApplicationFactory::getInstance()->getStore()->getWikiPageSortKey( $this->m_dataitem );
0 ignored issues
show
Compatibility introduced by
$this->m_dataitem of type object<SMWDataItem> is not a sub-type of object<SMW\DIWikiPage>. It seems like you assume a child class of the class SMWDataItem to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
643
	}
644
645
	/**
646
	 * @since 2.4
647
	 *
648
	 * @return string
649
	 */
650
	public function getDisplayTitle() {
651
652
		if ( $this->m_dataitem === null || !$this->isEnabledFeature( SMW_DV_WPV_DTITLE ) ) {
653
			return '';
654
		}
655
656
		return $this->findDisplayTitleFor( $this->m_dataitem );
657
	}
658
659
	/**
660
	 * Static function for creating a new wikipage object from
661
	 * data as it is typically stored internally. In particular,
662
	 * the title string is supposed to be in DB key form.
663
	 *
664
	 * @note The resulting wikipage object might be invalid if
665
	 * the provided title is not allowed. An object is returned
666
	 * in any case.
667
	 *
668
	 * @deprecated This method will vanish before SMW 1.7. If you really need this, simply copy its code.
669
	 *
670
	 * @return SMWWikiPageValue
671
	 */
672
	static public function makePage( $dbkey, $namespace, $ignoredParameter = '', $interwiki = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $ignoredParameter is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
673
		$diWikiPage = new SMWDIWikiPage( $dbkey, $namespace, $interwiki );
674
		$dvWikiPage = new SMWWikiPageValue( '_wpg' );
675
		$dvWikiPage->setDataItem( $diWikiPage );
676
		return $dvWikiPage;
677
	}
678
679 105
	/**
680
	 * Static function for creating a new wikipage object from a
681 105
	 * MediaWiki Title object.
682
	 *
683 105
	 * @deprecated This method will vanish before SMW 1.7. If you really need this, simply copy its code.
684
	 *
685 105
	 * @return SMWWikiPageValue
686
	 */
687
	static public function makePageFromTitle( Title $title ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
688 105
		$dvWikiPage = new SMWWikiPageValue( '_wpg' );
689 5
		$diWikiPage = SMWDIWikiPage::newFromTitle( $title );
690 104
		$dvWikiPage->setDataItem( $diWikiPage );
691
		$dvWikiPage->m_title = $title; // optional, just for efficiency
692 12
		return $dvWikiPage;
693
	}
694
695 105
	private function findDisplayTitleFor( $subject ) {
696
697
		$displayTitle = '';
698
699
		$dataItems = ApplicationFactory::getInstance()->getCachedPropertyValuesPrefetcher()->getPropertyValues(
700
			$subject,
701
			new DIProperty( '_DTITLE' )
702
		);
703
704
		if ( $dataItems !== null && $dataItems !== array() ) {
705
			$displayTitle = end( $dataItems )->getString();
706
		} elseif ( $subject->getSubobjectName() !== '' ) {
707
			// Check whether the base subject has a DISPLAYTITLE
708
			return $this->findDisplayTitleFor( $subject->asBase() );
709
		}
710
711
		return $displayTitle;
712
	}
713
714
}
715