Completed
Pull Request — master (#194)
by Nischay
02:24
created

Gallery::getSlideshowWidget()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 0
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SRF;
4
5
use SMW\ResultPrinter;
6
7
use SMWQueryResult;
8
use SMWPrintRequest;
9
use SMWDataItem;
10
use SMWOutputs;
11
use SRFUtils;
12
13
use Html;
14
use ImageGallery;
15
use Title;
16
17
/**
18
 * Result printer that outputs query results as a image gallery.
19
 *
20
 * @author Jeroen De Dauw < [email protected] >
21
 * @author mwjames
22
 * @author Rowan Rodrik van der Molen
23
 */
24
class Gallery extends ResultPrinter {
25
26
	/**
27
	 * @see SMWResultPrinter::getName
28
	 *
29
	 * @return string
30
	 */
31
	public function getName() {
32
		return $this->getContext()->msg( 'srf_printername_gallery' )->text();
33
	}
34
35
	/**
36
	 * @see SMWResultPrinter::buildResult
37
	 *
38
	 * @since 1.8
39
	 *
40
	 * @param SMWQueryResult $results
41
	 *
42
	 * @return string
43
	 */
44
	protected function buildResult( SMWQueryResult $results ) {
45
46
		// Intro/outro are not planned to work with the widget option
47
		if ( ( $this->params['intro'] !== '' || $this->params['outro'] !== '' ) && $this->params['widget'] !== '' ){
48
			return $results->addErrors( array(
49
				$this->getContext()->msg( 'srf-error-option-mix', 'widget' )->inContentLanguage()->text()
50
			) );
51
		};
52
53
		return $this->getResultText( $results, $this->outputMode );
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getResultT...ts, $this->outputMode); (array) is incompatible with the return type of the parent method SMW\ResultPrinter::buildResult of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
54
	}
55
56
	/**
57
	 * @see SMWResultPrinter::getResultText
58
	 *
59
	 * @param $results SMWQueryResult
60
	 * @param $outputmode integer
61
	 *
62
	 * @return string
63
	 */
64
	public function getResultText( SMWQueryResult $results, $outputmode ) {
0 ignored issues
show
Coding Style introduced by
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...
65
66
		$ig = new ImageGallery();
67
		$ig->setShowBytes( false );
68
		$ig->setShowFilename( false );
69
		$ig->setCaption( $this->mIntro ); // set caption to IQ header
70
71
		// No need for a special page to use the parser but for the "normal" page
72
		// view we have to ensure caption text is parsed correctly through the parser
73
		if ( !$this->isSpecialPage() ) {
74
			$ig->setParser( $GLOBALS['wgParser'] );
75
		}
76
77
		// Initialize
78
		static $statNr = 0;
79
		$html          = '';
80
		$processing    = '';
81
82
		if ( $this->params['widget'] == 'carousel' ) {
83
			// Carousel widget
84
			$ig->setAttributes( $this->getCarouselWidget() );
85
		} elseif ( $this->params['widget'] == 'slideshow' ) {
86
			// Slideshow widget
87
			$ig->setAttributes( $this->getSlideshowWidget() );
88
		} else {
89
90
			// Standard gallery attributes
91
			$attribs = array(
92
				'id' => uniqid(),
93
				'class' => $this->getImageOverlay(),
94
			);
95
96
			$ig->setAttributes( $attribs );
97
		}
98
99
		// Only use redirects where the overlay option is not used and redirect
100
		// thumb images towards a different target
101
		if ( $this->params['redirects'] !== '' && !$this->params['overlay'] ){
102
			SMWOutputs::requireResource( 'ext.srf.gallery.redirect' );
103
		}
104
105
		// For the carousel widget, the perrow option should not be set
106
		if ( $this->params['perrow'] !== '' && $this->params['widget'] !== 'carousel' ) {
107
			$ig->setPerRow( $this->params['perrow'] );
108
		}
109
110
		if ( $this->params['widths'] !== '' ) {
111
			$ig->setWidths( $this->params['widths'] );
112
		}
113
114
		if ( $this->params['heights'] !== '' ) {
115
			$ig->setHeights( $this->params['heights'] );
116
		}
117
118
		$printReqLabels = array();
119
		$redirectType = '';
120
121
		/**
122
		 * @var SMWPrintRequest $printReq
123
		 */
124
		foreach ( $results->getPrintRequests() as $printReq ) {
125
			$printReqLabels[] = $printReq->getLabel();
126
127
			// Get redirect type
128
			if ( $this->params['redirects'] === $printReq->getLabel() ){
129
			 $redirectType = $printReq->getTypeID();
130
			}
131
		}
132
133
		if ( $this->params['imageproperty'] !== '' && in_array( $this->params['imageproperty'], $printReqLabels ) ||
134
			$this->params['redirects'] !== '' && in_array( $this->params['redirects'], $printReqLabels ) ) {
135
136
			$this->addImageProperties(
137
				$results,
138
				$ig,
139
				$this->params['imageproperty'],
140
				$this->params['captionproperty'],
141
				$this->params['redirects'],
142
				$outputmode
143
			);
144
		} else {
145
			$this->addImagePages( $results, $ig );
146
		}
147
148
		// SRF Global settings
149
		SRFUtils::addGlobalJSVariables();
150
151
		// Display a processing image as long as the DOM is no ready
152
		if ( $this->params['widget'] !== '' ) {
153
			$processing = SRFUtils::htmlProcessingElement();
154
		}
155
156
		// Beautify the class selector
157
		$class = $this->params['widget'] ?  '-' . $this->params['widget'] . ' ' : '';
158
		$class = $this->params['redirects'] !== '' && $this->params['overlay'] === false ? $class . ' srf-redirect' . ' ': $class;
159
		$class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class ;
160
161
		// Separate content from result output
162
		if ( !$ig->isEmpty() ) {
163
			$attribs = array (
164
				'class'  => 'srf-gallery' . $class,
165
				'align'  => 'justify',
166
				'data-redirect-type' => $redirectType,
167
				'data-ns-text' => $this->getFileNsTextForPageLanguage()
168
			);
169
170
			$html = Html::rawElement( 'div', $attribs, $processing . $ig->toHTML() );
171
		}
172
173
		// If available, create a link that points to further results
174
		if ( $this->linkFurtherResults( $results ) ) {
175
			$html .= $this->getLink( $results, SMW_OUTPUT_HTML )->getText( SMW_OUTPUT_HTML, $this->mLinker );
176
		}
177
178
		return array( $html, 'nowiki' => true, 'isHTML' => true );
179
	}
180
181
	/**
182
	 * Handles queries where the images (and optionally their captions) are specified as properties.
183
	 *
184
	 * @since 1.5.3
185
	 *
186
	 * @param SMWQueryResult $results
187
	 * @param ImageGallery $ig
188
	 * @param string $imageProperty
189
	 * @param string $captionProperty
190
	 * @param string $redirectProperty
191
	 * @param $outputMode
192
	 */
193
	protected function addImageProperties( SMWQueryResult $results, ImageGallery &$ig, $imageProperty, $captionProperty, $redirectProperty, $outputMode ) {
194
		while ( /* array of SMWResultArray */ $rows = $results->getNext() ) { // Objects (pages)
195
			$images = array();
196
			$captions = array();
197
			$redirects = array();
198
199
			for ( $i = 0, $n = count( $rows ); $i < $n; $i++ ) { // Properties
200
				/**
201
				 * @var SMWResultArray $resultArray
202
				 * @var SMWDataValue $dataValue
203
				 */
204
				$resultArray = $rows[$i];
205
206
				$label = $resultArray->getPrintRequest()->getMode() == SMWPrintRequest::PRINT_THIS
207
					? '-' : $resultArray->getPrintRequest()->getLabel();
208
209
				// Make sure always use real label here otherwise it results in an empty array
210
				if ( $resultArray->getPrintRequest()->getLabel() == $imageProperty ) {
211
					while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
212
						if ( $dataValue->getTypeID() == '_wpg' ) {
213
							$images[] = $dataValue->getTitle();
214
						}
215
					}
216
				} elseif ( $label == $captionProperty ) {
217
					while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
218
						$captions[] = $dataValue->getShortText( $outputMode, $this->getLinker( true ) );
219
					}
220
				} elseif ( $label == $redirectProperty ) {
221
					while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
222
						if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
223
							$redirects[] = $dataValue->getTitle();
224
						} elseif ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_URI  ) {
225
						  $redirects[] = $dataValue->getURL();
226
						}
227
					}
228
				}
229
			}
230
231
			// Check available matches against captions
232
			$amountMatches = count( $captions ) == count( $images );
233
			$hasCaption = $amountMatches || count( $captions ) > 0;
234
235
			// Check available matches against redirects
236
			$amountRedirects = count( $redirects ) == count( $images );
237
			$hasRedirect = $amountRedirects || count( $redirects ) > 0;
238
239
			/**
240
			 * @var Title $imgTitle
241
			 */
242
			foreach ( $images as $imgTitle ) {
243
				if ( $imgTitle->exists() ) {
244
					$imgCaption = $hasCaption ? ( $amountMatches ? array_shift( $captions ) : $captions[0] ) : '';
245
					$imgRedirect = $hasRedirect ? ( $amountRedirects ? array_shift( $redirects ) : $redirects[0] ) : '';
246
					$this->addImageToGallery( $ig, $imgTitle, $imgCaption, $imgRedirect );
247
				}
248
			}
249
		}
250
	}
251
252
	/**
253
	 * Handles queries where the result objects are image pages.
254
	 *
255
	 * @since 1.5.3
256
	 *
257
	 * @param SMWQueryResult $results
258
	 * @param ImageGallery $ig
259
	 */
260
	protected function addImagePages( SMWQueryResult $results, ImageGallery &$ig ) {
261
		while ( $row = $results->getNext() ) {
262
			/**
263
			 * @var SMWResultArray $firstField
264
			 */
265
			$firstField = $row[0];
266
			$nextObject = $firstField->getNextDataValue();
267
268
			if ( $nextObject !== false ) {
269
				$imgTitle = $nextObject->getTitle();
270
271
				// Ensure the title belongs to the image namespace
272
				if ( $imgTitle instanceof Title && $imgTitle->getNamespace() === NS_FILE ) {
0 ignored issues
show
Bug introduced by
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...
273
					$imgCaption = '';
274
275
					// Is there a property queried for display with ?property
276
					if ( isset( $row[1] ) ) {
277
						$imgCaption = $row[1]->getNextDataValue();
278
						if ( is_object( $imgCaption ) ) {
279
							$imgCaption = $imgCaption->getShortText( $this->outputMode, $this->getLinker( true ) );
280
						}
281
					}
282
283
					$this->addImageToGallery( $ig, $imgTitle, $imgCaption );
284
				}
285
			}
286
		}
287
	}
288
289
	/**
290
	 * Adds a single image to the gallery.
291
	 * Takes care of automatically adding a caption when none is provided and parsing it's wikitext.
292
	 *
293
	 * @since 1.5.3
294
	 *
295
	 * @param ImageGallery $ig The gallery to add the image to
296
	 * @param Title $imgTitle The title object of the page of the image
297
	 * @param string $imgCaption An optional caption for the image
298
	 * @param string $imgRedirect
299
	 */
300
	protected function addImageToGallery( ImageGallery &$ig, Title $imgTitle, $imgCaption, $imgRedirect = '' ) {
301
302
		if ( empty( $imgCaption ) ) {
303
			if ( $this->m_params['autocaptions'] ) {
0 ignored issues
show
Deprecated Code introduced by
The property SMW\ResultPrinter::$m_params has been deprecated with message: Use $params instead. Will be removed in 1.10.

This property 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 property will be removed from the class and what other property to use instead.

Loading history...
304
				$imgCaption = $imgTitle->getBaseText();
305
306
				if ( !$this->m_params['fileextensions'] ) {
0 ignored issues
show
Deprecated Code introduced by
The property SMW\ResultPrinter::$m_params has been deprecated with message: Use $params instead. Will be removed in 1.10.

This property 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 property will be removed from the class and what other property to use instead.

Loading history...
307
					$imgCaption = preg_replace( '#\.[^.]+$#', '', $imgCaption );
308
				}
309
			} else {
310
				$imgCaption = '';
311
			}
312
		} else {
313
			if ( $imgTitle instanceof Title && $imgTitle->getNamespace() == NS_FILE && !$this->isSpecialPage() ) {
0 ignored issues
show
Bug introduced by
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...
314
				$imgCaption = $ig->mParser->recursiveTagParse( $imgCaption );
315
			}
316
		}
317
		// Use image alt as helper for either text
318
		$imgAlt =  $this->params['redirects'] === '' ? $imgCaption : $imgRedirect !== '' ? $imgRedirect : '' ;
319
320
		if ($this->params['lightgallery']) {
321
			$file = wfFindFile( $imgTitle );
322
			if ( $file && $file->exists() ) {
323
				$url = $file->getUrl();
324
				$ig->add( $imgTitle, $imgCaption, $imgAlt, $url );
325
			} else { // Not sure what to do here
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...
326
				// $ig->add( $imgTitle, $imgCaption, $imgAlt );
327
			}
328
		} else {
329
			$ig->add( $imgTitle, $imgCaption, $imgAlt );
330
		}
331
	}
332
333
	/**
334
	 * Returns the overlay setting
335
	 *
336
	 * @since 1.8
337
	 *
338
	 * @return string
339
	 */
340
	private function getImageOverlay() {
341
		if ( array_key_exists( 'overlay', $this->params ) && $this->params['overlay'] == true ) {
342
			SMWOutputs::requireResource( 'ext.srf.gallery.overlay' );
343
			return ' srf-overlay';
344
		} else if ( array_key_exists( 'lightgallery', $this->params ) && $this->params['lightgallery'] == true ) {
345
			SMWOutputs::requireResource( 'ext.srf.gallery.lightgallery' );
346
			return ' srf-lightgallery';
347
		} else {
348
			return '';
349
		}
350
	}
351
352
	/**
353
	 * Init carousel widget
354
	 *
355
	 * @since 1.8
356
	 *
357
	 * @return string
358
	 */
359
	private function getCarouselWidget() {
360
361
		// Set attributes for jcarousel
362
		$dataAttribs = array(
363
			'wrap' => 'both', // Whether to wrap at the first/last item (or both) and jump back to the start/end.
364
			'vertical' => 'false', // Orientation: vertical = false means horizontal
365
			'rtl' => 'false', // Directionality: rtl = false means ltr
366
		);
367
368
		// Use the perrow parameter to determine the scroll sequence.
369
		if ( empty( $this->params['perrow'] ) ) {
370
			$dataAttribs['scroll'] = 1;  // default 1
371
		} else {
372
			$dataAttribs['scroll'] = $this->params['perrow'];
373
			$dataAttribs['visible'] = $this->params['perrow'];
374
		}
375
376
		$attribs = array(
377
			'id' => uniqid(),
378
			'class' => 'jcarousel jcarousel-skin-smw' . $this->getImageOverlay(),
379
			'style' => 'display:none;',
380
		);
381
382
		foreach ( $dataAttribs as $name => $value ) {
383
			$attribs['data-' . $name] = $value;
384
		}
385
386
		SMWOutputs::requireResource( 'ext.srf.gallery.carousel' );
387
388
		return $attribs;
389
	}
390
391
392
	/**
393
	 * Init slideshow widget
394
	 *
395
	 * @since 1.8
396
	 *
397
	 * @return string
398
	 */
399
	private function getSlideshowWidget() {
400
401
		$attribs = array(
402
			'id'    => uniqid(),
403
			'class' => $this->getImageOverlay(),
404
			'style' => 'display:none;',
405
			'data-nav-control' => $this->params['navigation']
406
		);
407
408
		SMWOutputs::requireResource( 'ext.srf.gallery.slideshow' );
409
410
		return $attribs;
411
	}
412
413
	/**
414
	 * @see SMWResultPrinter::getParamDefinitions
415
	 *
416
	 * @since 1.8
417
	 *
418
	 * @param $definitions array of IParamDefinition
419
	 *
420
	 * @return array of IParamDefinition|array
421
	 */
422
	public function getParamDefinitions( array $definitions ) {
423
		$params = parent::getParamDefinitions( $definitions );
424
425
		$params['class'] = array(
426
			'type' => 'string',
427
			'message' => 'srf-paramdesc-class',
428
			'default' => ''
429
		);
430
431
		$params['widget'] = array(
432
			'type' => 'string',
433
			'default' => '',
434
			'message' => 'srf-paramdesc-widget',
435
			'values' => array( 'carousel', 'slideshow', '' )
436
		);
437
438
		$params['navigation'] = array(
439
			'type' => 'string',
440
			'default' => 'nav',
441
			'message' => 'srf-paramdesc-navigation',
442
			'values' => array( 'nav', 'pager', 'auto' )
443
		);
444
445
		$params['overlay'] = array(
446
			'type' => 'boolean',
447
			'default' => false,
448
			'message' => 'srf-paramdesc-overlay'
449
		);
450
451
		$params['lightgallery'] = array(
452
			'type' => 'boolean',
453
			'default' => false,
454
			'message' => 'srf-paramdesc-lightgallery'
455
		);
456
457
		$params['perrow'] = array(
458
			'type' => 'integer',
459
			'default' => '',
460
			'message' => 'srf_paramdesc_perrow'
461
		);
462
463
		$params['widths'] = array(
464
			'type' => 'integer',
465
			'default' => '',
466
			'message' => 'srf_paramdesc_widths'
467
		);
468
469
		$params['heights'] = array(
470
			'type' => 'integer',
471
			'default' => '',
472
			'message' => 'srf_paramdesc_heights'
473
		);
474
475
		$params['autocaptions'] = array(
476
			'type' => 'boolean',
477
			'default' => true,
478
			'message' => 'srf_paramdesc_autocaptions'
479
		);
480
481
		$params['fileextensions'] = array(
482
			'type' => 'boolean',
483
			'default' => false,
484
			'message' => 'srf_paramdesc_fileextensions'
485
		);
486
487
		$params['captionproperty'] = array(
488
			'type' => 'string',
489
			'default' => '',
490
			'message' => 'srf_paramdesc_captionproperty'
491
		);
492
493
		$params['imageproperty'] = array(
494
			'type' => 'string',
495
			'default' => '',
496
			'message' => 'srf_paramdesc_imageproperty'
497
		);
498
499
		$params['redirects'] = array(
500
			'type' => 'string',
501
			'default' => '',
502
			'message' => 'srf-paramdesc-redirects'
503
		);
504
505
		return $params;
506
	}
507
508
	private function isSpecialPage() {
509
		$title = $this->getContext()->getTitle();
510
		return $title instanceof Title && $title->isSpecialPage();
0 ignored issues
show
Bug introduced by
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...
511
	}
512
513
	private function getFileNsTextForPageLanguage() {
514
		$title = $this->getContext()->getTitle();
515
		return $title instanceof Title ? $title->getPageLanguage()->getNsText( NS_FILE ) : null;
0 ignored issues
show
Bug introduced by
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...
516
	}
517
518
}
519