Completed
Push — master ( 5d1976...30add5 )
by mw
13s
created

SMWWikiPageValue::getLongWikiText()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 15.7829

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 32
ccs 9
cts 16
cp 0.5625
rs 4.909
cc 9
eloc 17
nc 7
nop 1
crap 15.7829
1
<?php
2
3
use SMW\ApplicationFactory;
4
use SMW\DIProperty;
5
6
/**
7
 * @ingroup SMWDataValues
8
 */
9
10
/**
11
 * This datavalue implements special processing suitable for defining
12
 * wikipages as values of properties.
13
 *
14
 * The class can support general wiki pages, or pages of a fixed
15
 * namespace, Whether a namespace is fixed is decided based on the
16
 * type ID when the object is constructed.
17
 *
18
 * The short display simulates the behavior of the MediaWiki "pipe trick"
19
 * but always includes fragments. This can be overwritten by setting a
20
 * caption, which is also done by default when generating a value from user
21
 * input. The long display always includes all relevant information. Only if a
22
 * fixed namespace is used for the datatype, the namespace prefix is omitted.
23
 * This behavior has changed in SMW 1.7: up to this time, short displays have
24
 * always inlcuded the namespace and long displays used the pipe trick, leading
25
 * to a paradoxical confusion of "long" and "short".
26
 *
27
 * @author Nikolas Iwan
28
 * @author Markus Krötzsch
29
 * @ingroup SMWDataValues
30
 */
31
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...
32
33
	/**
34
	 * Fragment text for user-specified title. Not stored, but kept for
35
	 * printout on page.
36
	 * @var string
37
	 */
38
	protected $m_fragment = '';
39
40
	/**
41
	 * Full titletext with prefixes, including interwiki prefix.
42
	 * Set to empty string if not computed yet.
43
	 * @var string
44
	 */
45
	protected $m_prefixedtext = '';
46
47
	/**
48
	 * Cache for the related MW page ID.
49
	 * Set to -1 if not computed yet.
50
	 * @var integer
51
	 */
52
	protected $m_id = -1;
53
54
	/**
55
	 * Cache for the related MW title object.
56
	 * Set to null if not computed yet.
57
	 * @var Title
58
	 */
59
	protected $m_title = null;
60
61
	/**
62
	 * If this has a value other than NS_MAIN, the datavalue will only
63
	 * accept pages in this namespace. This field is initialized when
64
	 * creating the object (based on the type id or base on the preference
65
	 * of some subclass); it is not usually changed afterwards.
66
	 * @var integer
67
	 */
68
	protected $m_fixNamespace = NS_MAIN;
69
70
	/**
71
	 * @var array
72
	 */
73
	protected $linkAttributes = array();
74
75 175
	public function __construct( $typeid ) {
76 175
		parent::__construct( $typeid );
77
		switch ( $typeid ) {
78 175
			case '__typ':
79
				$this->m_fixNamespace = SMW_NS_TYPE;
80
			break;
81 175
			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...
82 4
				$this->m_fixNamespace = SMW_NS_PROPERTY;
83 4
			break;
84 174
			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...
85 25
				$this->m_fixNamespace = NS_CATEGORY;
86 25
			break;
87 169
			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...
88
				$this->m_fixNamespace = SF_NS_FORM;
89
			break;
90
			default: // case '_wpg':
91 169
				$this->m_fixNamespace = NS_MAIN;
92
		}
93 175
	}
94
95 124
	protected function parseUserValue( $value ) {
96 124
		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...
97
98
		// support inputs like " [[Test]] ";
99
		// note that this only works in pages if $smwgLinksInValues is set to true
100 124
		$value = ltrim( rtrim( $value, ' ]' ), ' [' );
101
102
		// #1066, Manipulate the output only for when the value has no caption
103
		// assigned and only if a single :Foo is being present, ::Foo is not permitted
104 124
		if ( $this->m_caption === false && isset( $value[2] ) && $value[0] === ':' && $value[1] !== ':' ) {
105 7
			$value = substr( $value, 1 );
106
		}
107
108 124
		if ( $this->m_caption === false ) {
109 124
			$this->m_caption = $value;
110
		}
111
112 124
		if ( $value !== '' ) {
113 124
			if ( $value[0] == '#' ) {
114
				if ( is_null( $this->m_contextPage ) ) {
115
					$this->addError( wfMessage( 'smw_notitle', $value )->inContentLanguage()->text() );
116
					return;
117
				} else {
118
					$this->m_title = Title::makeTitle( $this->m_contextPage->getNamespace(),
119
						$this->m_contextPage->getDBkey(), substr( $value, 1 ),
120
						$this->m_contextPage->getInterwiki() );
121
				}
122
			} else {
123 124
				$this->m_title = Title::newFromText( $value, $this->m_fixNamespace );
124
			}
125
126
			/// TODO: Escape the text so users can see punctuation problems (bug 11666).
127 124
			if ( is_null( $this->m_title ) ) {
128 5
				$this->addError( wfMessage( 'smw_notitle', $value )->inContentLanguage()->text() );
129 124
			} elseif ( ( $this->m_fixNamespace != NS_MAIN ) &&
130 124
				 ( $this->m_fixNamespace != $this->m_title->getNamespace() ) ) {
131
				$this->addError( wfMessage( 'smw_wrong_namespace',
132
					$wgContLang->getNsText( $this->m_fixNamespace ) )->inContentLanguage()->text() );
133
			} else {
134 124
				$this->m_fragment = str_replace( ' ', '_', $this->m_title->getFragment() );
135 124
				$this->m_prefixedtext = '';
136 124
				$this->m_id = -1; // unset id
137 124
				$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...
138
			}
139
		} else {
140
			$this->addError(  wfMessage( 'smw_notitle', $value )->inContentLanguage()->text() );
141
		}
142 124
	}
143
144
	/**
145
	 * @see SMWDataValue::loadDataItem()
146
	 * @param $dataitem SMWDataItem
147
	 * @return boolean
148
	 */
149 121
	protected function loadDataItem( SMWDataItem $dataItem ) {
150 121
		if ( $dataItem->getDIType() == SMWDataItem::TYPE_CONTAINER ) {
151
			// might throw an exception, we just pass it through
152
			$dataItem = $dataItem->getSemanticData()->getSubject();
153
		}
154
155 121
		if ( $dataItem->getDIType() !== SMWDataItem::TYPE_WIKIPAGE ) {
156
			return false;
157
		}
158
159 121
		$this->m_dataitem = $dataItem;
160 121
		$this->m_id = -1;
161 121
		$this->m_title = null;
162 121
		$this->m_fragment = $dataItem->getSubobjectName();
163 121
		$this->m_prefixedtext = '';
164 121
		$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...
165 121
		$this->linksAttributes = array();
0 ignored issues
show
Bug introduced by
The property linksAttributes does not seem to exist. Did you mean linkAttributes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
166
167 121
		if ( ( $this->m_fixNamespace != NS_MAIN ) &&
168 121
			( $this->m_fixNamespace != $dataItem->getNamespace() ) ) {
169
				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...
170
				$this->addError( wfMessage( 'smw_wrong_namespace',
171
					$wgContLang->getNsText( $this->m_fixNamespace ) )->inContentLanguage()->text() );
172
		}
173
174 121
		return true;
175
	}
176
177
	/**
178
	 * @since 2.4
179
	 *
180
	 * @param array $linkAttributes
181
	 */
182 85
	public function setLinkAttributes( array $linkAttributes ) {
183 85
		$this->linkAttributes = $linkAttributes;
184 85
	}
185
186
	/**
187
	 * Display the value on a wiki page. This is used to display the value
188
	 * in the place where it was annotated on a wiki page. The desired
189
	 * behavior is that the display in this case looks as if no property
190
	 * annotation had been given, i.e. an annotation [[property::page|foo]]
191
	 * should display like [[page|foo]] in MediaWiki. But this should lead
192
	 * to a link, not to a category assignment. This means that:
193
	 *
194
	 * (1) If Image: is used (instead of Media:) then let MediaWiki embed
195
	 * the image.
196
	 *
197
	 * (2) If Category: is used, treat it as a page and link to it (do not
198
	 * categorize the page)
199
	 *
200
	 * (3) Preserve everything given after "|" for display (caption, image
201
	 * parameters, ...)
202
	 *
203
	 * (4) Use the (default) caption for display. When the value comes from
204
	 * user input, this includes the full value that one would also see in
205
	 * MediaWiki.
206
	 *
207
	 * @param $linked mixed generate links if not null or false
208
	 * @return string
209
	 */
210 95
	public function getShortWikiText( $linked = null ) {
211
212 95
		if ( is_null( $linked ) || $linked === false ||
213 93
			$this->m_outformat == '-' || !$this->isValid() ||
214 95
			$this->m_caption === '' ) {
215 22
			return $this->m_caption !== false ? $this->m_caption : $this->getWikiValue();
216
		}
217
218 93
		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...
219 3
			$linkEscape = '';
220 3
			$defaultCaption = '|' . $this->getShortCaptionText() . '|frameless|border|text-top';
221
		} else {
222 91
			$linkEscape = ':';
223 91
			$defaultCaption = '|' . $this->getShortCaptionText();
224
		}
225
226 93
		if ( $this->m_caption === false ) {
227 29
			$link = '[[' . $linkEscape . $this->getWikiLinkTarget() . $defaultCaption . ']]';
228
		} else {
229 87
			$link = '[[' . $linkEscape . $this->getWikiLinkTarget() . '|' . $this->m_caption . ']]';
230
		}
231
232 93
		if ( $this->m_fragment !== '' ) {
233 7
			$this->linkAttributes['class'] = 'smw-subobject-entity';
234
		}
235
236 93
		if ( $this->linkAttributes !== array() ) {
237 7
			$link = \Html::rawElement(
238 7
				'span',
239 7
				$this->linkAttributes,
240
				$link
241
			);
242
		}
243
244 93
		return $link;
245
	}
246
247
	/**
248
	 * Display the value as in getShortWikiText() but create HTML.
249
	 * The only difference is that images are not embedded.
250
	 *
251
	 * @param Linker $linker mixed the Linker object to use or null if no linking is desired
252
	 * @return string
253
	 */
254 3
	public function getShortHTMLText( $linker = null ) {
255
256 3
		if ( $this->m_fragment !== '' ) {
257
			$this->linkAttributes['class'] = 'smw-subobject-entity';
258
		}
259
260
		// init the Title object, may reveal hitherto unnoticed errors:
261 3
		if ( !is_null( $linker ) && $linker !== false &&
262 3
				$this->m_caption !== '' && $this->m_outformat != '-' ) {
263 2
			$this->getTitle();
264
		}
265
266 3
		$displayTitle = $this->getDisplayTitle();
267
268 3
		if ( $displayTitle !== '' && $linker === null ) {
269
			return htmlspecialchars( $displayTitle );
270
		}
271
272 3
		if ( is_null( $linker ) || $linker === false || !$this->isValid() ||
273 3
				$this->m_outformat == '-' || $this->m_caption === '' ) {
274
275 1
			$caption = $this->m_caption === false ? $this->getWikiValue() : $this->m_caption;
276 1
			return htmlspecialchars( $caption );
277
		}
278
279 2
		$caption = $this->m_caption === false ? $this->getShortCaptionText() : $this->m_caption;
280 2
		$caption = htmlspecialchars( $caption );
281
282 2
		if ( $this->getNamespace() == NS_MEDIA ) { // this extra case *is* needed
283
			return $linker->makeMediaLinkObj( $this->getTitle(), $caption );
284
		}
285
286 2
		return $linker->link(
287 2
			$this->getTitle(),
288
			$caption,
289 2
			$this->linkAttributes
290
		);
291
	}
292
293
	/**
294
	 * Display the "long" value on a wiki page. This behaves largely like
295
	 * getShortWikiText() but does not use the caption. Instead, it always
296
	 * takes the long display form (wiki value).
297
	 *
298
	 * @param $linked mixed if true the result will be linked
299
	 * @return string
300
	 */
301 12
	public function getLongWikiText( $linked = null ) {
302 12
		if ( !$this->isValid() ) {
303
			return $this->getErrorText();
304
		}
305
306 12
		if ( is_null( $linked ) || $linked === false || $this->m_outformat == '-' ) {
307 3
			return $this->getWikiValue();
308 11
		} 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...
309
			// Embed images and other files
310
			// Note that the embedded file links to the image, hence needs no additional link text.
311
			// There should not be a linebreak after an impage, just like there is no linebreak after
312
			// other values (whether formatted or not).
313
			return '[[' . $this->getWikiLinkTarget() . '|' .
314
				$this->getLongCaptionText() . '|frameless|border|text-top]]';
315
		}
316
317 11
		$link = '[[:' . $this->getWikiLinkTarget() . '|' . $this->getLongCaptionText() . ']]';
318
319 11
		if ( $this->m_fragment !== '' ) {
320
			$this->linkAttributes['class'] = 'smw-subobject-entity';
321
		}
322
323 11
		if ( $this->linkAttributes !== array() ) {
324
			$link = \Html::rawElement(
325
				'span',
326
				$this->linkAttributes,
327
				$link
328
			);
329
		}
330
331 11
		return $link;
332
	}
333
334
	/**
335
	 * Display the "long" value in HTML. This behaves largely like
336
	 * getLongWikiText() but does not embed images.
337
	 *
338
	 * @param $linker mixed if a Linker is given, the result will be linked
339
	 * @return string
340
	 */
341 1
	public function getLongHTMLText( $linker = null ) {
342
343 1
		if ( $this->m_fragment !== '' ) {
344
			$this->linkAttributes['class'] = 'smw-subobject-entity';
345
		}
346
347
		// init the Title object, may reveal hitherto unnoticed errors:
348 1
		if ( !is_null( $linker ) && ( $this->m_outformat != '-' ) ) {
349 1
			$this->getTitle();
350
		}
351
352 1
		if ( !$this->isValid() ) {
353
			return $this->getErrorText();
354
		}
355
356 1
		if ( is_null( $linker ) || $this->m_outformat == '-' ) {
357
			return htmlspecialchars( $this->getWikiValue() );
358 1
		} elseif ( $this->getNamespace() == NS_MEDIA ) { // this extra case is really needed
359
			return $linker->makeMediaLinkObj( $this->getTitle(),
360
				htmlspecialchars( $this->getLongCaptionText() ) );
361
		}
362
363
		// all others use default linking, no embedding of images here
364 1
		return $linker->link(
365 1
			$this->getTitle(),
366 1
			htmlspecialchars( $this->getLongCaptionText() ),
367 1
			$this->linkAttributes
368
		);
369
	}
370
371
	/**
372
	 * Return a string that could be used in an in-page property assignment
373
	 * for setting this value. This does not include initial ":" for
374
	 * escaping things like Category: links since the property value does
375
	 * not include such escapes either. Fragment information is included.
376
	 * Namespaces are omitted if a fixed namespace is used, since they are
377
	 * not needed in this case when making a property assignment.
378
	 *
379
	 * @return string
380
	 */
381 75
	public function getWikiValue() {
382 75
		return ( $this->m_fixNamespace == NS_MAIN ? $this->getPrefixedText() : $this->getText() ) .
383 75
			( $this->m_fragment !== '' ? "#{$this->m_fragment}" : '' );
384
	}
385
386
	public function getHash() {
387
		return $this->isValid() ? $this->getPrefixedText() : implode( "\t", $this->getErrors() );
388
	}
389
390
	/**
391
	 * Create links to mapping services based on a wiki-editable message.
392
	 * The parameters available to the message are:
393
	 * $1: urlencoded article name (no namespace)
394
	 *
395
	 * @return array
396
	 */
397
	protected function getServiceLinkParams() {
398
		if ( $this->isValid() ) {
399
			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...
400
		} else {
401
			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...
402
		}
403
	}
404
405
///// special interface for wiki page values
406
407
	/**
408
	 * Return according Title object or null if no valid value was set.
409
	 * null can be returned even if this object returns true for isValid(),
410
	 * since the latter function does not check whether MediaWiki can really
411
	 * make a Title out of the given data.
412
	 * However, isValid() will return false *after* this function failed in
413
	 * trying to create a title.
414
	 *
415
	 * @return Title
416
	 */
417 2
	public function getTitle() {
418 2
		if ( ( $this->isValid() ) && is_null( $this->m_title ) ) {
419 2
			$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...
420
421 2
			if ( is_null( $this->m_title ) ) { // should not normally happen, but anyway ...
422
				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...
423
				$this->addError( wfMessage(
424
					'smw_notitle',
425
					$wgContLang->getNsText( $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...
426
				)->inContentLanguage()->text() );
427
			}
428
		}
429
430 2
		return $this->m_title;
431
	}
432
433
	/**
434
	 * Get MediaWiki's ID for this value or 0 if not available.
435
	 *
436
	 * @return integer
437
	 */
438
	public function getArticleID() {
439
		if ( $this->m_id === false ) {
440
			$this->m_id = !is_null( $this->getTitle() ) ? $this->m_title->getArticleID() : 0;
441
		}
442
443
		return $this->m_id;
444
	}
445
446
	/**
447
	 * Get namespace constant for this value.
448
	 *
449
	 * @return integer
450
	 */
451 2
	public function getNamespace() {
452 2
		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...
453
	}
454
455
	/**
456
	 * Get DBKey for this value. Subclasses that allow for values that do not
457
	 * correspond to wiki pages may choose a DB key that is not a legal title
458
	 * DB key but rather another suitable internal ID. Thus it is not suitable
459
	 * to use this method in places where only MediaWiki Title keys are allowed.
460
	 *
461
	 * @return string
462
	 */
463
	public function getDBkey() {
464
		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...
465
	}
466
467
	/**
468
	 * Get text label for this value, just like Title::getText().
469
	 *
470
	 * @return string
471
	 */
472 124
	public function getText() {
473 124
		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...
474
	}
475
476
	/**
477
	 * Get the prefixed text for this value, including a localized namespace
478
	 * prefix.
479
	 *
480
	 * @return string
481
	 */
482 117
	public function getPrefixedText() {
483 117
		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...
484 117
		if ( $this->m_prefixedtext === '' ) {
485 117
			if ( $this->isValid() ) {
486 117
				$nstext = $wgContLang->getNSText( $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...
487 117
				$this->m_prefixedtext =
488 117
					( $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...
489 117
						$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...
490 117
					( $nstext !== '' ? "$nstext:" : '' ) . $this->getText();
491
			} else {
492
				$this->m_prefixedtext = 'NO_VALID_VALUE';
493
			}
494
		}
495 117
		return $this->m_prefixedtext;
496
	}
497
498
	/**
499
	 * Get interwiki prefix or empty string.
500
	 *
501
	 * @return string
502
	 */
503
	public function getInterwiki() {
504
		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...
505
	}
506
507
	/**
508
	 * Get a short caption used to label this value. In particular, this
509
	 * omits namespace and interwiki prefixes (similar to the MediaWiki
510
	 * "pipe trick"). Fragments are included unless they start with an
511
	 * underscore (used for generated fragment names that are not helpful
512
	 * for users and that might change easily).
513
	 *
514
	 * @since 1.7
515
	 * @return string
516
	 */
517 94
	protected function getShortCaptionText() {
518 94
		if ( $this->m_fragment !== '' && $this->m_fragment[0] != '_' ) {
519 1
			$fragmentText = '#' . $this->m_fragment;
520
		} else {
521 94
			$fragmentText = '';
522
		}
523
524 94
		$displayTitle = $this->getDisplayTitle();
525
526 94
		if ( $displayTitle === '' ) {
527 94
			$displayTitle = $this->getText();
528
		}
529
530 94
		return $displayTitle . $fragmentText;
531
	}
532
533
	/**
534
	 * Get a long caption used to label this value. In particular, this
535
	 * includes namespace and interwiki prefixes, while fragments are only
536
	 * included if they do not start with an underscore (used for generated
537
	 * fragment names that are not helpful for users and that might change
538
	 * easily).
539
	 *
540
	 * @since 1.7
541
	 * @return string
542
	 */
543 12
	protected function getLongCaptionText() {
544 12
		if ( $this->m_fragment !== '' && $this->m_fragment[0] != '_' ) {
545
			$fragmentText = '#' . $this->m_fragment;
546
		} else {
547 12
			$fragmentText = '';
548
		}
549
550 12
		$displayTitle = $this->getDisplayTitle();
551
552 12
		if ( $displayTitle === '' ) {
553 12
			$displayTitle = $this->m_fixNamespace == NS_MAIN ? $this->getPrefixedText() : $this->getText();
554
		}
555
556 12
		return $displayTitle . $fragmentText;
557
	}
558
559
	/**
560
	 * Compute a text that can be used in wiki text to link to this
561
	 * datavalue. Processing includes some escaping and adding the
562
	 * fragment.
563
	 *
564
	 * @since 1.7
565
	 * @return string
566
	 */
567 97
	protected function getWikiLinkTarget() {
568 97
		return str_replace( "'", '&#x0027;', $this->getPrefixedText() ) .
569 97
			( $this->m_fragment !== '' ? "#{$this->m_fragment}" : '' );
570
	}
571
572
	/**
573
	 * Find the sortkey for this object.
574
	 *
575
	 * @deprecated Use SMWStore::getWikiPageSortKey(). Will vanish before SMW 1.7
576
	 *
577
	 * @return string sortkey
578
	 */
579
	public function getSortKey() {
580
		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...
581
	}
582
583
	/**
584
	 * @since 2.4
585
	 *
586
	 * @return string
587
	 */
588 107
	public function getDisplayTitle() {
589
590 107
		if ( $this->m_dataitem === null || !$this->isEnabledFeature( SMW_DV_WPV_DTITLE ) ) {
591
			return '';
592
		}
593
594 107
		return $this->findDisplayTitleFor( $this->m_dataitem );
595
	}
596
597
	/**
598
	 * Static function for creating a new wikipage object from
599
	 * data as it is typically stored internally. In particular,
600
	 * the title string is supposed to be in DB key form.
601
	 *
602
	 * @note The resulting wikipage object might be invalid if
603
	 * the provided title is not allowed. An object is returned
604
	 * in any case.
605
	 *
606
	 * @deprecated This method will vanish before SMW 1.7. If you really need this, simply copy its code.
607
	 *
608
	 * @return SMWWikiPageValue
609
	 */
610
	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...
611
		$diWikiPage = new SMWDIWikiPage( $dbkey, $namespace, $interwiki );
612
		$dvWikiPage = new SMWWikiPageValue( '_wpg' );
613
		$dvWikiPage->setDataItem( $diWikiPage );
614
		return $dvWikiPage;
615
	}
616
617
	/**
618
	 * Static function for creating a new wikipage object from a
619
	 * MediaWiki Title object.
620
	 *
621
	 * @deprecated This method will vanish before SMW 1.7. If you really need this, simply copy its code.
622
	 *
623
	 * @return SMWWikiPageValue
624
	 */
625
	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...
626
		$dvWikiPage = new SMWWikiPageValue( '_wpg' );
627
		$diWikiPage = SMWDIWikiPage::newFromTitle( $title );
628
		$dvWikiPage->setDataItem( $diWikiPage );
629
		$dvWikiPage->m_title = $title; // optional, just for efficiency
630
		return $dvWikiPage;
631
	}
632
633 107
	private function findDisplayTitleFor( $subject ) {
634
635 107
		$displayTitle = '';
636
637 107
		$dataItems = ApplicationFactory::getInstance()->getCachedPropertyValuesPrefetcher()->getPropertyValues(
638
			$subject,
639 107
			new DIProperty( '_DTITLE' )
640
		);
641
642 107
		if ( $dataItems !== null && $dataItems !== array() ) {
643 1
			$displayTitle = end( $dataItems )->getString();
644 107
		} elseif ( $subject->getSubobjectName() !== '' ) {
645
			// Check whether the base subject has a DISPLAYTITLE
646 7
			return $this->findDisplayTitleFor( $subject->asBase() );
647
		}
648
649 107
		return $displayTitle;
650
	}
651
652
}
653