Completed
Push — rmus ( 2d679e )
by Jeroen De
110:41 queued 108:21
created

Gallery::addImageToGallery()   B

Complexity

Conditions 9
Paths 20

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 14.8607

Importance

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