Completed
Push — master ( 9b2ed5...981814 )
by Jeroen De
76:07
created

Gallery   F

Complexity

Total Complexity 79

Size/Duplication

Total Lines 488
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 52.38%

Importance

Changes 0
Metric Value
wmc 79
lcom 1
cbo 7
dl 0
loc 488
ccs 88
cts 168
cp 0.5238
rs 2.08
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 3 1
A buildResult() 0 15 4
F getResultText() 0 119 24
F addImageProperties() 0 59 21
B addImagePages() 0 28 8
B addImageToGallery() 0 21 9
A getImageOverlay() 0 8 3
A getCarouselWidget() 0 31 3
A getSlideshowWidget() 0 13 1
B getParamDefinitions() 0 79 1
A isSpecialPage() 0 4 2
A getFileNsTextForPageLanguage() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like Gallery 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 Gallery, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SRF;
4
5
use Html;
6
use SMW\ResultPrinter;
7
use SMWDataItem;
8
use SMWOutputs;
9
use SMWPrintRequest;
10
use SMWQueryResult;
11
use SRFUtils;
12
use Title;
13
use TraditionalImageGallery;
14
15
/**
16
 * Result printer that outputs query results as a image gallery.
17
 *
18
 * @author Jeroen De Dauw < [email protected] >
19
 * @author mwjames
20
 * @author Rowan Rodrik van der Molen
21
 */
22
class Gallery extends ResultPrinter {
23
24
	/**
25
	 * @see SMWResultPrinter::getName
26
	 *
27
	 * @return string
28
	 */
29
	public function getName() {
30
		return $this->msg( 'srf_printername_gallery' )->text();
31
	}
32
33
	/**
34
	 * @see SMWResultPrinter::buildResult
35
	 *
36
	 * @since 1.8
37
	 *
38
	 * @param SMWQueryResult $results
39
	 *
40
	 * @return string
41
	 */
42 1
	protected function buildResult( SMWQueryResult $results ) {
43
44
		// Intro/outro are not planned to work with the widget option
45 1
		if ( ( $this->params['intro'] !== '' || $this->params['outro'] !== '' ) && $this->params['widget'] !== '' ) {
46
			$results->addErrors(
47
				[
48
					$this->msg( 'srf-error-option-mix', 'widget' )->inContentLanguage()->text()
49
				]
50
			);
51
52
			return '';
53
		};
54
55 1
		return $this->getResultText( $results, $this->outputMode );
56
	}
57
58
	/**
59
	 * @see SMWResultPrinter::getResultText
60
	 *
61
	 * @param $results SMWQueryResult
62
	 * @param $outputmode integer
63
	 *
64
	 * @return string | array
65
	 */
66 1
	public function getResultText( SMWQueryResult $results, $outputmode ) {
0 ignored issues
show
Coding Style introduced by Jeroen De Dauw
getResultText 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...
67
68 1
		$ig = new TraditionalImageGallery();
69
70 1
		$ig->setShowBytes( false );
71 1
		$ig->setShowFilename( false );
72
73 1
		if ( method_exists( $ig, 'setShowDimensions' ) ) {
74
			$ig->setShowDimensions( false );
75
		}
76
77 1
		$ig->setCaption( $this->mIntro ); // set caption to IQ header
78
79
		// No need for a special page to use the parser but for the "normal" page
80
		// view we have to ensure caption text is parsed correctly through the parser
81 1
		if ( !$this->isSpecialPage() ) {
82 1
			$ig->setParser( $GLOBALS['wgParser'] );
83
		}
84
85 1
		$html = '';
86 1
		$processing = '';
87
88 1
		if ( $this->params['widget'] == 'carousel' ) {
89
			// Carousel widget
90
			$ig->setAttributes( $this->getCarouselWidget() );
91 1
		} elseif ( $this->params['widget'] == 'slideshow' ) {
92
			// Slideshow widget
93
			$ig->setAttributes( $this->getSlideshowWidget() );
94
		} else {
95
96
			// Standard gallery attributes
97
			$attribs = [
98 1
				'id' => uniqid(),
99 1
				'class' => $this->getImageOverlay(),
100
			];
101
102 1
			$ig->setAttributes( $attribs );
103
		}
104
105
		// Only use redirects where the overlay option is not used and redirect
106
		// thumb images towards a different target
107 1
		if ( $this->params['redirects'] !== '' && !$this->params['overlay'] ) {
108
			SMWOutputs::requireResource( 'ext.srf.gallery.redirect' );
109
		}
110
111
		// For the carousel widget, the perrow option should not be set
112 1
		if ( $this->params['perrow'] !== '' && $this->params['widget'] !== 'carousel' ) {
113
			$ig->setPerRow( $this->params['perrow'] );
114
		}
115
116 1
		if ( $this->params['widths'] !== '' ) {
117
			$ig->setWidths( $this->params['widths'] );
118
		}
119
120 1
		if ( $this->params['heights'] !== '' ) {
121
			$ig->setHeights( $this->params['heights'] );
122
		}
123
124 1
		$printReqLabels = [];
125 1
		$redirectType = '';
126
127
		/**
128
		 * @var SMWPrintRequest $printReq
129
		 */
130 1
		foreach ( $results->getPrintRequests() as $printReq ) {
131 1
			$printReqLabels[] = $printReq->getLabel();
132
133
			// Get redirect type
134 1
			if ( $this->params['redirects'] === $printReq->getLabel() ) {
135 1
				$redirectType = $printReq->getTypeID();
136
			}
137
		}
138
139 1
		if ( $this->params['imageproperty'] !== '' && in_array( $this->params['imageproperty'], $printReqLabels ) ||
140 1
			$this->params['redirects'] !== '' && in_array( $this->params['redirects'], $printReqLabels ) ) {
141
142
			$this->addImageProperties(
143
				$results,
144
				$ig,
145
				$this->params['imageproperty'],
146
				$this->params['captionproperty'],
147
				$this->params['redirects'],
148
				$outputmode
149
			);
150
		} else {
151 1
			$this->addImagePages( $results, $ig );
152
		}
153
154
		// SRF Global settings
155 1
		SRFUtils::addGlobalJSVariables();
156
157
		// Display a processing image as long as the DOM is no ready
158 1
		if ( $this->params['widget'] !== '' ) {
159
			$processing = SRFUtils::htmlProcessingElement();
160
		}
161
162
		// Beautify the class selector
163 1
		$class = $this->params['widget'] ? '-' . $this->params['widget'] . ' ' : '';
164 1
		$class = $this->params['redirects'] !== '' && $this->params['overlay'] === false ? $class . ' srf-redirect' . ' ' : $class;
165 1
		$class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class;
166
167
		// Separate content from result output
168 1
		if ( !$ig->isEmpty() ) {
169
			$attribs = [
170 1
				'class' => 'srf-gallery' . $class,
171 1
				'data-redirect-type' => $redirectType,
172 1
				'data-ns-text' => $this->getFileNsTextForPageLanguage()
173
			];
174
175 1
			$html = Html::rawElement( 'div', $attribs, $processing . $ig->toHTML() );
176
		}
177
178
		// If available, create a link that points to further results
179 1
		if ( $this->linkFurtherResults( $results ) ) {
180
			$html .= $this->getLink( $results, SMW_OUTPUT_HTML )->getText( SMW_OUTPUT_HTML, $this->mLinker );
181
		}
182
183 1
		return [ $html, 'nowiki' => true, 'isHTML' => true ];
184
	}
185
186
	/**
187
	 * Handles queries where the images (and optionally their captions) are specified as properties.
188
	 *
189
	 * @since 1.5.3
190
	 *
191
	 * @param SMWQueryResult $results
192
	 * @param TraditionalImageGallery $ig
193
	 * @param string $imageProperty
194
	 * @param string $captionProperty
195
	 * @param string $redirectProperty
196
	 * @param $outputMode
197
	 */
198
	protected function addImageProperties( SMWQueryResult $results, &$ig, $imageProperty, $captionProperty, $redirectProperty, $outputMode ) {
199
		while ( /* array of SMWResultArray */
200
		$rows = $results->getNext() ) { // Objects (pages)
201
			$images = [];
202
			$captions = [];
203
			$redirects = [];
204
205
			for ( $i = 0, $n = count( $rows ); $i < $n; $i++ ) { // Properties
206
				/**
207
				 * @var \SMWResultArray $resultArray
208
				 * @var \SMWDataValue $dataValue
209
				 */
210
				$resultArray = $rows[$i];
211
212
				$label = $resultArray->getPrintRequest()->getMode() == SMWPrintRequest::PRINT_THIS
213
					? '-' : $resultArray->getPrintRequest()->getLabel();
214
215
				// Make sure always use real label here otherwise it results in an empty array
216
				if ( $resultArray->getPrintRequest()->getLabel() == $imageProperty ) {
217
					while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
218
						if ( $dataValue->getTypeID() == '_wpg' ) {
219
							$images[] = $dataValue->getTitle();
220
						}
221
					}
222
				} elseif ( $label == $captionProperty ) {
223
					while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
224
						$captions[] = $dataValue->getShortText( $outputMode, $this->getLinker( true ) );
225
					}
226
				} elseif ( $label == $redirectProperty ) {
227
					while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
228
						if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
229
							$redirects[] = $dataValue->getTitle();
230
						} elseif ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_URI ) {
231
							$redirects[] = $dataValue->getURL();
232
						}
233
					}
234
				}
235
			}
236
237
			// Check available matches against captions
238
			$amountMatches = count( $captions ) == count( $images );
239
			$hasCaption = $amountMatches || count( $captions ) > 0;
240
241
			// Check available matches against redirects
242
			$amountRedirects = count( $redirects ) == count( $images );
243
			$hasRedirect = $amountRedirects || count( $redirects ) > 0;
244
245
			/**
246
			 * @var Title $imgTitle
247
			 */
248
			foreach ( $images as $imgTitle ) {
249
				if ( $imgTitle->exists() ) {
250
					$imgCaption = $hasCaption ? ( $amountMatches ? array_shift( $captions ) : $captions[0] ) : '';
251
					$imgRedirect = $hasRedirect ? ( $amountRedirects ? array_shift( $redirects ) : $redirects[0] ) : '';
252
					$this->addImageToGallery( $ig, $imgTitle, $imgCaption, $imgRedirect );
253
				}
254
			}
255
		}
256
	}
257
258
	/**
259
	 * Handles queries where the result objects are image pages.
260
	 *
261
	 * @since 1.5.3
262
	 *
263
	 * @param SMWQueryResult $results
264
	 * @param TraditionalImageGallery $ig
265
	 */
266 1
	protected function addImagePages( SMWQueryResult $results, &$ig ) {
267 1
		while ( $row = $results->getNext() ) {
268
			/**
269
			 * @var \SMWResultArray $firstField
270
			 */
271 1
			$firstField = $row[0];
272 1
			$nextObject = $firstField->getNextDataValue();
273
274 1
			if ( $nextObject !== false ) {
275 1
				$imgTitle = method_exists( $nextObject, 'getTitle' ) ? $nextObject->getTitle() : null;
276
277
				// Ensure the title belongs to the image namespace
278 1
				if ( $imgTitle instanceof Title && $imgTitle->getNamespace() === NS_FILE ) {
0 ignored issues
show
Bug introduced by mwjames
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
279 1
					$imgCaption = '';
280
281
					// Is there a property queried for display with ?property
282 1
					if ( isset( $row[1] ) ) {
283 1
						$imgCaption = $row[1]->getNextDataValue();
284 1
						if ( is_object( $imgCaption ) ) {
285 1
							$imgCaption = $imgCaption->getShortText( $this->outputMode, $this->getLinker( true ) );
286
						}
287
					}
288
289 1
					$this->addImageToGallery( $ig, $imgTitle, $imgCaption );
290
				}
291
			}
292
		}
293 1
	}
294
295
	/**
296
	 * Adds a single image to the gallery.
297
	 * Takes care of automatically adding a caption when none is provided and parsing it's wikitext.
298
	 *
299
	 * @since 1.5.3
300
	 *
301
	 * @param TraditionalImageGallery $ig The gallery to add the image to
302
	 * @param Title $imgTitle The title object of the page of the image
303
	 * @param string $imgCaption An optional caption for the image
304
	 * @param string $imgRedirect
305
	 */
306 1
	protected function addImageToGallery( &$ig, Title $imgTitle, $imgCaption, $imgRedirect = '' ) {
307
308 1
		if ( empty( $imgCaption ) ) {
309
			if ( $this->params['autocaptions'] ) {
310
				$imgCaption = $imgTitle->getBaseText();
311
312
				if ( !$this->params['fileextensions'] ) {
313
					$imgCaption = preg_replace( '#\.[^.]+$#', '', $imgCaption );
314
				}
315
			} else {
316
				$imgCaption = '';
317
			}
318
		} else {
319 1
			if ( $imgTitle instanceof Title && $imgTitle->getNamespace() == NS_FILE && !$this->isSpecialPage() ) {
0 ignored issues
show
Bug introduced by mwjames
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
320 1
				$imgCaption = $ig->mParser->recursiveTagParse( $imgCaption );
321
			}
322
		}
323
		// Use image alt as helper for either text
324 1
		$imgAlt = $this->params['redirects'] === '' ? $imgCaption : $imgRedirect !== '' ? $imgRedirect : '';
325 1
		$ig->add( $imgTitle, $imgCaption, $imgAlt );
326 1
	}
327
328
	/**
329
	 * Returns the overlay setting
330
	 *
331
	 * @since 1.8
332
	 *
333
	 * @return string
334
	 */
335 1
	private function getImageOverlay() {
336 1
		if ( array_key_exists( 'overlay', $this->params ) && $this->params['overlay'] == true ) {
337
			SMWOutputs::requireResource( 'ext.srf.gallery.overlay' );
338
			return ' srf-overlay';
339
		} else {
340 1
			return '';
341
		}
342
	}
343
344
	/**
345
	 * Init carousel widget
346
	 *
347
	 * @since 1.8
348
	 *
349
	 * @return string[]
350
	 */
351
	private function getCarouselWidget() {
352
353
		// Set attributes for jcarousel
354
		$dataAttribs = [
355
			'wrap' => 'both', // Whether to wrap at the first/last item (or both) and jump back to the start/end.
356
			'vertical' => 'false', // Orientation: vertical = false means horizontal
357
			'rtl' => 'false', // Directionality: rtl = false means ltr
358
		];
359
360
		// Use the perrow parameter to determine the scroll sequence.
361
		if ( empty( $this->params['perrow'] ) ) {
362
			$dataAttribs['scroll'] = 1;  // default 1
363
		} else {
364
			$dataAttribs['scroll'] = $this->params['perrow'];
365
			$dataAttribs['visible'] = $this->params['perrow'];
366
		}
367
368
		$attribs = [
369
			'id' => uniqid(),
370
			'class' => 'jcarousel jcarousel-skin-smw' . $this->getImageOverlay(),
371
			'style' => 'display:none;',
372
		];
373
374
		foreach ( $dataAttribs as $name => $value ) {
375
			$attribs['data-' . $name] = $value;
376
		}
377
378
		SMWOutputs::requireResource( 'ext.srf.gallery.carousel' );
379
380
		return $attribs;
381
	}
382
383
	/**
384
	 * Init slideshow widget
385
	 *
386
	 * @since 1.8
387
	 *
388
	 * @return string[]
389
	 */
390
	private function getSlideshowWidget() {
391
392
		$attribs = [
393
			'id' => uniqid(),
394
			'class' => $this->getImageOverlay(),
395
			'style' => 'display:none;',
396
			'data-nav-control' => $this->params['navigation']
397
		];
398
399
		SMWOutputs::requireResource( 'ext.srf.gallery.slideshow' );
400
401
		return $attribs;
402
	}
403
404
	/**
405
	 * @see SMWResultPrinter::getParamDefinitions
406
	 *
407
	 * @since 1.8
408
	 *
409
	 * @param $definitions array of IParamDefinition
410
	 *
411
	 * @return array of IParamDefinition|array
412
	 */
413 1
	public function getParamDefinitions( array $definitions ) {
414 1
		$params = parent::getParamDefinitions( $definitions );
415
416 1
		$params['class'] = [
417
			'type' => 'string',
418
			'message' => 'srf-paramdesc-class',
419
			'default' => ''
420
		];
421
422 1
		$params['widget'] = [
423
			'type' => 'string',
424
			'default' => '',
425
			'message' => 'srf-paramdesc-widget',
426
			'values' => [ 'carousel', 'slideshow', '' ]
427
		];
428
429 1
		$params['navigation'] = [
430
			'type' => 'string',
431
			'default' => 'nav',
432
			'message' => 'srf-paramdesc-navigation',
433
			'values' => [ 'nav', 'pager', 'auto' ]
434
		];
435
436 1
		$params['overlay'] = [
437
			'type' => 'boolean',
438
			'default' => false,
439
			'message' => 'srf-paramdesc-overlay'
440
		];
441
442 1
		$params['perrow'] = [
443
			'type' => 'integer',
444
			'default' => '',
445
			'message' => 'srf_paramdesc_perrow'
446
		];
447
448 1
		$params['widths'] = [
449
			'type' => 'integer',
450
			'default' => '',
451
			'message' => 'srf_paramdesc_widths'
452
		];
453
454 1
		$params['heights'] = [
455
			'type' => 'integer',
456
			'default' => '',
457
			'message' => 'srf_paramdesc_heights'
458
		];
459
460 1
		$params['autocaptions'] = [
461
			'type' => 'boolean',
462
			'default' => true,
463
			'message' => 'srf_paramdesc_autocaptions'
464
		];
465
466 1
		$params['fileextensions'] = [
467
			'type' => 'boolean',
468
			'default' => false,
469
			'message' => 'srf_paramdesc_fileextensions'
470
		];
471
472 1
		$params['captionproperty'] = [
473
			'type' => 'string',
474
			'default' => '',
475
			'message' => 'srf_paramdesc_captionproperty'
476
		];
477
478 1
		$params['imageproperty'] = [
479
			'type' => 'string',
480
			'default' => '',
481
			'message' => 'srf_paramdesc_imageproperty'
482
		];
483
484 1
		$params['redirects'] = [
485
			'type' => 'string',
486
			'default' => '',
487
			'message' => 'srf-paramdesc-redirects'
488
		];
489
490 1
		return $params;
491
	}
492
493
	/**
494
	 * @return bool
495
	 */
496 1
	private function isSpecialPage() {
0 ignored issues
show
Coding Style introduced by mwjames
isSpecialPage 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...
497 1
		$title = $GLOBALS['wgTitle'];
498 1
		return $title instanceof Title && $title->isSpecialPage();
0 ignored issues
show
Bug introduced by mwjames
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
499
	}
500
501
	/**
502
	 * @return bool|null|string
503
	 */
504 1
	private function getFileNsTextForPageLanguage() {
0 ignored issues
show
Coding Style introduced by mwjames
getFileNsTextForPageLanguage 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...
505 1
		$title = $GLOBALS['wgTitle'];
506 1
		return $title instanceof Title ? $title->getPageLanguage()->getNsText( NS_FILE ) : null;
0 ignored issues
show
Bug introduced by mwjames
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
507
	}
508
509
}
510