GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Setup Failed
Push — master ( 1f58dd...e46154 )
by
unknown
31:29
created

src/Element.php (10 issues)

1
<?php
2
3
/**
4
 * File holding the Lingo\Element class.
5
 *
6
 * This file is part of the MediaWiki extension Lingo.
7
 *
8
 * @copyright 2011 - 2018, Stephan Gambke
9
 * @license GPL-2.0-or-later
10
 *
11
 * The Lingo extension is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by the Free
13
 * Software Foundation; either version 2 of the License, or (at your option) any
14
 * later version.
15
 *
16
 * The Lingo extension is distributed in the hope that it will be useful, but
17
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU General Public License along
22
 * with this program. If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 * @author Stephan Gambke
25
 *
26
 * @file
27
 * @ingroup Lingo
28
 */
29
30
namespace Lingo;
31
32
use DOMDocument;
33
use DOMElement;
34
use DOMText;
35
use Title;
36
37
/**
38
 * This class represents a term-definition pair.
39
 * One term may be related to several definitions.
40
 *
41
 * @ingroup Lingo
42
 */
43
class Element {
44
	const ELEMENT_TERM = 0;
45
	const ELEMENT_DEFINITION = 1;
46
	const ELEMENT_SOURCE = 2;
47
	const ELEMENT_LINK = 3;
48
	const ELEMENT_STYLE = 4;
49
50
	const ELEMENT_FIELDCOUNT = 5;  // number of fields stored for each element; (last field's index) + 1
51
52
	const LINK_TEMPLATE_ID = 'LingoLink';
53
54
	private $formattedTerm = null;
55
	private $formattedDefinitions = null;
56
57
	private $mDefinitions = [];
58
	private $mTerm = null;
59
60
	private $hasBeenDisplayed = false;
61
62
	/**
63
	 * Lingo\Element constructor.
64
	 *
65
	 * @param string $term
66
	 * @param string[] $definition
67
	 */
68 12
	public function __construct( &$term, &$definition ) {
69 12
		$this->mTerm = $term;
70 12
		$this->addDefinition( $definition );
71 12
	}
72
73
	/**
74
	 * @param array $definition
75
	 */
76 11
	public function addDefinition( &$definition ) {
77 11
		$this->mDefinitions[] = $definition + array_fill( 0, self::ELEMENT_FIELDCOUNT, null );
78 11
	}
79
80
	/**
81
	 * @param DOMDocument $doc
82
	 *
83
	 * @return DOMElement|DOMText
84
	 */
85 11
	public function getFormattedTerm( DOMDocument &$doc ) {
86 11
		global $wgexLingoDisplayOnce;
87
88 11
		if ( $wgexLingoDisplayOnce && $this->hasBeenDisplayed ) {
89 2
			return $doc->createTextNode( $this->mTerm );
90
		}
91
92 11
		$this->hasBeenDisplayed = true;
93
94 11
		$this->buildFormattedTerm( $doc );
95
96 11
		return $this->formattedTerm->cloneNode( true );
97
	}
98
99
	/**
100
	 * @param DOMDocument $doc
101
	 */
102 11
	private function buildFormattedTerm( DOMDocument &$doc ) {
103
		// only create if not yet created
104 11
		if ( $this->formattedTerm === null || $this->formattedTerm->ownerDocument !== $doc ) {
105
106 11
			if ( $this->isSimpleLink() ) {
107 7
				$this->formattedTerm = $this->buildFormattedTermAsLink( $doc );
108
			} else {
109 4
				$this->formattedTerm = $this->buildFormattedTermAsTooltip( $doc );
110
			}
111
		}
112 11
	}
113
114
	/**
115
	 * @return bool
116
	 */
117 11
	private function isSimpleLink() {
118 11
		return count( $this->mDefinitions ) === 1 &&
119 11
			!is_string( $this->mDefinitions[ 0 ][ self::ELEMENT_DEFINITION ] ) &&
120 11
			is_string( $this->mDefinitions[ 0 ][ self::ELEMENT_LINK ] );
121
	}
122
123
	/**
124
	 * @param DOMDocument $doc
125
	 * @return DOMElement
126
	 */
127 7
	protected function buildFormattedTermAsLink( DOMDocument &$doc ) {
128 7
		$linkTarget = $this->mDefinitions[ 0 ][ self::ELEMENT_LINK ];
129 7
		$descriptor = $this->getDescriptorFromLinkTarget( $linkTarget );
130
131 7
		if ( $descriptor === null ) {
0 ignored issues
show
The condition $descriptor === null is always false.
Loading history...
132 2
			$this->mDefinitions = [];
133 2
			$this->addErrorMessageForInvalidLink( $linkTarget );
134 2
			return $this->buildFormattedTermAsTooltip( $doc );
135
		}
136
137
		// create link element
138 5
		$link = $doc->createElement( 'a', htmlentities( $this->mDefinitions[ 0 ][ self::ELEMENT_TERM ] ) );
139
140
		// set the link target
141 5
		$link->setAttribute( 'href', $descriptor[ 'url' ] );
142 5
		$link->setAttribute( 'class', implode( ' ', $this->getClassesForLink( $descriptor ) ) );
143
144 5
		$title = $this->getTitleForLink( $descriptor );
145 5
		if ( $title !== null ) {
0 ignored issues
show
The condition $title !== null is always true.
Loading history...
146 4
			$link->setAttribute( 'title', $title );
147
		}
148
149 5
		return $link;
150
	}
151
152
	/**
153
	 * @param DOMDocument $doc
154
	 *
155
	 * @return DOMElement
156
	 */
157 6
	protected function buildFormattedTermAsTooltip( DOMDocument &$doc ) {
158
		// Wrap term and definition in <span> tags
159 6
		$span = $doc->createElement( 'span', htmlentities( $this->mTerm ) );
160 6
		$span->setAttribute( 'class', 'mw-lingo-term' );
161 6
		$span->setAttribute( 'data-lingo-term-id', $this->getId() );
162
163 6
		return $span;
164
	}
165
166
	/**
167
	 * @param $descriptor
168
	 *
169
	 * @return string[]
170
	 */
171 5
	protected function getClassesForLink( $descriptor ) {
172
		// TODO: should this be more elaborate?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
173
		// Cleanest would probably be to use Linker::link and parse it
174
		// back into a DOMElement, but we are in a somewhat time-critical
175
		// part here.
176
177
		// set style
178 5
		$classes = [ 'mw-lingo-term' ];
179
180 5
		$classes[] = $this->mDefinitions[ 0 ][ self::ELEMENT_STYLE ];
181
182 5
		if ( array_key_exists( 'title', $descriptor ) && $descriptor[ 'title' ] instanceof Title ) {
183
184 4
			if ( !$descriptor['title']->isKnown() ) {
185 2
				$classes[] = 'new';
186
			}
187
188 4
			if ( $descriptor['title']->isExternal() ) {
189 4
				$classes[] = 'extiw';
190
			}
191
192
		} else {
193 1
			$classes[] = 'ext';
194
		}
195
196 5
		return array_filter( $classes );
197
	}
198
199
	/**
200
	 * @param Title $target
201
	 * @param DOMElement $link
202
	 *
203
	 * @return string
204
	 */
205 5
	protected function getTitleForLink( $descriptor ) {
206
		/** @var \Title $target */
207 5
		$target = $descriptor[ 'title' ];
208
209 5
		if ( is_string( $target ) ) {
0 ignored issues
show
The condition is_string($target) is always false.
Loading history...
210 1
			return $target;
211
		}
212
213 4
		if ( $target->getPrefixedText() === '' ) {
214 1
			return null;
215
		}
216
217 3
		if ( $target->isKnown() ) {
218 1
			return $target->getPrefixedText();
219
		}
220
221 2
		return wfMessage( 'red-link-title', $target->getPrefixedText() )->text();
0 ignored issues
show
The function wfMessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

221
		return /** @scrutinizer ignore-call */ wfMessage( 'red-link-title', $target->getPrefixedText() )->text();
Loading history...
222
	}
223
224
	/**
225
	 * @return string[]
226
	 */
227 4
	public function getFormattedDefinitions() {
228 4
		if ( $this->formattedDefinitions === null ) {
229 4
			$this->buildFormattedDefinitions();
230
		}
231
232 4
		return $this->formattedDefinitions;
233
	}
234
235
	/**
236
	 */
237 4
	protected function buildFormattedDefinitions() {
238 4
		if ( $this->isSimpleLink() ) {
239 1
			$this->formattedDefinitions = '';
240 1
			return;
241
		}
242
243 3
		$divDefinitions = "<div class='mw-lingo-tooltip' id='{$this->getId()}'>";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
244
245 3
		$definition = reset( $this->mDefinitions );
246 3
		while ( $definition !== false ) {
247
248 3
			$text = $definition[ self::ELEMENT_DEFINITION ];
249 3
			$link = $definition[ self::ELEMENT_LINK ];
250 3
			$style = $definition[ self::ELEMENT_STYLE ];
251
252 3
			// navigation-not-searchable removes definition from CirrusSearch index
253
			$divDefinitions .= "<div class='mw-lingo-definition navigation-not-searchable {$style}'>"
254 3
				. "<div class='mw-lingo-definition-text'>\n{$text}\n</div>";
255
256 2
			if ( $link !== null ) {
257
258 2
				$descriptor = $this->getDescriptorFromLinkTarget( $link );
259 1
260
				if ( $descriptor === null ) {
261 1
					$this->addErrorMessageForInvalidLink( $link );
262
				} else {
263
					$divDefinitions .= "<div class='mw-lingo-definition-link'>[{$descriptor[ 'url' ]} <nowiki/>]</div>";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $descriptor instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
264
				}
265 3
			}
266
267 3
			$divDefinitions .= "</div>";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal </div> does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
268
269
			$definition = next( $this->mDefinitions );
270 3
		}
271
272 3
		$divDefinitions .= "\n</div>";
273 3
274
		$this->formattedDefinitions = $divDefinitions;
275
	}
276
277
	/**
278 6
	 * @return string
279 6
	 */
280
	public function getId() {
281
		return md5( $this->mTerm );
282
	}
283
284
	/**
285
	 * @param string $linkTarget
286
	 *
287 9
	 * @return string[]
288 9
	 */
289 1
	protected function getDescriptorFromLinkTarget( $linkTarget ) {
290
		if ( $this->isValidLinkTarget( $linkTarget ) ) {
291
			return [ 'url' => $linkTarget, 'title' => $this->mTerm ];
292 8
		}
293
294 8
		$title = Title::newFromText( $linkTarget );
295 5
296
		if ( $title !== null ) {
297
			return [ 'url' => $title->getFullURL(), 'title' => $title ];
298 3
		}
299
300
		return null;
301
	}
302
303
	/**
304
	 * @param string $linkTarget
305
	 *
306 9
	 * @return bool
307 9
	 */
308
	protected function isValidLinkTarget( $linkTarget ) {
309
		return wfParseUrl( $linkTarget ) !== false;
0 ignored issues
show
The function wfParseUrl was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

309
		return /** @scrutinizer ignore-call */ wfParseUrl( $linkTarget ) !== false;
Loading history...
310
	}
311
312
	/**
313 3
	 * @param $link
314 3
	 */
315 3
	protected function addErrorMessageForInvalidLink( $link ) {
316
		$errorMessage = wfMessage( 'lingo-invalidlinktarget', $this->mTerm, $link )->text();
0 ignored issues
show
The function wfMessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

316
		$errorMessage = /** @scrutinizer ignore-call */ wfMessage( 'lingo-invalidlinktarget', $this->mTerm, $link )->text();
Loading history...
317 3
		$errorDefinition = [ self::ELEMENT_DEFINITION => $errorMessage, self::ELEMENT_STYLE => 'invalid-link-target' ];
318 3
319
		$this->addDefinition( $errorDefinition );
320
	}
321
322
}
323