00001 <?php
00002
00024 class SMWSearchByProperty extends SpecialPage {
00025
00027 private $propertystring = '';
00029 private $property = null;
00031 private $valuestring = '';
00033 private $value = null;
00035 private $limit = 20;
00037 private $offset = 0;
00038
00042 public function __construct() {
00043 parent::__construct( 'SearchByProperty' );
00044 }
00045
00051 public function execute( $query ) {
00052 global $wgRequest, $wgOut;
00053 $this->setHeaders();
00054
00055
00056 $this->propertystring = $wgRequest->getText( 'property' );
00057 $this->valuestring = $wgRequest->getText( 'value' );
00058
00059 $params = SMWInfolink::decodeParameters( $query, false );
00060 reset( $params );
00061
00062
00063 if ( $this->propertystring === '' ) $this->propertystring = current( $params );
00064 if ( $this->valuestring === '' ) $this->valuestring = next( $params );
00065
00066 $this->valuestring = str_replace( ' ', ' ', $this->valuestring );
00067 $this->valuestring = str_replace( ' ', ' ', $this->valuestring );
00068
00069 $this->property = SMWPropertyValue::makeUserProperty( $this->propertystring );
00070 if ( !$this->property->isValid() ) {
00071 $this->propertystring = '';
00072 } else {
00073 $this->propertystring = $this->property->getWikiValue();
00074 $this->value = SMWDataValueFactory::newPropertyObjectValue( $this->property->getDataItem(), $this->valuestring );
00075
00076 if ( $this->value->isValid() ) {
00077 $this->valuestring = $this->value->getWikiValue();
00078 } else {
00079 $this->value = null;
00080 }
00081 }
00082
00083 $limitstring = $wgRequest->getVal( 'limit' );
00084 if ( is_numeric( $limitstring ) ) {
00085 $this->limit = intval( $limitstring );
00086 }
00087
00088 $offsetstring = $wgRequest->getVal( 'offset' );
00089 if ( is_numeric( $offsetstring ) ) {
00090 $this->offset = intval( $offsetstring );
00091 }
00092
00093 $wgOut->addHTML( $this->displaySearchByProperty() );
00094 $wgOut->addHTML( $this->queryForm() );
00095
00096 SMWOutputs::commitToOutputPage( $wgOut );
00097 }
00098
00104 private function displaySearchByProperty() {
00105 global $wgOut, $smwgSearchByPropertyFuzzy;
00106 $linker = smwfGetLinker();
00107
00108 if ( $this->propertystring === '' ) {
00109 return '<p>' . wfMsg( 'smw_sbv_docu' ) . "</p>\n";
00110 }
00111
00112 if ( ( $this->value == null ) || !$this->value->isValid() ) {
00113 return '<p>' . wfMsg( 'smw_sbv_novalue', $this->property->getShortHTMLText( $linker ) ) . "</p>\n";
00114 }
00115
00116 $wgOut->setPagetitle( $this->property->getWikiValue() . ' ' . $this->value->getShortHTMLText( null ) );
00117 $html = '';
00118
00119 $exact = $this->getExactResults();
00120 $count = count( $exact );
00121
00122 if ( ( $count < ( $this->limit / 3 ) ) && ( $this->value->isNumeric() ) && $smwgSearchByPropertyFuzzy ) {
00123 $greater = $this->getNearbyResults( $count, true );
00124 $lesser = $this->getNearbyResults( $count, false );
00125
00126
00127 $cG = count( $greater );
00128 $cL = count( $lesser );
00129
00130 if ( ( $cG + $cL + $count ) > $this->limit ) {
00131 $l = $this->limit - $count;
00132 $lhalf = round( $l / 2 );
00133
00134 if ( $lhalf < $cG ) {
00135 if ( $lhalf < $cL ) {
00136 $cL = $lhalf; $cG = $lhalf;
00137 } else {
00138 $cG = $this->limit - ( $count + $cL );
00139 }
00140 } else {
00141 $cL = $this->limit - ( $count + $cG );
00142 }
00143 }
00144
00145 if ( ( $cG + $cL + $count ) == 0 )
00146 $html .= wfMsg( 'smw_result_noresults' );
00147 else {
00148 $html .= wfMsg( 'smw_sbv_displayresultfuzzy', $this->property->getShortHTMLText( $linker ), $this->value->getShortHTMLText( $linker ) ) . "<br />\n";
00149 $html .= $this->displayResults( $lesser, $cL, false );
00150
00151 if ( $count == 0 ) {
00152 $html .= "          <em><strong><small>(" . $this->value->getLongHTMLText() . ")</small></strong></em>\n";
00153 } else {
00154 $html .= $this->displayResults( $exact, $count, true, true );
00155 }
00156
00157 $html .= $this->displayResults( $greater, $cG );
00158 }
00159 } else {
00160 $html .= wfMsg( 'smw_sbv_displayresult', $this->property->getShortHTMLText( $linker ), $this->value->getShortHTMLText( $linker ) ) . "<br />\n";
00161
00162 if ( 0 == $count ) {
00163 $html .= wfMsg( 'smw_result_noresults' );
00164 } else {
00165 $navi = $this->getNavigationBar( $count );
00166 if ( ( $this->offset > 0 ) || ( $count > $this->limit ) ) $html .= $navi;
00167 $html .= $this->displayResults( $exact, $this->limit );
00168 if ( ( $this->offset > 0 ) || ( $count > $this->limit ) ) $html .= $navi;
00169 }
00170 }
00171
00172 $html .= '<p> </p>';
00173
00174 return $html;
00175 }
00176
00187 private function displayResults( $results, $number = -1, $first = true, $highlight = false ) {
00188 $html = "<ul>\n";
00189
00190 if ( !$first && ( $number > 0 ) ) {
00191
00192
00193 $results = array_slice( array_reverse( $results ), 0, $number );
00194 }
00195
00196 while ( $results && $number != 0 ) {
00197 $result = array_shift( $results );
00198
00199 $html .= '<li>' . $result[0]->getLongHTMLText( smwfGetLinker() );
00200
00201 if ( $result[0]->getTypeID() == '_wpg' ) {
00202 $html .= '  ' . SMWInfolink::newBrowsingLink( '+', $result[0]->getLongWikiText() )->getHTML( smwfGetLinker() );
00203 }
00204
00205 if ( array_key_exists( 1, $result ) && is_object( $result[1] ) && ( ( $this->value != $result[1] ) || $highlight ) ) {
00206 $html .= " <em><small>(" . $result[1]->getLongHTMLText( smwfGetLinker() ) . ")</small></em>";
00207 }
00208
00209 $html .= "</li>";
00210
00211 if ( $highlight ) {
00212 $html = "<strong>" . $html . "</strong>";
00213 }
00214
00215 $html .= "\n";
00216 $number--;
00217 }
00218
00219 $html .= "</ul>\n";
00220
00221 return $html;
00222 }
00223
00231 private function getNavigationBar( $count ) {
00232 global $smwgQMaxInlineLimit;
00233
00234 if ( $this->offset > 0 ) {
00235 $navigation = Html::element(
00236 'a',
00237 array(
00238 'href' => SpecialPage::getSafeTitleFor( 'SearchByProperty' )->getLocalURL( array(
00239 'offset' => max( 0, $this->offset - $this->limit ),
00240 'limit' => $this->limit,
00241 'property' => $this->property->getWikiValue(),
00242 'value' => $this->value->getWikiValue()
00243 ) )
00244 ),
00245 wfMsg( 'smw_result_prev' )
00246 );
00247 }
00248 else {
00249 $navigation = wfMsg( 'smw_result_prev' );
00250 }
00251
00252 $navigation .=
00253 '     <b>' .
00254 wfMsg( 'smw_result_results' ) . ' ' .
00255 ( $this->offset + 1 ) . '– ' .
00256 ( $this->offset + min( $count, $this->limit ) ) .
00257 '</b>    ';
00258
00259 if ( $count > $this->limit ) {
00260 $navigation .= Html::element(
00261 'a',
00262 array(
00263 'href' => SpecialPage::getSafeTitleFor( 'SearchByProperty' )->getLocalURL( array(
00264 'offset' => $this->offset + $this->limit,
00265 'limit' => $this->limit,
00266 'property' => $this->property->getWikiValue(),
00267 'value' => $this->value->getWikiValue()
00268 ) )
00269 ),
00270 wfMsg( 'smw_result_next' )
00271 );
00272 } else {
00273 $navigation .= wfMsg( 'smw_result_next' );
00274 }
00275
00276 $max = false;
00277 $first = true;
00278
00279 foreach ( array( 20, 50, 100, 250, 500 ) as $l ) {
00280 if ( $max ) continue;
00281
00282 if ( $first ) {
00283 $navigation .= '        (';
00284 $first = false;
00285 } else {
00286 $navigation .= ' ' . wfMsgExt( 'pipe-separator' , 'escapenoentities' ) . ' ';
00287 }
00288
00289 if ( $l > $smwgQMaxInlineLimit ) {
00290 $l = $smwgQMaxInlineLimit;
00291 $max = true;
00292 }
00293
00294 if ( $this->limit != $l ) {
00295 $navigation .= Html::element(
00296 'a',
00297 array(
00298 'href' => SpecialPage::getSafeTitleFor( 'SearchByProperty' )->getLocalURL( array(
00299 'offset' => $this->offset,
00300 'limit' => $l,
00301 'property' => $this->property->getWikiValue(),
00302 'value' => $this->value->getWikiValue()
00303 ) )
00304 ),
00305 $l
00306 );
00307 } else {
00308 $navigation .= '<b>' . $l . '</b>';
00309 }
00310 }
00311
00312 $navigation .= ')';
00313
00314 return $navigation;
00315 }
00316
00322 private function getExactResults() {
00323 $options = new SMWRequestOptions();
00324 $options->limit = $this->limit + 1;
00325 $options->offset = $this->offset;
00326 $options->sort = true;
00327
00328 $res = smwfGetStore()->getPropertySubjects( $this->property->getDataItem(), $this->value->getDataItem(), $options );
00329 $results = array();
00330
00331 foreach ( $res as $result ) {
00332 array_push( $results, array(
00333 SMWDataValueFactory::newDataItemValue( $result, null ),
00334 $this->value
00335 ) );
00336 }
00337
00338 return $results;
00339 }
00340
00350 private function getNearbyResults( $count, $greater = true ) {
00351 $options = new SMWRequestOptions();
00352 $options->limit = $this->limit + 1;
00353 $options->sort = true;
00354
00355
00356
00357 $printrequest = new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, '', clone $this->property );
00358
00359 $params = array();
00360 $params['format'] = 'ul';
00361 $params['sort'] = $this->propertystring;
00362 $params['order'] = 'DESC';
00363 if ( $greater ) $params['order'] = 'ASC';
00364 $cmp = '<';
00365 if ( $greater ) $cmp = '>';
00366
00367 $querystring = '[[' . $this->propertystring . '::' . $cmp . $this->valuestring . ']]';
00368
00369 $printouts = array( $printrequest );
00370
00371 SMWQueryProcessor::addThisPrintout( $printouts, $params );
00372 $params = SMWQueryProcessor::getProcessedParams( $params, $printouts );
00373 $queryobj = SMWQueryProcessor::createQuery( $querystring, $params, SMWQueryProcessor::SPECIAL_PAGE, 'ul', $printouts );
00374 $queryobj->querymode = SMWQuery::MODE_INSTANCES;
00375 $queryobj->setLimit( $this->limit );
00376 $queryobj->setOffset( $count );
00377
00378 $results = smwfGetStore()->getQueryResult( $queryobj );
00379
00380 $result = $results->getNext();
00381 $ret = array();
00382
00383 while ( $result ) {
00384 $r = array( $result[0]->getNextDataValue() );
00385
00386 if ( array_key_exists( 1, $result ) ) {
00387 $r[] = $result[1]->getNextDataValue();
00388 }
00389
00390 $ret[] = $r;
00391
00392 $result = $results->getNext();
00393 }
00394
00395 if ( !$greater ) {
00396 $ret = array_reverse( $ret );
00397 }
00398
00399 return $ret;
00400 }
00401
00407 private function queryForm() {
00408 self::addAutoComplete();
00409 $spectitle = SpecialPage::getTitleFor( 'SearchByProperty' );
00410 $html = '<form name="searchbyproperty" action="' . htmlspecialchars( $spectitle->getLocalURL() ) . '" method="get">' . "\n" .
00411 '<input type="hidden" name="title" value="' . $spectitle->getPrefixedText() . '"/>' ;
00412 $html .= wfMsg( 'smw_sbv_property' ) . ' <input type="text" id="property_box" name="property" value="' . htmlspecialchars( $this->propertystring ) . '" />' . "   \n";
00413 $html .= wfMsg( 'smw_sbv_value' ) . ' <input type="text" name="value" value="' . htmlspecialchars( $this->valuestring ) . '" />' . "\n";
00414 $html .= '<input type="submit" value="' . wfMsg( 'smw_sbv_submit' ) . "\"/>\n</form>\n";
00415
00416 return $html;
00417 }
00418
00424 protected static function addAutoComplete() {
00425 SMWOutputs::requireResource( 'jquery.ui.autocomplete' );
00426
00427 $javascript_autocomplete_text = <<<END
00428 <script type="text/javascript">
00429 jQuery(document).ready(function(){
00430 jQuery("#property_box").autocomplete({
00431 minLength: 2,
00432 source: function(request, response) {
00433 jQuery.getJSON(wgScriptPath+'/api.php?action=opensearch&limit=10&namespace='+wgNamespaceIds['property']+'&format=jsonfm&search='+request.term, function(data){
00434
00435 for(i=0;i<data[1].length;i++) data[1][i]=data[1][i].substr(data[1][i].indexOf(':')+1);
00436 response(data[1]);
00437 });
00438 }
00439 });
00440 });
00441 </script>
00442
00443 END;
00444
00445 SMWOutputs::requireScript( 'smwAutocompleteSpecialSearchByProperty', $javascript_autocomplete_text );
00446 }
00447
00448 }