Completed
Push — master ( 20f2b6...7ca281 )
by Toni Hermoso
19:05
created

SDImportData   F

Complexity

Total Complexity 124

Size/Duplication

Total Lines 896
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
dl 0
loc 896
rs 1.704
c 0
b 0
f 0
wmc 124
lcom 1
cbo 10

18 Methods

Rating   Name   Duplication   Size   Complexity  
F saveJSONData() 0 103 21
A addPropertyTypes() 0 18 3
B importProperties() 0 36 6
A insertInternalObject() 0 34 5
A insertObjectviaJSON() 0 40 3
B insertInternalObjectviaJSON() 0 66 6
B getSelector() 0 62 9
A isAssocArray() 0 4 2
A processWikiText() 0 14 3
A getJSONContent() 0 28 4
B processJSON() 0 48 7
B checkJSONData() 0 28 6
F importWikiText() 0 127 23
B importJSONBatch() 0 45 7
B importJSON() 0 22 7
A prepareStructForJSON() 0 27 4
B onOutputPageBeforeHTML() 0 39 7
A onResourceLoaderGetConfigVars() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like SDImportData often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SDImportData, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 9 and the first side effect is on line 4.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
if ( !defined( 'MEDIAWIKI' ) ) {
4
	echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
5
}
6
7
/** In this class we store things related to data processing **/
8
9
class SDImportData {
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...
10
11
12
	/**
13
	 * Occurs after the save page request has been processed.
14
	 *
15
	 * @param WikiPage $wikiPage
16
	 * @param User $user
17
	 * @param Content $content
18
	 * @param string $summary
19
	 * @param boolean $isMinor
20
	 * @param boolean $isWatch
21
	 * @param $section Deprecated
22
	 * @param integer $flags
23
	 * @param {Revision|null} $revision
0 ignored issues
show
Documentation introduced by
The doc-type {Revision|null} could not be parsed: Unknown type name "{Revision" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
24
	 * @param Status $status
25
	 * @param integer $baseRevId
26
	 * @param integer $undidRevId
27
	 *
28
	 * @return boolean
29
	 * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageContentSaveComplete
30
	 */
31
	public static function saveJSONData( $wikiPage, $user, $content, $summary, $isMinor, $isWatch, $section, $flags, $revision, $status, $baseRevId, $undidRevId=null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $summary 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...
Unused Code introduced by
The parameter $isMinor 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...
Unused Code introduced by
The parameter $isWatch 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...
Unused Code introduced by
The parameter $section 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...
Unused Code introduced by
The parameter $flags 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...
Unused Code introduced by
The parameter $status 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...
Unused Code introduced by
The parameter $baseRevId 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...
Unused Code introduced by
The parameter $undidRevId 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...
32
		
33
		global $wgSDImportDataPage;
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...
34
35
		if ( $wikiPage ) {
36
			
37
			// Get NS
38
			$pageTitle = $wikiPage->getTitle();
39
40
			if ( is_object( $pageTitle ) ) {
41
42
				$ns = $pageTitle->getNsText();
43
				
44
				if ( $ns === "" ) {
45
					
46
					$ns = "_"; // Handle main namespace
47
				}
48
49
				if ( key_exists( $ns, $wgSDImportDataPage ) ) {
50
51
					$nsRepo = $wgSDImportDataPage[$ns];
52
53
					if ( array_key_exists( "json", $nsRepo ) ) {		
54
55
						if ( $nsRepo["json"] ) {
56
57
							list( $args, $table ) = self::getJSONContent( $content );
58
						
59
							$object = self::getSelector( $args, $nsRepo, "rowobject" ); // String
60
							$fields = self::getSelector( $args, $nsRepo, "rowfields" ); // Array
61
							$types = self::getSelector( $args, $nsRepo, "typefields" ); // Array
62
							$refs = self::getSelector( $args, $nsRepo, "ref" ); // Hash
63
							$pre = self::getSelector( $args, $nsRepo, "prefields" ); // Array
64
							$post = self::getSelector( $args, $nsRepo, "postfields" ); // Array
65
							$single = self::getSelector( $args, $nsRepo, "single" ); // Boolean
66
		
67
							// Adding properties, unless they exist
68
							$propertyTypes = self::addPropertyTypes( $fields, $types );
69
							// TODO: Handling failing, etc.
70
							self::importProperties( $propertyTypes );
71
		
72
							$dprops = array();
73
74
							if ( $refs ) {
75
								foreach ( $refs as $key => $val ) {
76
									$dprops[ $key ] = self::processWikiText( $val, $pageTitle );
77
								}
78
							}
79
							
80
							if ( $table ) {
81
							
82
								foreach ( $table as $row ) {
83
									$fieldcount = 0;
84
									$struct = array();
85
									foreach ( $row as $field ) {
86
				
87
										$field = trim( $field );
88
										
89
										if ( ! empty( $field ) ) {
90
											$pretxt = "";
91
											if ( isset( $pre[ $fieldcount ] ) && !empty( $pre[ $fieldcount ] ) ) {
92
												$pretxt = $pre[ $fieldcount ].":"; // : for pre
93
											}
94
											$postxt = "";
95
											if ( isset( $post[ $fieldcount ] ) && !empty( $post[ $fieldcount ] ) ) {
96
												$postxt = "@".$post[ $fieldcount ]; // @ for post
97
											}
98
											
99
											if ( array_key_exists( $fieldcount, $fields ) ) {
100
												$struct[ $fields[ $fieldcount ] ] =  $pretxt.$field.$postxt;
101
											}
102
										}
103
										$fieldcount++;
104
									}
105
									foreach ( $dprops as $dpropk => $dpropv ) {
106
										$struct[ $dpropk ] = $dpropv;
107
									}
108
109
									if ( count( array_keys( $struct ) ) > 0 ) {
110
										
111
										if ( $single ) {
112
											self::insertObjectviaJSON( $wikiPage, $revision, $user, $struct );
0 ignored issues
show
Documentation introduced by
$struct is of type array, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
113
										} else {
114
											self::insertInternalObjectviaJSON( $wikiPage, $revision, $user, $object, $struct );
0 ignored issues
show
Documentation introduced by
$struct is of type array, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
115
										}
116
									}
117
									
118
								}
119
							
120
							}
121
						
122
						}
123
					
124
					}
125
		
126
				}
127
			
128
			}
129
		
130
		}
131
		
132
		return true;
133
	}
134
	
135
	
136
	/**
137
	 * Function for combining properties and types
138
	 * @param $props array
139
	 * @param $types array
140
	 * 
141
	 * @return array
142
	*/
143
	public static function addPropertyTypes( $props, $types ) {
144
		
145
		$count = 0;
146
		
147
		foreach ( $types as $type ) {
148
			
149
			if ( array_key_exists( $count, $props ) ) {
150
				
151
				$prop = $props[ $count ];
152
				$propertyTypes[ $prop ] = $type;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$propertyTypes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $propertyTypes = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
153
			}
154
			
155
			$count++;
156
			
157
		}
158
		
159
		return $propertyTypes;
0 ignored issues
show
Bug introduced by
The variable $propertyTypes does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
160
	}
161
	
162
	/**
163
	 * Function for importing Properties straight into the wiki
164
	 * @param $propertyTypes array
165
	 * @param $overwrite boolean
166
	 * @param $user User
167
	 * 
168
	 * @return array
169
	*/
170
	public static function importProperties( $propertyTypes, $overwrite=false, $user=null) {
0 ignored issues
show
Unused Code introduced by
The parameter $user 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...
171
		
172
		$edit_summary = "Adding property via SDImport";
173
		$listProps = array();
174
		
175
		foreach ( $propertyTypes as $prop => $type ) {
176
			
177
			// Consider going ahead it type is not null
178
			if ( $type ) {
179
180
				// TODO: to consider not hardcoding NS
181
				$propPageName = "Property:".$prop;
182
				
183
				$propTitle = Title::newFromText( $propPageName );
184
				
185
				$wikiPage = new WikiPage( $propTitle );
186
				
187
				if ( ! $wikiPage->exists() || ( $wikiPage->exists() && $overwrite ) ) {
188
					
189
					$text = "[[Has Type::".$type."]]";
190
					
191
					$new_content = new WikitextContent( $text );
192
					$status = $wikiPage->doEditContent( $new_content, $edit_summary );
0 ignored issues
show
Unused Code introduced by
$status is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
193
					
194
					// Adding list
195
					// TODO: ideally handling Status 
196
					array_push( $listProps, $prop );
197
				}
198
			
199
			}
200
			
201
		}
202
		
203
		
204
		return $listProps;
205
	}
206
	
207
	/**
208
	 * @param $pageTitle Title
209
	 * @param $object string
210
	 * @param struct object
211
	 * 
212
	 * @return boolean
213
	*/
214
	public static function insertInternalObject( $parser, $pageTitle, $object, $struct ) {
215
216
		# TODO: Check if this will work
217
		if ( ! $parser ) {
218
			$parser = new Parser();
219
			$parser->setTitle( $pageTitle ); // Put context
220
		}
221
		
222
		$subobjectArgs = array( &$parser );
223
		// Blank first argument, so that subobject ID will be
224
		// an automatically-generated random number.
225
		$subobjectArgs[1] = '';
226
		// "main" property, pointing back to the page.
227
		$mainPageName = $pageTitle->getText();
228
		$mainPageNamespace = $pageTitle->getNsText();
229
		if ( $mainPageNamespace != '' ) {
230
			$mainPageName = $mainPageNamespace . ':' . $mainPageName;
231
		}
232
		$subobjectArgs[2] = $object . '=' . $mainPageName;
233
234
		foreach ( $struct as $prop => $value ) {
235
			$subobjectArgs[] = $prop . '=' . $value;
236
		}
237
238
		if ( class_exists( 'SMW\SubobjectParserFunction' ) ) {
239
			// SMW 1.9+
240
			$subobjectFunction = \SMW\ParserFunctionFactory::newFromParser( $parser )->getSubobjectParser();
0 ignored issues
show
Deprecated Code introduced by
The method SMW\ParserFunctionFactory::getSubobjectParser() has been deprecated with message: since 2.1, use newSubobjectParserFunction

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
241
			return $subobjectFunction->parse( new SMW\ParserParameterFormatter( $subobjectArgs ) );
242
		} else {
243
			// SMW 1.8
244
			call_user_func_array( array( 'SMWSubobject', 'render' ), $subobjectArgs );
245
		}
246
		return;
247
	}
248
	
249
	
250
	/**
251
	 * @param $wikiPage wikiPage
252
     * @param $revision revision
253
     * @param $user user
254
	 * @param struct object
255
	 * 
256
	 * @return boolean
257
     * 
258
     * Code adapted from: https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/2974
259
	*/
260
	public static function insertObjectviaJSON( $wikiPage, $revision, $user, $struct ) {
261
	
262
		$applicationFactory = \SMW\ApplicationFactory::getInstance();
263
		
264
		$mwCollaboratorFactory = $applicationFactory->newMwCollaboratorFactory();
265
		
266
		/** * Initialize the ParserOuput object */
267
		$editInfoProvider = $mwCollaboratorFactory->newEditInfoProvider( $wikiPage, $revision, $user );
268
		
269
		$parserOutput = $editInfoProvider->fetchEditInfo()->getOutput();
270
271
		if ( !$parserOutput instanceof \ParserOutput ) {
0 ignored issues
show
Bug introduced by
The class ParserOutput does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
272
			return true;
273
		}
274
		
275
		$parserData = $applicationFactory->newParserData( $wikiPage->getTitle(), $parserOutput );
276
	
277
		$subject = $parserData->getSubject();
278
279
		$subject = new \SMW\DIWikiPage( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki() );
280
		
281
		// TODO: To finish
282
		foreach ( $struct as $property => $value ) {
283
			// Struct to iterate
284
			
285
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByText( $property, $value, false, $subject );
286
287
			$parserData->getSemanticData()->addDataValue( $dataValue );
288
289
		}
290
	
291
		// This part is used to add the subobject the the main subject
292
		$parserData->pushSemanticDataToParserOutput();
293
		$parserData->updateStore();
294
		// Below it works event with maintenance function
295
		// $store = \SMW\StoreFactory::getStore();
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
296
		// $store->updateData( $parserData->getSemanticData() );
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
297
		
298
		return true;
299
	}	
300
	
301
	/**
302
	 * @param $wikiPage wikiPage
303
     * @param $revision revision
304
     * @param $user user
305
	 * @param $object string
306
	 * @param struct object
307
	 * 
308
	 * @return boolean
309
     * 
310
     * Code from: https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/2974
311
	*/
312
	public static function insertInternalObjectviaJSON( $wikiPage, $revision, $user, $object, $struct ) {
313
314
		$applicationFactory = \SMW\ApplicationFactory::getInstance();
315
		
316
		$mwCollaboratorFactory = $applicationFactory->newMwCollaboratorFactory();
317
		
318
		/** * Initialize the ParserOuput object */
319
		$editInfoProvider = $mwCollaboratorFactory->newEditInfoProvider( $wikiPage, $revision, $user );
320
		
321
		$parserOutput = $editInfoProvider->fetchEditInfo()->getOutput();
322
323
		if ( !$parserOutput instanceof \ParserOutput ) {
0 ignored issues
show
Bug introduced by
The class ParserOutput does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
324
			return true;
325
		}
326
		
327
		$parserData = $applicationFactory->newParserData( $wikiPage->getTitle(), $parserOutput );
328
329
		$subject = $parserData->getSubject();
330
		
331
		// Identify the content as unique
332
		$subobjectName = '_SDI' . md5( json_encode( $struct ) );
333
334
		$subject = new \SMW\DIWikiPage( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki(), $subobjectName );
335
336
		// Build the subobject by using a separate container object
337
		$containerSemanticData = new \SMWContainerSemanticData( $subject );
338
339
		// Iterate through here
340
		
341
		foreach ( $struct as $property => $value ) {
342
			// If you don't know the type, use the DataValueFactory
343
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByText( $property, $value );
344
			$containerSemanticData->addDataValue( $dataValue );
345
		}
346
		
347
		// Object assignation
348
		
349
		if ( $object ) {
350
			
351
			if ( ! empty( $object ) ) {
352
				
353
				if ( $wikiPage->getTitle() ) {
354
					
355
					$fullTitle = $wikiPage->getTitle()->getPrefixedText();
356
					
357
					$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByText( $object, $fullTitle );
358
					$containerSemanticData->addDataValue( $dataValue );
359
					
360
				}
361
				
362
			}
363
			
364
		}
365
		
366
		
367
		// This part is used to add the subobject the the main subject
368
		$parserData->getSemanticData()->addPropertyObjectValue( new \SMW\DIProperty( \SMW\DIProperty::TYPE_SUBOBJECT ), new \SMWDIContainer( $containerSemanticData ) );
369
		$parserData->pushSemanticDataToParserOutput();
370
		$parserData->updateStore();
371
372
		// Below it works event with maintenance function
373
		// $store = \SMW\StoreFactory::getStore();
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
374
		// $store->updateData( $parserData->getSemanticData() );
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
375
		
376
		return true;
377
	}
378
379
380
	/**
381
	* @first -> First hash
382
	* @second -> Second hash
383
	* @key -> Actual key
384
385
	* @return variable (depending on case)
386
	*/
387
	public static function getSelector( $first, $second, $key ) {
388
		
389
		if ( key_exists( $key, $first ) ) {
390
			// Here process
391
			
392
			$array = array();
393
394
			if ( is_array( $first[ $key ] ) ) {
395
				$keyvals = $first[ $key ];
396
			} else {
397
				$keyvals = explode( ",", $first[ $key ] );
398
			}
399
			
400
			
401
			if ( self::isAssocArray( $keyvals ) ) {
402
				
403
				return $keyvals;
404
			
405
			} else {
406
			
407
				if ( count( $keyvals ) < 2 ) {
408
					// If => ergo hash
409
					
410
					$keyhvals = explode( "#", $keyvals[0], 2 );
411
	
412
					if ( count( $keyhvals ) > 1 ) {
413
						$array[ trim( $keyhvals[0] ) ] = trim( $keyhvals[1] );
414
						return $array;
415
					} else {
416
						return trim( $keyhvals[0] );
417
					}
418
				} else { 
419
	
420
					foreach ( $keyvals as $keyval ) {
421
						$keyval = trim( $keyval );
422
						
423
						// If => ergo hash
424
						$keyhvals = explode( "#", $keyval, 2 );
425
		
426
						if ( count( $keyhvals ) > 1 ) {
427
							$array[ trim( $keyhvals[0] ) ] = trim( $keyhvals[1] );
428
						}
429
						else {
430
							array_push( $array, trim( $keyhvals[0] ) );
431
						}
432
					}
433
	
434
					return $array;
435
				}
436
			
437
			}
438
439
		} else {
440
			if ( key_exists( $key, $second ) ) {
441
				// Direct
442
				return $second[$key];
443
			} else {
444
				return false;
445
			}
446
		}
447
		
448
	}
449
	
450
451
	/**
452
	 * Whether associative array or not
453
	 * $arr Array
454
	 * @return boolean
455
	*/
456
	
457
	public static function isAssocArray( array $arr ) {
458
	    if (array() === $arr) return false;
459
	    return array_keys($arr) !== range(0, count($arr) - 1);
460
	}
461
462
463
464
	/**
465
	 * Occurs after the save page request has been processed.
466
	 * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageContentSaveComplete
467
	 *
468
	 * @param text string
469
	 *
470
	 * @return boolean
471
	*/
472
	public static function processWikiText( $text, $pageTitle ) {
473
474
		// TODO: Ideally a full wikitext processing here, etc.
475
476
		if ( $text == '{{PAGENAME}}' ) {
477
			$text = $pageTitle->getText();
478
		} elseif ( $text == '{{FULLPAGENAME}}' ) {
479
			$text = $pageTitle->getPrefixedText();
480
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
481
			// Do nothing;
482
		}
483
484
		return $text;
485
	}
486
487
	
488
	private static function getJSONContent( $content ) {
489
490
		$outcome = array( );
491
		$args = null;
492
		$data = null;
493
494
		if ( $content ) {
495
			
496
			if ( is_object( $content ) ) {
497
				
498
				if ( $content->getModel() == CONTENT_MODEL_JSON ) {
499
500
					// Only act if JSON
501
					
502
					$json = $content->getNativeData();
503
504
					
505
					list( $args, $data ) = self::processJSON( $json );
506
				}
507
				
508
			}
509
		}
510
		
511
		array_push( $outcome, $args );
512
		array_push( $outcome, $data );
513
514
		return $outcome;
515
	}
516
517
	
518
	private static function processJSON( $json ) {
519
520
		$outcome = array( );
521
		$args = null;
522
		$data = null;
523
		
524
		$SDIJSON = false;
525
		
526
		// Check JSON is valid
527
		$jsonObj = json_decode( $json, true );
528
529
		if ( $jsonObj ) {
530
		
531
			if ( array_key_exists( "meta", $jsonObj ) ) {
532
				
533
				$meta = $jsonObj["meta"];
534
535
				if ( array_key_exists( "app", $meta ) ) {
536
					
537
					if ( $meta["app"] === "SDI" ) {
538
						$SDIJSON = true;
539
					}
540
					
541
				}
542
				
543
				$args = $meta;
544
				
545
				# TODO: Addding more custom fields to args
546
				
547
				
548
				if ( array_key_exists( "data", $jsonObj ) && $SDIJSON ) {
549
				
550
					$dataObj = $jsonObj["data"];
551
				
552
					$data = self::checkJSONData( $dataObj );
553
				
554
				}
555
			}
556
		
557
		}
558
559
		
560
		array_push( $outcome, $args );
561
		array_push( $outcome, $data );
562
563
		return $outcome;	
564
		
565
	}
566
	
567
	private static function checkJSONData( $dataObj ) {
568
		
569
		$data = null;
570
		
571
		if ( is_array( $dataObj ) ) {
572
			
573
			if ( count( $dataObj ) > 0 ) {
574
				
575
				$bad = false;
576
				
577
				// We should have an array of arrays
578
				foreach ( $dataObj as $row ) {
579
					
580
					if ( ! is_array( $row ) ) {
581
						$bad = true;
582
					}
583
				}
584
				
585
				if ( ! $bad ) {
586
					$data = $dataObj;
587
				}
588
				
589
			}
590
		}
591
592
			
593
		return $data;
594
	}
595
596
597
	/** Import of Wikitext, let's say, at commit */
598
	/**
599
	* @text Bulk data text
600
	* @pagetitle Title of the page
601
	* @delimiter Delimiter of CSV
602
	* @enclosure Enclosure of CSV
603
	* @num Occurrence in page. If only one, then 0
604
	* @return status of update
605
	*/
606
	public static function importWikiText( $text, $pagetitle, $separator=NULL, $delimiter=NULL, $num=0 ) {
0 ignored issues
show
Coding Style introduced by
importWikiText uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
607
608
		$title = Title::newFromText( $pagetitle );
609
		$wikipage = WikiPage::factory( $title );
610
		
611
		# Default cases
612
		$newpage = false;
613
		$contentModel = "wikitext";
614
		
615
		$extraInfo = "";
616
617
		$ns = $title->getSubjectNsText();
618
		
619
		# Handle main namespace with _
620
		if ( $ns == "" ) {
621
			$ns = "_";
622
		}
623
624
		if ( $GLOBALS["wgSDImportDataPage"] && array_key_exists( $ns, $GLOBALS["wgSDImportDataPage"] ) ) {
625
626
			if ( $separator !== NULL ) {
627
				if ( array_key_exists( "separator", $GLOBALS["wgSDImportDataPage"][$ns] ) ) {
628
					if ( $GLOBALS["wgSDImportDataPage"][$ns]["separator"] != $separator ) {
629
						$extraInfo = $extraInfo . " separator=\"".$separator."\"";
630
					}
631
				}
632
			}
633
			if ( $delimiter !== NULL ) {
634
				if ( array_key_exists( "delimiter", $GLOBALS["wgSDImportDataPage"][$ns] ) ) {
635
					if ( $GLOBALS["wgSDImportDataPage"][$ns]["delimiter"] != $delimiter ) {
636
						$extraInfo = $extraInfo . " delimiter='".$delimiter."' ";
0 ignored issues
show
Unused Code introduced by
$extraInfo is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
637
					}
638
				}
639
			}
640
		}
641
642
		// Retrievet text of page
643
		// Back-compatibility, just in case
644
		
645
		// TODO: Handle if creation of page
646
		if ( ! $wikipage->exists() ) {
647
			$newpage = true;
648
		}
649
		
650
		if ( ! $newpage ) {
651
		
652
			if ( method_exists ( $wikipage, "getContent" ) ) {
653
				$mainContent = $wikipage->getContent();
654
				$mainText = $mainContent->getNativeData();
655
				$contentModel = $wikipage->getContentModel();
656
				
657
				if ( ! $contentModel ) {
658
					$contentModel = "wikitext";
659
				}
660
				
661
			} else {
662
				$mainText = $wikipage->getText();
663
				$contentModel = "wikitext";
664
			}
665
		
666
		}
667
668
		$status = 0;
669
		$tableText = "";
670
		
671
		# Allow only in wikitext context
672
		if ( $contentModel === "wikitext" ) {
673
		
674
		
675
			if ( ! $newpage ) {
676
				
677
				// Get matches
678
				$page_parts = preg_split( "/(<smwdata.*?>)/", $mainText, -1, PREG_SPLIT_DELIM_CAPTURE );
0 ignored issues
show
Bug introduced by
The variable $mainText does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
679
		
680
				$count = 0;
681
				$outcome = array();
682
		
683
				foreach ( $page_parts as $page_part ) {
684
		
685
					if ( preg_match( "/<smwdata/", $page_part ) ) {
686
						$count = $count + 1;
687
					} else {
688
						if ( $num == $count - 1 ) {
689
							if ( preg_match( "/<\/smwdata/", $page_part ) ) {
690
		
691
								$in_parts = preg_split( "/(<\/smwdata.*?>)/", $page_part, -1, PREG_SPLIT_DELIM_CAPTURE );
692
								$in_parts[0] = "\n".$text."\n";
693
								$page_part = implode( "", $in_parts );
694
							}
695
						}
696
					}
697
		
698
					array_push( $outcome, $page_part );
699
				}
700
				
701
				// If stuff
702
				if ( count( $outcome ) > 0 ) {
703
	
704
					$tableText = implode( "", $outcome );			
705
				}
706
			
707
			} else {
708
				
709
				$tableText = "<smwdata>".$text."</smwdata>";
710
				
711
			}
712
	
713
	
714
			if ( ! empty( $tableText ) ) {
715
				
716
				// Submit content
717
				// Back-compatibility, just in case
718
				if ( method_exists ( $wikipage, "doEditContent" ) ) {
719
					$content = new WikiTextContent( $tableText );
720
					$status = $wikipage->doEditContent( $content, "Updating content" );
721
				} else {
722
					$status = $wikipage->doEdit( $tableText, "Updating content" );
723
				}
724
	
725
			}
726
			
727
			// TODO: Handle status value if not normal one
728
		
729
		}
730
731
		return $status;
732
	}
733
	
734
	
735
736
	/**
737
	* @text Bulk data text
738
	* @pagetitle Title of the page
739
	* @return status of update
740
	*/
741
742
	public static function importJSONBatch( $text, $namespace="", $overwrite=false) {
743
744
		$jsonObj = json_decode( $text, true );
745
		$dataObj = $jsonObj["data"];
746
		$dataHash = array();
747
				
748
		for ( $x=0; $x <count($dataObj); $x++ ) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
749
750
			if ( count( $dataObj[$x] ) > 1 ) {
751
				
752
				$pageCell = array_shift(  $dataObj[$x] );
753
				
754
				if ( $pageCell !== "" ) {
755
					
756
					if ( $namespace === "" ) {
757
						$pagetitle =  $pageCell;
758
					} else {
759
						$pagetitle = $namespace . ':' . $pageCell;
760
					}	
761
					
762
				}
763
				
764
				if ( ! $dataHash[ $pagetitle ] ) {
765
					$dataHash[ $pagetitle ] = array();
0 ignored issues
show
Bug introduced by
The variable $pagetitle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
766
				}
767
				
768
				array_push( $dataHash[ $pagetitle ], $dataObj[$x] );
769
				
770
			}
771
			
772
		}
773
		
774
		foreach ( $dataHash as $pagetitle => $dataArray ) {
775
			
776
			$jsonSubObj = array();
777
			$jsonSubObj["data"] = $dataArray;
778
			$jsonSubObj["meta"] = $jsonObj["meta"];
779
780
			self::importJSON( json_encode( $jsonSubObj ), $pagetitle, $overwrite );
781
			
782
		}
783
		
784
		return true;
785
786
	}
787
788
	/** Import of JSON into a page, let's say, at commit **/
789
	/**
790
	* @text Bulk data text
791
	* @pagetitle Title of the page
792
	* @return status of update
793
	*/
794
	public static function importJSON( $text, $pagetitle, $overwrite=false) {
795
796
		$title = Title::newFromText( $pagetitle );
797
		$wikipage = WikiPage::factory( $title );
798
		$goahead = true;
799
		$status = false;
800
		// Check if exists
801
		if ( $wikipage->exists() &&  ! $overwrite ) {
802
			$goahead = false;
803
		}
804
			if ( $goahead ) {
805
				// Check compatibility. Only if newer versions of MW
806
				if ( method_exists ( $wikipage, "getContent" ) ) {
807
					$contentModel = $wikipage->getContentModel();
808
					if ( $contentModel === "json" || ! $wikipage->exists() ) {
809
						$content = new JSONContent($text);
810
						$status = $wikipage->doEditContent( $content, "Updating content" );
811
					}
812
				}
813
			}
814
		return $status;
815
	}
816
	
817
	/** TODO: TO BE UPDATED **/
818
	public static function prepareStructForJSON( $meta, $data ) {
819
		
820
		$strJSON = "";
821
		
822
		if ( $data ) {
823
			
824
			$obj = array( );
825
			
826
			// TODO: this may change in future versions
827
			$obj["meta"] = array();
828
			$obj["meta"]["app"] = "SDI";
829
			$obj["meta"]["version"] = 0.1;
830
			
831
			if ( $meta ) {
832
				
833
				if ( array_key_exists( "rowfields", $meta ) ) {
834
					$obj["meta"]["rowfields"] = $meta["rowfields"];
835
				}
836
			}
837
			
838
			$obj["data"] = $data;
839
			
840
			$strJSON = json_encode( $obj );
841
		}
842
843
		return $strJSON;
844
	}
845
	
846
847
	/**
848
	* @param $out OutputPage
849
	* @param $text string
850
	* @return $out OutputPage
851
	*/
0 ignored issues
show
Documentation introduced by
The doc-type $out could not be parsed: Unknown type name "$out" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
852
	
853
	public static function onOutputPageBeforeHTML( &$out, &$text ) {
0 ignored issues
show
Unused Code introduced by
The parameter $text 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...
854
855
		// We add Modules
856
		$out->addModules( 'ext.sdimport' );
857
		
858
		global $wgSDImportDataPage;
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...
859
		
860
		// Get Namespace
861
		
862
		$context = RequestContext::getMain();
863
		if ( $context ) {
864
			$title = $context->getTitle();
865
			if ( $title ) {
866
				
867
				$ns = $title->getSubjectNsText();
868
				
869
				# Handle main namespace with _
870
				if ( $ns == "" ) {
871
					$ns = "_";
872
				}
873
				
874
				if ( array_key_exists( $ns, $wgSDImportDataPage ) ) {
875
					
876
					if ( array_key_exists( "form", $wgSDImportDataPage[$ns] )  ) {
877
						
878
						if ( $wgSDImportDataPage[$ns]["form"] === true ) {
879
							
880
							// Adding form libraries only if needed
881
							$out->addModules( 'ext.sdimport.form' );
882
							
883
						}
884
					}
885
				}
886
				
887
			}
888
		}
889
		
890
		return $out;
891
	}
892
	
893
	/** This allow PHP vars to be exposed to JavaScript **/
894
	
895
	public static function onResourceLoaderGetConfigVars( &$vars ) {
896
		
897
		global $wgSDImportDataPage;
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...
898
899
900
		$vars['wgSDImportDataPage'] = $wgSDImportDataPage;
901
902
		return true;
903
	}
904
}
905