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.

BasicBackend::processNextGlossaryLine()   A
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 21
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 1
b 0
f 0
nc 6
nop 3
dl 0
loc 21
ccs 10
cts 10
cp 1
crap 5
rs 9.6111
1
<?php
2
3
/**
4
 * File holding the Lingo\Backend 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
 * @file
26
 * @ingroup Lingo
27
 */
28
namespace Lingo;
29
30
use ApprovedRevs;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type ApprovedRevs was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use Hooks;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type Hooks was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
use Parser;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type Parser was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
use ParserOptions;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type ParserOptions was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use Revision;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type Revision was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
use TextContent;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type TextContent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
36
use Title;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type Title was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
use User;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type User was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
use WikiPage;
0 ignored issues
show
Bug introduced by Stephan Gambke
The type WikiPage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
39
40
/**
41
 * The Lingo\BasicBackend class.
42
 *
43
 * @ingroup Lingo
44
 */
45
class BasicBackend extends Backend {
46
47
	protected $mArticleLines = null;
48
49
	/**
50
	 * Lingo\BasicBackend constructor.
51
	 * @param MessageLog|null &$messages
52
	 */
53 1
	public function __construct( MessageLog &$messages = null ) {
54 1
		parent::__construct( $messages );
55
56 1
		$this->registerHooks();
57 1
	}
58
59 17
	protected function registerHooks() {
60 17
		Hooks::register( 'ArticlePurge', [ $this, 'purgeCache' ] );
61 17
		Hooks::register( 'PageContentSave', [ $this, 'purgeCache' ] );
62 17
	}
63
64
	/**
65
	 * This function returns the next element. The element is an array of four
66
	 * strings: Term, Definition, Link, Source. For the Lingo\BasicBackend Link
67
	 * and Source are set to null. If there is no next element the function
68
	 * returns null.
69
	 *
70
	 * @return array|null
71
	 * @throws \MWException
72
	 */
73 7
	public function next() {
74 7
		static $term = null;
75 7
		static $definitions = [];
76 7
		static $ret = [];
77
78 7
		$this->collectDictionaryLines();
79
80
		// loop backwards: accumulate definitions until term found
81 7
		while ( ( count( $ret ) === 0 ) && ( $this->mArticleLines ) ) {
82
83 7
			$line = array_pop( $this->mArticleLines );
84
85 7
			if ( $this->isValidGlossaryLine( $line ) ) {
86
87 6
				list( $term, $definitions ) = $this->processNextGlossaryLine( $line, $term, $definitions );
88
89 6
				if ( $term !== null ) {
90 6
					$ret = $this->queueDefinitions( $definitions, $term );
91
				}
92
			}
93
		}
94
95 7
		return array_pop( $ret );
96
	}
97
98
	/**
99
	 * @param string $line
100
	 * @param string $term
101
	 * @param string[] $definitions
102
	 * @return array
103
	 */
104 9
	protected function processNextGlossaryLine( $line, $term, $definitions ) {
105 9
		$chunks = explode( ':', $line, 2 );
106
107
		// found a new definition?
108 9
		if ( count( $chunks ) === 2 ) {
109
110
			// wipe the data if it's a totally new term definition
111 9
			if ( !empty( $term ) && count( $definitions ) > 0 ) {
112 9
				$definitions = [];
113 9
				$term = null;
114
			}
115
116 9
			$definitions[] = trim( $chunks[ 1 ] );
117
		}
118
119
		// found a new term?
120 9
		if ( strlen( trim( $chunks[ 0 ] ) ) > 1 ) {
121 9
			$term = trim( substr( $chunks[ 0 ], 1 ) );
122
		}
123
124 9
		return [ $term, $definitions ];
125
	}
126
127
	/**
128
	 * @param string[] $definitions
129
	 * @param string $term
130
	 * @return array
131
	 */
132 9
	protected function queueDefinitions( $definitions, $term ) {
133 9
		$ret = [];
134
135 9
		foreach ( $definitions as $definition ) {
136 9
			$ret[] = [
137 9
				Element::ELEMENT_TERM       => $term,
138 9
				Element::ELEMENT_DEFINITION => $definition,
139 9
				Element::ELEMENT_LINK       => null,
140 9
				Element::ELEMENT_SOURCE     => null
141
			];
142
		}
143
144 9
		return $ret;
145
	}
146
147
	/**
148
	 * @throws \MWException
149
	 */
150 14
	protected function collectDictionaryLines() {
151 14
		if ( $this->mArticleLines !== null ) {
152 6
			return;
153
		}
154
155
		// Get Terminology page
156 14
		$dictionaryPageName = $this->getLingoPageName();
157 14
		$dictionaryTitle = $this->getTitleFromText( $dictionaryPageName );
158
159 14
		if ( $dictionaryTitle->getInterwiki() !== '' ) {
160 1
			$this->getMessageLog()->addError( wfMessage( 'lingo-terminologypagenotlocal', $dictionaryPageName )->inContentLanguage()->text() );
0 ignored issues
show
Bug introduced by Stephan Gambke
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

160
			$this->getMessageLog()->addError( /** @scrutinizer ignore-call */ wfMessage( 'lingo-terminologypagenotlocal', $dictionaryPageName )->inContentLanguage()->text() );
Loading history...
161 1
			return;
162
		}
163
164 13
		$rawContent = $this->getRawDictionaryContent( $dictionaryTitle );
165
166
		// Expand templates and variables in the text, producing valid, static
167
		// wikitext. Have to use a new anonymous user to avoid any leakage as
168
		// Lingo is caching only one user-independent glossary
169 13
		$parser = new Parser;
170 13
		$content = $parser->preprocess( $rawContent, $dictionaryTitle, new ParserOptions( new User() ) );
171
172 13
		$this->mArticleLines = explode( "\n", $content );
173 13
	}
174
175
	/**
176
	 * @return string
177
	 */
178 15
	private function getLingoPageName() {
179 15
		global $wgexLingoPage;
180 15
		return $wgexLingoPage ? $wgexLingoPage : wfMessage( 'lingo-terminologypagename' )->inContentLanguage()->text();
0 ignored issues
show
Bug introduced by Stephan Gambke
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

180
		return $wgexLingoPage ? $wgexLingoPage : /** @scrutinizer ignore-call */ wfMessage( 'lingo-terminologypagename' )->inContentLanguage()->text();
Loading history...
181
	}
182
183
	/**
184
	 * @param Title $dictionaryTitle
185
	 *
186
	 * @return null|string
187
	 */
188 13
	protected function getRawDictionaryContent( Title $dictionaryTitle ) {
189 13
		global $wgRequest;
190
191
		// This is a hack special-casing the submitting of the terminology page
192
		// itself. In this case the Revision is not up to date when we get here,
193
		// i.e. $revision->getText() would return outdated Text. This hack takes the
194
		// text directly out of the data from the web request.
195 13
		if ( $wgRequest->getVal( 'action', 'view' ) === 'submit' &&
196 13
			$this->getTitleFromText( $wgRequest->getVal( 'title' ) )->getArticleID() === $dictionaryTitle->getArticleID()
197
		) {
198
199 1
			return $wgRequest->getVal( 'wpTextbox1' );
200
		}
201
202 12
		$revision = $this->getRevisionFromTitle( $dictionaryTitle );
203
204 12
		if ( $revision !== null ) {
205
206 11
			$content = $revision->getContent();
207
208 11
			if ( is_null( $content ) ) {
209 1
				return '';
210
			}
211
212 10
			if ( $content instanceof TextContent ) {
213 9
214
				// FIXME: getNativeData() is deprecated for MW 1.33+. Use getText().
0 ignored issues
show
Coding Style introduced by Stephan
Comment refers to a FIXME task "getNativeData() is deprecated for MW 1.33+. Use getText"
Loading history...
215
				if ( !method_exists( $content, 'getText' ) ) {
216 1
					return $content->getNativeData();
217
				}
218
219
				return $content->getText();
220 1
			}
221
222
			$this->getMessageLog()->addError( wfMessage( 'lingo-notatextpage', $dictionaryTitle->getFullText() )->inContentLanguage()->text() );
0 ignored issues
show
Bug introduced by Stephan Gambke
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

222
			$this->getMessageLog()->addError( /** @scrutinizer ignore-call */ wfMessage( 'lingo-notatextpage', $dictionaryTitle->getFullText() )->inContentLanguage()->text() );
Loading history...
223 2
224
		} else {
225
226
			$this->getMessageLog()->addWarning( wfMessage( 'lingo-noterminologypage', $dictionaryTitle->getFullText() )->inContentLanguage()->text() );
227
		}
228
229
		return '';
230
	}
231
232 12
	/**
233 12
	 * Returns revision of the terms page.
234
	 *
235 12
	 * @param Title $title
236
	 * @return null|Revision
237 2
	 */
238 1
	protected function getRevisionFromTitle( Title $title ) {
239
		global $wgexLingoEnableApprovedRevs;
240
241 1
		if ( $wgexLingoEnableApprovedRevs ) {
242
243
			if ( defined( 'APPROVED_REVS_VERSION' ) ) {
244 11
				return $this->getApprovedRevisionFromTitle( $title );
245
			}
246
247
			$this->getMessageLog()->addWarning( wfMessage( 'lingo-noapprovedrevs' )->inContentLanguage()->text() );
0 ignored issues
show
Bug introduced by Stephan Gambke
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

247
			$this->getMessageLog()->addWarning( /** @scrutinizer ignore-call */ wfMessage( 'lingo-noapprovedrevs' )->inContentLanguage()->text() );
Loading history...
248
		}
249
250
		return $this->getLatestRevisionFromTitle( $title );
251
	}
252
253 1
	/**
254 1
	 * Initiates the purging of the cache when the Terminology page was saved or purged.
255
	 *
256 1
	 * @param WikiPage &$wikipage
257
	 * @return Bool
258
	 */
259 1
	public function purgeCache( WikiPage &$wikipage ) {
260
		if ( !is_null( $wikipage ) && ( $wikipage->getTitle()->getText() === $this->getLingoPageName() ) ) {
261
262
			$this->getLingoParser()->purgeGlossaryFromCache();
263
		}
264
265
		return true;
266
	}
267
268
	/**
269
	 * The basic backend is cache-enabled so this function returns true.
270 1
	 *
271 1
	 * Actual caching is done by the parser, the backend just calls
272
	 * Lingo\LingoParser::purgeCache when necessary.
273
	 *
274
	 * @return bool
275
	 */
276
	public function useCache() {
277
		return true;
278
	}
279
280
	/**
281
	 * @codeCoverageIgnore
282
	 * @param string $dictionaryPage
283
	 * @return Title
284
	 */
285
	protected function getTitleFromText( $dictionaryPage ) {
286
		return Title::newFromTextThrow( $dictionaryPage );
287
	}
288
289
	/**
290
	 * @codeCoverageIgnore
291
	 * @param Title $title
292
	 * @return null|Revision
293
	 */
294
	protected function getApprovedRevisionFromTitle( Title $title ) {
295
		return Revision::newFromId( ApprovedRevs::getApprovedRevID( $title ) );
296
	}
297
298
	/**
299
	 * @codeCoverageIgnore
300
	 * @param Title $title
301
	 * @return null|Revision
302
	 */
303
	protected function getLatestRevisionFromTitle( Title $title ) {
304
		return Revision::newFromTitle( $title );
305 13
	}
306 13
307
	/**
308
	 * @param string $line
309
	 * @return bool
310
	 */
311
	protected function isValidGlossaryLine( $line ) {
312
		return !empty( $line ) && ( $line[ 0 ] === ';' || $line[ 0 ] === ':' );
313
	}
314
315
}
316