Completed
Push — master ( af61ba...20f2b6 )
by Toni Hermoso
20:25
created

SDImportData::insertInternalObject()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 16
nop 4
dl 0
loc 34
rs 9.0648
c 0
b 0
f 0
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
							$props = self::getSelector( $args, $nsRepo, "typefields" ); // Array
0 ignored issues
show
Unused Code introduced by
$props 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...
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
							// TODO: Should we add props here if they don't exist?
68
		
69
							$dprops = array();
70
71
							if ( $refs ) {
72
								foreach ( $refs as $key => $val ) {
73
									$dprops[ $key ] = self::processWikiText( $val, $pageTitle );
74
								}
75
							}
76
							
77
							if ( $table ) {
78
							
79
								foreach ( $table as $row ) {
80
									$fieldcount = 0;
81
									$struct = array();
82
									foreach ( $row as $field ) {
83
				
84
										$field = trim( $field );
85
										
86
										if ( ! empty( $field ) ) {
87
											$pretxt = "";
88
											if ( isset( $pre[ $fieldcount ] ) && !empty( $pre[ $fieldcount ] ) ) {
89
												$pretxt = $pre[ $fieldcount ].":"; // : for pre
90
											}
91
											$postxt = "";
92
											if ( isset( $post[ $fieldcount ] ) && !empty( $post[ $fieldcount ] ) ) {
93
												$postxt = "@".$post[ $fieldcount ]; // @ for post
94
											}
95
											
96
											if ( array_key_exists( $fieldcount, $fields ) ) {
97
												$struct[ $fields[ $fieldcount ] ] =  $pretxt.$field.$postxt;
98
											}
99
										}
100
										$fieldcount++;
101
									}
102
									foreach ( $dprops as $dpropk => $dpropv ) {
103
										$struct[ $dpropk ] = $dpropv;
104
									}
105
106
									if ( count( array_keys( $struct ) ) > 0 ) {
107
										
108
										if ( $single ) {
109
											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...
110
										} else {
111
											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...
112
										}
113
									}
114
									
115
								}
116
							
117
							}
118
						
119
						}
120
					
121
					}
122
		
123
				}
124
			
125
			}
126
		
127
		}
128
		
129
		return true;
130
	}
131
	
132
	/**
133
	 * Function for importing Properties straight into the wiko
134
	 * @param $propertyTypes array
135
	 * @param $overwrite boolean
136
	 * @param $user User
137
	 * 
138
	 * @return array
139
	*/
140
	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...
141
		
142
		$edit_summary = "Adding property via SDImport";
143
		$listProps = array();
144
		
145
		foreach ( $propertyTypes as $prop => $type ) {
146
			
147
			// TODO: to consider not hardcoding NS
148
			$propPageName = "Property:".$prop;
149
			
150
			$propTitle = Title::newFromText( $propPageName );
151
			
152
			$wikiPage = new WikiPage( $propTitle );
153
			
154
			if ( ! $wikiPage->exists() || ( $wikiPage->exists() && $overwrite ) ) {
155
				
156
				$text = "[[Has Type::".$type."]]";
157
				
158
				$new_content = new WikitextContent( $text );
159
				$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...
160
				
161
				// Adding list
162
				// TODO: ideally handling Status 
163
				array_push( $listProps, $prop );
164
			}
165
			
166
		}
167
		
168
		
169
		return $listProps;
170
	}
171
	
172
	/**
173
	 * @param $pageTitle Title
174
	 * @param $object string
175
	 * @param struct object
176
	 * 
177
	 * @return boolean
178
	*/
179
	public static function insertInternalObject( $parser, $pageTitle, $object, $struct ) {
180
181
		# TODO: Check if this will work
182
		if ( ! $parser ) {
183
			$parser = new Parser();
184
			$parser->setTitle( $pageTitle ); // Put context
185
		}
186
		
187
		$subobjectArgs = array( &$parser );
188
		// Blank first argument, so that subobject ID will be
189
		// an automatically-generated random number.
190
		$subobjectArgs[1] = '';
191
		// "main" property, pointing back to the page.
192
		$mainPageName = $pageTitle->getText();
193
		$mainPageNamespace = $pageTitle->getNsText();
194
		if ( $mainPageNamespace != '' ) {
195
			$mainPageName = $mainPageNamespace . ':' . $mainPageName;
196
		}
197
		$subobjectArgs[2] = $object . '=' . $mainPageName;
198
199
		foreach ( $struct as $prop => $value ) {
200
			$subobjectArgs[] = $prop . '=' . $value;
201
		}
202
203
		if ( class_exists( 'SMW\SubobjectParserFunction' ) ) {
204
			// SMW 1.9+
205
			$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...
206
			return $subobjectFunction->parse( new SMW\ParserParameterFormatter( $subobjectArgs ) );
207
		} else {
208
			// SMW 1.8
209
			call_user_func_array( array( 'SMWSubobject', 'render' ), $subobjectArgs );
210
		}
211
		return;
212
	}
213
	
214
	
215
	/**
216
	 * @param $wikiPage wikiPage
217
     * @param $revision revision
218
     * @param $user user
219
	 * @param struct object
220
	 * 
221
	 * @return boolean
222
     * 
223
     * Code adapted from: https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/2974
224
	*/
225
	public static function insertObjectviaJSON( $wikiPage, $revision, $user, $struct ) {
226
	
227
		$applicationFactory = \SMW\ApplicationFactory::getInstance();
228
		
229
		$mwCollaboratorFactory = $applicationFactory->newMwCollaboratorFactory();
230
		
231
		/** * Initialize the ParserOuput object */
232
		$editInfoProvider = $mwCollaboratorFactory->newEditInfoProvider( $wikiPage, $revision, $user );
233
		
234
		$parserOutput = $editInfoProvider->fetchEditInfo()->getOutput();
235
236
		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...
237
			return true;
238
		}
239
		
240
		$parserData = $applicationFactory->newParserData( $wikiPage->getTitle(), $parserOutput );
241
	
242
		$subject = $parserData->getSubject();
243
244
		$subject = new \SMW\DIWikiPage( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki() );
245
		
246
		// TODO: To finish
247
		foreach ( $struct as $property => $value ) {
248
			// Struct to iterate
249
			
250
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByText( $property, $value, false, $subject );
251
252
			$parserData->getSemanticData()->addDataValue( $dataValue );
253
254
		}
255
	
256
		// This part is used to add the subobject the the main subject
257
		$parserData->pushSemanticDataToParserOutput();
258
		$parserData->updateStore();
259
		// Below it works event with maintenance function
260
		// $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...
261
		// $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...
262
		
263
		return true;
264
	}	
265
	
266
	/**
267
	 * @param $wikiPage wikiPage
268
     * @param $revision revision
269
     * @param $user user
270
	 * @param $object string
271
	 * @param struct object
272
	 * 
273
	 * @return boolean
274
     * 
275
     * Code from: https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/2974
276
	*/
277
	public static function insertInternalObjectviaJSON( $wikiPage, $revision, $user, $object, $struct ) {
278
279
		$applicationFactory = \SMW\ApplicationFactory::getInstance();
280
		
281
		$mwCollaboratorFactory = $applicationFactory->newMwCollaboratorFactory();
282
		
283
		/** * Initialize the ParserOuput object */
284
		$editInfoProvider = $mwCollaboratorFactory->newEditInfoProvider( $wikiPage, $revision, $user );
285
		
286
		$parserOutput = $editInfoProvider->fetchEditInfo()->getOutput();
287
288
		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...
289
			return true;
290
		}
291
		
292
		$parserData = $applicationFactory->newParserData( $wikiPage->getTitle(), $parserOutput );
293
294
		$subject = $parserData->getSubject();
295
		
296
		// Identify the content as unique
297
		$subobjectName = '_SDI' . md5( json_encode( $struct ) );
298
299
		$subject = new \SMW\DIWikiPage( $subject->getDBkey(), $subject->getNamespace(), $subject->getInterwiki(), $subobjectName );
300
301
		// Build the subobject by using a separate container object
302
		$containerSemanticData = new \SMWContainerSemanticData( $subject );
303
304
		// Iterate through here
305
		
306
		foreach ( $struct as $property => $value ) {
307
			// If you don't know the type, use the DataValueFactory
308
			$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByText( $property, $value );
309
			$containerSemanticData->addDataValue( $dataValue );
310
		}
311
		
312
		// Object assignation
313
		
314
		if ( $object ) {
315
			
316
			if ( ! empty( $object ) ) {
317
				
318
				if ( $wikiPage->getTitle() ) {
319
					
320
					$fullTitle = $wikiPage->getTitle()->getPrefixedText();
321
					
322
					$dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByText( $object, $fullTitle );
323
					$containerSemanticData->addDataValue( $dataValue );
324
					
325
				}
326
				
327
			}
328
			
329
		}
330
		
331
		
332
		// This part is used to add the subobject the the main subject
333
		$parserData->getSemanticData()->addPropertyObjectValue( new \SMW\DIProperty( \SMW\DIProperty::TYPE_SUBOBJECT ), new \SMWDIContainer( $containerSemanticData ) );
334
		$parserData->pushSemanticDataToParserOutput();
335
		$parserData->updateStore();
336
337
		// Below it works event with maintenance function
338
		// $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...
339
		// $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...
340
		
341
		return true;
342
	}
343
344
345
	/**
346
	* @first -> First hash
347
	* @second -> Second hash
348
	* @key -> Actual key
349
350
	* @return variable (depending on case)
351
	*/
352
	public static function getSelector( $first, $second, $key ) {
353
		
354
		if ( key_exists( $key, $first ) ) {
355
			// Here process
356
			
357
			$array = array();
358
359
			if ( is_array( $first[ $key ] ) ) {
360
				$keyvals = $first[ $key ];
361
			} else {
362
				$keyvals = explode( ",", $first[ $key ] );
363
			}
364
			
365
			
366
			if ( self::isAssocArray( $keyvals ) ) {
367
				
368
				return $keyvals;
369
			
370
			} else {
371
			
372
				if ( count( $keyvals ) < 2 ) {
373
					// If => ergo hash
374
					
375
					$keyhvals = explode( "#", $keyvals[0], 2 );
376
	
377
					if ( count( $keyhvals ) > 1 ) {
378
						$array[ trim( $keyhvals[0] ) ] = trim( $keyhvals[1] );
379
						return $array;
380
					} else {
381
						return trim( $keyhvals[0] );
382
					}
383
				} else { 
384
	
385
					foreach ( $keyvals as $keyval ) {
386
						$keyval = trim( $keyval );
387
						
388
						// If => ergo hash
389
						$keyhvals = explode( "#", $keyval, 2 );
390
		
391
						if ( count( $keyhvals ) > 1 ) {
392
							$array[ trim( $keyhvals[0] ) ] = trim( $keyhvals[1] );
393
						}
394
						else {
395
							array_push( $array, trim( $keyhvals[0] ) );
396
						}
397
					}
398
	
399
					return $array;
400
				}
401
			
402
			}
403
404
		} else {
405
			if ( key_exists( $key, $second ) ) {
406
				// Direct
407
				return $second[$key];
408
			} else {
409
				return false;
410
			}
411
		}
412
		
413
	}
414
	
415
416
	/**
417
	 * Whether associative array or not
418
	 * $arr Array
419
	 * @return boolean
420
	*/
421
	
422
	public static function isAssocArray( array $arr ) {
423
	    if (array() === $arr) return false;
424
	    return array_keys($arr) !== range(0, count($arr) - 1);
425
	}
426
427
428
429
	/**
430
	 * Occurs after the save page request has been processed.
431
	 * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageContentSaveComplete
432
	 *
433
	 * @param text string
434
	 *
435
	 * @return boolean
436
	*/
437
	public static function processWikiText( $text, $pageTitle ) {
438
439
		// TODO: Ideally a full wikitext processing here, etc.
440
441
		if ( $text == '{{PAGENAME}}' ) {
442
			$text = $pageTitle->getText();
443
		} elseif ( $text == '{{FULLPAGENAME}}' ) {
444
			$text = $pageTitle->getPrefixedText();
445
		} 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...
446
			// Do nothing;
447
		}
448
449
		return $text;
450
	}
451
452
	
453
	private static function getJSONContent( $content ) {
454
455
		$outcome = array( );
456
		$args = null;
457
		$data = null;
458
459
		if ( $content ) {
460
			
461
			if ( is_object( $content ) ) {
462
				
463
				if ( $content->getModel() == CONTENT_MODEL_JSON ) {
464
465
					// Only act if JSON
466
					
467
					$json = $content->getNativeData();
468
469
					
470
					list( $args, $data ) = self::processJSON( $json );
471
				}
472
				
473
			}
474
		}
475
		
476
		array_push( $outcome, $args );
477
		array_push( $outcome, $data );
478
479
		return $outcome;
480
	}
481
482
	
483
	private static function processJSON( $json ) {
484
485
		$outcome = array( );
486
		$args = null;
487
		$data = null;
488
		
489
		$SDIJSON = false;
490
		
491
		// Check JSON is valid
492
		$jsonObj = json_decode( $json, true );
493
494
		if ( $jsonObj ) {
495
		
496
			if ( array_key_exists( "meta", $jsonObj ) ) {
497
				
498
				$meta = $jsonObj["meta"];
499
500
				if ( array_key_exists( "app", $meta ) ) {
501
					
502
					if ( $meta["app"] === "SDI" ) {
503
						$SDIJSON = true;
504
					}
505
					
506
				}
507
				
508
				$args = $meta;
509
				
510
				# TODO: Addding more custom fields to args
511
				
512
				
513
				if ( array_key_exists( "data", $jsonObj ) && $SDIJSON ) {
514
				
515
					$dataObj = $jsonObj["data"];
516
				
517
					$data = self::checkJSONData( $dataObj );
518
				
519
				}
520
			}
521
		
522
		}
523
524
		
525
		array_push( $outcome, $args );
526
		array_push( $outcome, $data );
527
528
		return $outcome;	
529
		
530
	}
531
	
532
	private static function checkJSONData( $dataObj ) {
533
		
534
		$data = null;
535
		
536
		if ( is_array( $dataObj ) ) {
537
			
538
			if ( count( $dataObj ) > 0 ) {
539
				
540
				$bad = false;
541
				
542
				// We should have an array of arrays
543
				foreach ( $dataObj as $row ) {
544
					
545
					if ( ! is_array( $row ) ) {
546
						$bad = true;
547
					}
548
				}
549
				
550
				if ( ! $bad ) {
551
					$data = $dataObj;
552
				}
553
				
554
			}
555
		}
556
557
			
558
		return $data;
559
	}
560
561
562
	/** Import of Wikitext, let's say, at commit */
563
	/**
564
	* @text Bulk data text
565
	* @pagetitle Title of the page
566
	* @delimiter Delimiter of CSV
567
	* @enclosure Enclosure of CSV
568
	* @num Occurrence in page. If only one, then 0
569
	* @return status of update
570
	*/
571
	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...
572
573
		$title = Title::newFromText( $pagetitle );
574
		$wikipage = WikiPage::factory( $title );
575
		
576
		# Default cases
577
		$newpage = false;
578
		$contentModel = "wikitext";
579
		
580
		$extraInfo = "";
581
582
		$ns = $title->getSubjectNsText();
583
		
584
		# Handle main namespace with _
585
		if ( $ns == "" ) {
586
			$ns = "_";
587
		}
588
589
		if ( $GLOBALS["wgSDImportDataPage"] && array_key_exists( $ns, $GLOBALS["wgSDImportDataPage"] ) ) {
590
591
			if ( $separator !== NULL ) {
592
				if ( array_key_exists( "separator", $GLOBALS["wgSDImportDataPage"][$ns] ) ) {
593
					if ( $GLOBALS["wgSDImportDataPage"][$ns]["separator"] != $separator ) {
594
						$extraInfo = $extraInfo . " separator=\"".$separator."\"";
595
					}
596
				}
597
			}
598
			if ( $delimiter !== NULL ) {
599
				if ( array_key_exists( "delimiter", $GLOBALS["wgSDImportDataPage"][$ns] ) ) {
600
					if ( $GLOBALS["wgSDImportDataPage"][$ns]["delimiter"] != $delimiter ) {
601
						$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...
602
					}
603
				}
604
			}
605
		}
606
607
		// Retrievet text of page
608
		// Back-compatibility, just in case
609
		
610
		// TODO: Handle if creation of page
611
		if ( ! $wikipage->exists() ) {
612
			$newpage = true;
613
		}
614
		
615
		if ( ! $newpage ) {
616
		
617
			if ( method_exists ( $wikipage, "getContent" ) ) {
618
				$mainContent = $wikipage->getContent();
619
				$mainText = $mainContent->getNativeData();
620
				$contentModel = $wikipage->getContentModel();
621
				
622
				if ( ! $contentModel ) {
623
					$contentModel = "wikitext";
624
				}
625
				
626
			} else {
627
				$mainText = $wikipage->getText();
628
				$contentModel = "wikitext";
629
			}
630
		
631
		}
632
633
		$status = 0;
634
		$tableText = "";
635
		
636
		# Allow only in wikitext context
637
		if ( $contentModel === "wikitext" ) {
638
		
639
		
640
			if ( ! $newpage ) {
641
				
642
				// Get matches
643
				$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...
644
		
645
				$count = 0;
646
				$outcome = array();
647
		
648
				foreach ( $page_parts as $page_part ) {
649
		
650
					if ( preg_match( "/<smwdata/", $page_part ) ) {
651
						$count = $count + 1;
652
					} else {
653
						if ( $num == $count - 1 ) {
654
							if ( preg_match( "/<\/smwdata/", $page_part ) ) {
655
		
656
								$in_parts = preg_split( "/(<\/smwdata.*?>)/", $page_part, -1, PREG_SPLIT_DELIM_CAPTURE );
657
								$in_parts[0] = "\n".$text."\n";
658
								$page_part = implode( "", $in_parts );
659
							}
660
						}
661
					}
662
		
663
					array_push( $outcome, $page_part );
664
				}
665
				
666
				// If stuff
667
				if ( count( $outcome ) > 0 ) {
668
	
669
					$tableText = implode( "", $outcome );			
670
				}
671
			
672
			} else {
673
				
674
				$tableText = "<smwdata>".$text."</smwdata>";
675
				
676
			}
677
	
678
	
679
			if ( ! empty( $tableText ) ) {
680
				
681
				// Submit content
682
				// Back-compatibility, just in case
683
				if ( method_exists ( $wikipage, "doEditContent" ) ) {
684
					$content = new WikiTextContent( $tableText );
685
					$status = $wikipage->doEditContent( $content, "Updating content" );
686
				} else {
687
					$status = $wikipage->doEdit( $tableText, "Updating content" );
688
				}
689
	
690
			}
691
			
692
			// TODO: Handle status value if not normal one
693
		
694
		}
695
696
		return $status;
697
	}
698
	
699
	
700
701
	/**
702
	* @text Bulk data text
703
	* @pagetitle Title of the page
704
	* @return status of update
705
	*/
706
707
	public static function importJSONBatch( $text, $namespace="", $overwrite=false) {
708
709
		$jsonObj = json_decode( $text, true );
710
		$dataObj = $jsonObj["data"];
711
		$dataHash = array();
712
				
713
		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...
714
715
			if ( count( $dataObj[$x] ) > 1 ) {
716
				
717
				$pageCell = array_shift(  $dataObj[$x] );
718
				
719
				if ( $pageCell !== "" ) {
720
					
721
					if ( $namespace === "" ) {
722
						$pagetitle =  $pageCell;
723
					} else {
724
						$pagetitle = $namespace . ':' . $pageCell;
725
					}	
726
					
727
				}
728
				
729
				if ( ! $dataHash[ $pagetitle ] ) {
730
					$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...
731
				}
732
				
733
				array_push( $dataHash[ $pagetitle ], $dataObj[$x] );
734
				
735
			}
736
			
737
		}
738
		
739
		foreach ( $dataHash as $pagetitle => $dataArray ) {
740
			
741
			$jsonSubObj = array();
742
			$jsonSubObj["data"] = $dataArray;
743
			$jsonSubObj["meta"] = $jsonObj["meta"];
744
745
			self::importJSON( json_encode( $jsonSubObj ), $pagetitle, $overwrite );
746
			
747
		}
748
		
749
		return true;
750
751
	}
752
753
	/** Import of JSON into a page, let's say, at commit **/
754
	/**
755
	* @text Bulk data text
756
	* @pagetitle Title of the page
757
	* @return status of update
758
	*/
759
	public static function importJSON( $text, $pagetitle, $overwrite=false) {
760
761
		$title = Title::newFromText( $pagetitle );
762
		$wikipage = WikiPage::factory( $title );
763
		$goahead = true;
764
		$status = false;
765
		// Check if exists
766
		if ( $wikipage->exists() &&  ! $overwrite ) {
767
			$goahead = false;
768
		}
769
			if ( $goahead ) {
770
				// Check compatibility. Only if newer versions of MW
771
				if ( method_exists ( $wikipage, "getContent" ) ) {
772
					$contentModel = $wikipage->getContentModel();
773
					if ( $contentModel === "json" || ! $wikipage->exists() ) {
774
						$content = new JSONContent($text);
775
						$status = $wikipage->doEditContent( $content, "Updating content" );
776
					}
777
				}
778
			}
779
		return $status;
780
	}
781
	
782
	/** TODO: TO BE UPDATED **/
783
	public static function prepareStructForJSON( $meta, $data ) {
784
		
785
		$strJSON = "";
786
		
787
		if ( $data ) {
788
			
789
			$obj = array( );
790
			
791
			// TODO: this may change in future versions
792
			$obj["meta"] = array();
793
			$obj["meta"]["app"] = "SDI";
794
			$obj["meta"]["version"] = 0.1;
795
			
796
			if ( $meta ) {
797
				
798
				if ( array_key_exists( "rowfields", $meta ) ) {
799
					$obj["meta"]["rowfields"] = $meta["rowfields"];
800
				}
801
			}
802
			
803
			$obj["data"] = $data;
804
			
805
			$strJSON = json_encode( $obj );
806
		}
807
808
		return $strJSON;
809
	}
810
	
811
812
	/**
813
	* @param $out OutputPage
814
	* @param $text string
815
	* @return $out OutputPage
816
	*/
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...
817
	
818
	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...
819
820
		// We add Modules
821
		$out->addModules( 'ext.sdimport' );
822
		
823
		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...
824
		
825
		// Get Namespace
826
		
827
		$context = RequestContext::getMain();
828
		if ( $context ) {
829
			$title = $context->getTitle();
830
			if ( $title ) {
831
				
832
				$ns = $title->getSubjectNsText();
833
				
834
				# Handle main namespace with _
835
				if ( $ns == "" ) {
836
					$ns = "_";
837
				}
838
				
839
				if ( array_key_exists( $ns, $wgSDImportDataPage ) ) {
840
					
841
					if ( array_key_exists( "form", $wgSDImportDataPage[$ns] )  ) {
842
						
843
						if ( $wgSDImportDataPage[$ns]["form"] === true ) {
844
							
845
							// Adding form libraries only if needed
846
							$out->addModules( 'ext.sdimport.form' );
847
							
848
						}
849
					}
850
				}
851
				
852
			}
853
		}
854
		
855
		return $out;
856
	}
857
	
858
	/** This allow PHP vars to be exposed to JavaScript **/
859
	
860
	public static function onResourceLoaderGetConfigVars( &$vars ) {
861
		
862
		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...
863
864
865
		$vars['wgSDImportDataPage'] = $wgSDImportDataPage;
866
867
		return true;
868
	}
869
}
870