Completed
Push — master ( a1bdd0...80a64d )
by mw
130:13 queued 115:01
created

SMWPropertyPage::doQuerySubjectListWithValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 2
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
use SMW\ApplicationFactory;
4
use SMW\DataValueFactory;
5
use SMW\Localizer;
6
use SMW\RequestOptions;
7
use SMW\StringCondition;
8
use SMW\PropertyRegistry;
9
use SMWDataValue as DataValue;
10
use SMW\DIProperty;
11
12
/**
13
 * Implementation of MediaWiki's Article that shows additional information on
14
 * property pages. Very similar to CategoryPage, but with different printout
15
 * that also displays values for each subject with the given property.
16
 *
17
 * @ingroup SMW
18
 *
19
 * @author Markus Krötzsch
20
 */
21
class SMWPropertyPage extends SMWOrderedListPage {
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...
22
23
	/**
24
	 * @see SMWOrderedListPage::initParameters()
25
	 * @note We use a smaller limit here; property pages might become large.
26
	 */
27
	protected function initParameters() {
28
		global $smwgPropertyPagingLimit;
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...
29
		$this->limit = $smwgPropertyPagingLimit;
30
		$this->mProperty = DIProperty::newFromUserLabel( $this->mTitle->getText() );
31
		$this->store = ApplicationFactory::getInstance()->getStore();
32
		return true;
33
	}
34
35
	/**
36
	 * Returns the HTML which is added to $wgOut after the article text.
37
	 *
38
	 * @return string
39
	 */
40
	protected function getHtml() {
41
42
		if ( !$this->store->getRedirectTarget( $this->mProperty )->equals( $this->mProperty ) ) {
43
			return '';
44
		}
45
46
		$list = $this->getSubpropertyList() . $this->getPropertyValueList();
47
		$result = ( $list !== '' ? Html::element( 'div', array( 'id' => 'smwfootbr' ) ) . $list : '' );
48
49
		return $result;
50
	}
51
52
	/**
53
	 * Returns an introductory text for a predefined property
54
	 *
55
	 * @note In order to enable a more detailed description for a specific
56
	 * predefined property a concatenated message key can be used (e.g
57
	 * 'smw-pa-property-predefined' + <internal property key> => '_asksi' )
58
	 *
59
	 * @since 1.9
60
	 *
61
	 * @return string
62
	 */
63
	protected function getIntroductoryText() {
64
		$propertyName = htmlspecialchars( $this->mTitle->getText() );
65
		$message = '';
66
67
		if ( $this->mProperty->isUserDefined() ) {
68
			return $message;
69
		}
70
71
		$key = $this->mProperty->getKey();
72
73
		if ( ( $messageKey = PropertyRegistry::getInstance()->findPropertyDescriptionMsgKeyById( $key ) ) !== '' ) {
74
			$messageKeyLong = $messageKey . '-long';
75
		} else {
76
			$messageKey = 'smw-pa-property-predefined' . strtolower( $key );
77
			$messageKeyLong = 'smw-pa-property-predefined-long' . strtolower( $key );
78
		}
79
80
		$message .= wfMessage( $messageKey )->exists() ? wfMessage( $messageKey, $propertyName )->parse() : wfMessage( 'smw-pa-property-predefined-default' )->parse();
81
		$message .= wfMessage( $messageKeyLong )->exists() ? ' ' . wfMessage( $messageKeyLong )->parse() : '';
82
		$message .= ' ' . wfMessage( 'smw-pa-property-predefined-common' )->parse();
83
84
		return Html::rawElement( 'div', array( 'class' => 'smw-property-predefined-intro' ), $message );
85
	}
86
87
	protected function getTopIndicator() {
88
89
		$propertyName = htmlspecialchars( $this->mTitle->getText() );
90
91
		$usageCountHtml = '';
92
		$requestOptions = new RequestOptions();
93
		$requestOptions->limit = 1;
94
		$requestOptions->addStringCondition( $propertyName, StringCondition::STRCOND_PRE );
95
		$cachedLookupList = $this->store->getPropertiesSpecial( $requestOptions );
96
		$usageList = $cachedLookupList->fetchList();
97
98
		if ( $usageList && $usageList !== array() ) {
99
			$usage = end( $usageList );
100
			$usageCount = $usage[1];
101
			$usageCountHtml = Html::rawElement(
102
				'div', array(
103
					'title' => $this->getContext()->getLanguage()->timeanddate( $cachedLookupList->getTimestamp() ),
104
					'class' => 'smw-page-indicator usage-count' . ( $usageCount < 25000 ? ( $usageCount > 5000 ? ' moderate' : '' ) : ' high' ) ),
105
				$usageCount
106
			);
107
		}
108
109
		return Html::rawElement( 'div', array(), Html::rawElement(
110
				'div', array(
111
				'class' => 'smw-page-indicator property-type',
112
				'title' => wfMessage( 'smw-page-indicator-type-info', $this->mProperty->isUserDefined() )->parse()
113
			), ( $this->mProperty->isUserDefined() ? 'U' : 'S' )
114
		) . $usageCountHtml );
115
	}
116
117
	/**
118
	 * Get the HTML for displaying subproperties of this property. This list
119
	 * is usually short and we implement no additional navigation.
120
	 *
121
	 * @return string
122
	 */
123
	protected function getSubpropertyList() {
124
125
		$options = new SMWRequestOptions();
126
		$options->sort = true;
127
		$options->ascending = true;
128
		$subproperties = $this->store->getPropertySubjects( new SMW\DIProperty( '_SUBP' ), $this->getDataItem(), $options );
129
130
		$result = '';
131
132
		$resultCount = count( $subproperties );
133
		if ( $resultCount > 0 ) {
134
			$titleText = htmlspecialchars( $this->mTitle->getText() );
135
			$result .= "<div id=\"mw-subcategories\">\n<h2>" . wfMessage( 'smw_subproperty_header', $titleText )->text() . "</h2>\n<p>";
136
137
			if ( !$this->mProperty->isUserDefined() ) {
138
				$result .= wfMessage( 'smw_isspecprop' )->text() . ' ';
139
			}
140
141
			$result .= wfMessage( 'smw_subpropertyarticlecount' )->numParams( $resultCount )->text() . "</p>\n";
142
143
			if ( $resultCount < 6 ) {
144
				$result .= SMWPageLister::getShortList( 0, $resultCount, $subproperties, null );
145
			} else {
146
				$result .= SMWPageLister::getColumnList( 0, $resultCount, $subproperties, null );
147
			}
148
149
			$result .= "\n</div>";
150
		}
151
152
		return $result;
153
	}
154
155
	/**
156
	 * Get the HTML for displaying values of this property, based on the
157
	 * current from/until and limit settings.
158
	 *
159
	 * @return string
160
	 */
161
	protected function getPropertyValueList() {
162
		global $smwgPropertyPagingLimit, $wgRequest;
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...
163
164
		 // limit==0: configuration setting to disable this completely
165
		if ( $this->limit < 1 ) {
166
			return '';
167
		}
168
169
		$diWikiPages = array();
0 ignored issues
show
Unused Code introduced by
$diWikiPages 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...
170
		$options = SMWPageLister::getRequestOptions( $this->limit, $this->from, $this->until );
171
172
		$options->limit = $wgRequest->getVal( 'limit', $smwgPropertyPagingLimit );
173
		$options->offset = $wgRequest->getVal( 'offset', '0' );
174
175
		if ( ( $value = $wgRequest->getVal( 'value', '' ) ) !== '' ) {
176
			$diWikiPages = $this->doQuerySubjectListWithValue( $value, $options );
177
		} else {
178
			$diWikiPages = $this->store->getAllPropertySubjects( $this->mProperty, $options );
179
		}
180
181
		if ( !$options->ascending ) {
182
			$diWikiPages = array_reverse( $diWikiPages );
183
		}
184
185
		$result = '';
186
187
		if ( count( $diWikiPages ) > 0 ) {
188
			$pageLister = new SMWPageLister( $diWikiPages, null, $this->limit, $this->from, $this->until );
189
190
			$this->mTitle->setFragment( '#SMWResults' ); // Make navigation point to the result list.
191
			$navigation = $pageLister->getNavigationLinks( $this->mTitle );
0 ignored issues
show
Unused Code introduced by
$navigation 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...
192
193
			$dvWikiPage = DataValueFactory::getInstance()->newDataValueByItem(
194
				$this->mProperty
195
			);
196
197
			// Allow the DV formatter to access a specific language code
198
			$dvWikiPage->setOption(
199
				DataValue::OPT_USER_LANGUAGE,
200
				Localizer::getInstance()->getUserLanguage()->getCode()
201
			);
202
203
			$titleText = htmlspecialchars( $dvWikiPage->getWikiValue() );
204
			$resultNumber = min( $this->limit, count( $diWikiPages ) );
0 ignored issues
show
Unused Code introduced by
$resultNumber 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...
205
206
			$result .= "<a name=\"SMWResults\"></a><div id=\"mw-pages\">\n" .
207
			           '<h2>' . wfMessage( 'smw_attribute_header', $titleText )->text() . "</h2>\n<p>";
208
209
			$result .= $this->getNavigationLinks( 'smw_attributearticlecount', $diWikiPages, $smwgPropertyPagingLimit ) .
210
			           $this->subjectObjectList( $diWikiPages ) . "\n</div>";
211
		}
212
213
		return $result;
214
	}
215
216
	/**
217
	 * Format $diWikiPages chunked by letter in a table that shows subject
218
	 * articles in one column and object articles/values in the other one.
219
	 *
220
	 * @param $diWikiPages array
221
	 * @return string
222
	 */
223
	protected function subjectObjectList( array $diWikiPages ) {
224
		global $wgContLang, $smwgMaxPropertyValues;
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...
225
226
		$ac = count( $diWikiPages );
227
228
		if ( $ac > $this->limit ) {
229
			if ( $this->until !== '' ) {
230
				$start = 1;
231
			} else {
232
				$start = 0;
233
				$ac = $ac - 1;
234
			}
235
		} else {
236
			$start = 0;
237
		}
238
239
		$r = '<table class="property-page-results" style="width: 100%;" cellspacing="0" cellpadding="0">';
240
		$prev_start_char = 'None';
241
242
		for ( $index = $start; $index < $ac; $index++ ) {
243
			$diWikiPage = $diWikiPages[$index];
244
			$dvWikiPage = DataValueFactory::getInstance()->newDataValueByItem( $diWikiPage, null );
245
246
			$sortkey = $this->store->getWikiPageSortKey( $diWikiPage );
247
			$start_char = $wgContLang->convert( $wgContLang->firstChar( $sortkey ) );
248
249
			// Header for index letters
250
			if ( $start_char != $prev_start_char ) {
251
				$r .= '<tr class="header-row" ><th class="smwpropname"><div class="header-title">' . htmlspecialchars( $start_char ) . "</div></th><th></th></tr>\n";
252
				$prev_start_char = $start_char;
253
			}
254
255
			// Property name
256
			$searchlink = SMWInfolink::newBrowsingLink( '+', $dvWikiPage->getWikiValue() );
257
			$r .= '<tr class="value-row" ><td class="smwpropname">' . $dvWikiPage->getShortHTMLText( smwfGetLinker() ) .
258
			      '&#160;' . $searchlink->getHTML( smwfGetLinker() ) . '</td><td class="smwprops">';
259
260
			// Property values
261
			$ropts = new SMWRequestOptions();
262
			$ropts->limit = $smwgMaxPropertyValues + 1;
263
			$values = $this->store->getPropertyValues( $diWikiPage, $this->mProperty, $ropts );
264
			$i = 0;
265
266
			foreach ( $values as $di ) {
267
				if ( $i != 0 ) {
268
					$r .= ', ';
269
				}
270
				$i++;
271
272
				if ( $i < $smwgMaxPropertyValues + 1 ) {
273
					$dv = DataValueFactory::getInstance()->newDataValueByItem( $di, $this->mProperty );
274
275
					$dv->setOutputFormat( 'LOCL' );
276
277
					$r .= $dv->getShortHTMLText( smwfGetLinker() ) . $dv->getInfolinkText( SMW_OUTPUT_HTML, smwfGetLinker() );
278
				} else {
279
					$searchlink = SMWInfolink::newInversePropertySearchLink( '…', $dvWikiPage->getWikiValue(), $this->mTitle->getText() );
280
					$r .= $searchlink->getHTML( smwfGetLinker() );
281
				}
282
			}
283
284
			$r .= "</td></tr>\n";
285
		}
286
287
		$r .= '</table>';
288
289
		return $r;
290
	}
291
292
	private function doQuerySubjectListWithValue( $value, $options ) {
293
294
		$applicationFactory = ApplicationFactory::getInstance();
295
296
		$dataValue = $applicationFactory->getDataValueFactory()->newDataValueByProperty( $this->mProperty );
297
		$dataValue->setOption( DataValue::OPT_QUERY_CONTEXT, true );
298
		$dataValue->setUserValue( $value );
299
		$queryFactory = $applicationFactory->getQueryFactory();
300
301
		$description = $queryFactory->newDescriptionFactory()->newFromDataValue(
302
			$dataValue
303
		);
304
305
		$query = $queryFactory->newQuery( $description );
306
		$query->setLimit( $options->limit );
307
		$query->setOffset( $options->offset );
308
		$query->setSortKeys( array( '' => 'asc' ) );
309
310
		return $this->store->getQueryResult( $query )->getResults();
311
	}
312
313
}
314