summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/src/MediaWiki/Specials/SearchByProperty/PageBuilder.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/MediaWiki/Specials/SearchByProperty/PageBuilder.php')
-rw-r--r--www/wiki/extensions/SemanticMediaWiki/src/MediaWiki/Specials/SearchByProperty/PageBuilder.php395
1 files changed, 395 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/MediaWiki/Specials/SearchByProperty/PageBuilder.php b/www/wiki/extensions/SemanticMediaWiki/src/MediaWiki/Specials/SearchByProperty/PageBuilder.php
new file mode 100644
index 00000000..7c2a7e5a
--- /dev/null
+++ b/www/wiki/extensions/SemanticMediaWiki/src/MediaWiki/Specials/SearchByProperty/PageBuilder.php
@@ -0,0 +1,395 @@
+<?php
+
+namespace SMW\MediaWiki\Specials\SearchByProperty;
+
+use Html;
+use SMW\ApplicationFactory;
+use SMW\DataTypeRegistry;
+use SMW\DataValueFactory;
+use SMW\DataValues\StringValue;
+use SMW\DIProperty;
+use SMW\DIWikiPage;
+use SMW\MediaWiki\MessageBuilder;
+use SMW\MediaWiki\Renderer\HtmlFormRenderer;
+use SMW\ProcessingErrorMsgHandler;
+use SMWDataValue as DataValue;
+use SMWInfolink as Infolink;
+
+/**
+ * @license GNU GPL v2+
+ * @since 2.1
+ *
+ * @author Denny Vrandecic
+ * @author Daniel Herzig
+ * @author Markus Kroetzsch
+ * @author mwjames
+ */
+class PageBuilder {
+
+ /**
+ * @var HtmlFormRenderer
+ */
+ private $htmlFormRenderer;
+
+ /**
+ * @var PageRequestOptions
+ */
+ private $pageRequestOptions;
+
+ /**
+ * @var QueryResultLookup
+ */
+ private $queryResultLookup;
+
+ /**
+ * @var MessageBuilder
+ */
+ private $messageBuilder;
+
+ /**
+ * @var Linker
+ */
+ private $linker;
+
+ /**
+ * @since 2.1
+ *
+ * @param HtmlFormRenderer $htmlFormRenderer
+ * @param PageRequestOptions $pageRequestOptions
+ * @param QueryResultLookup $queryResultLookup
+ */
+ public function __construct( HtmlFormRenderer $htmlFormRenderer, PageRequestOptions $pageRequestOptions, QueryResultLookup $queryResultLookup ) {
+ $this->htmlFormRenderer = $htmlFormRenderer;
+ $this->pageRequestOptions = $pageRequestOptions;
+ $this->queryResultLookup = $queryResultLookup;
+ $this->linker = smwfGetLinker();
+ }
+
+ /**
+ * @since 2.1
+ *
+ * @return string
+ */
+ public function getHtml() {
+
+ $this->pageRequestOptions->initialize();
+ $this->messageBuilder = $this->htmlFormRenderer->getMessageBuilder();
+
+ list( $resultMessage, $resultList, $resultCount ) = $this->getResultHtml();
+
+ if ( ( $resultList === '' || $resultList === null ) &&
+ $this->pageRequestOptions->property->getDataItem() instanceof DIProperty &&
+ $this->pageRequestOptions->valueString === '' ) {
+ list( $resultMessage, $resultList, $resultCount ) = $this->tryToFindAtLeastOnePropertyTableReferenceFor(
+ $this->pageRequestOptions->property->getDataItem()
+ );
+ }
+
+ if ( $resultList === '' || $resultList === null ) {
+ $resultList = $this->messageBuilder->getMessage( 'smw_result_noresults' )->text();
+ }
+
+ $pageDescription = Html::rawElement(
+ 'p',
+ [ 'class' => 'smw-sp-searchbyproperty-description' ],
+ $this->messageBuilder->getMessage( 'smw-sp-searchbyproperty-description' )->parse()
+ );
+
+ $resultListHeader = Html::element(
+ 'h2',
+ [],
+ $this->messageBuilder->getMessage( 'smw-sp-searchbyproperty-resultlist-header' )->text()
+ );
+
+ return $pageDescription . $this->getHtmlForm( $resultMessage, $resultCount ) . $resultListHeader . $resultList;
+ }
+
+ private function getHtmlForm( $resultMessage, $resultCount ) {
+
+ // Precaution to avoid any inline breakage caused by a div element
+ // within a paragraph (e.g Highlighter content)
+ $resultMessage = str_replace( 'div', 'span', $resultMessage );
+
+ $html = $this->htmlFormRenderer
+ ->setName( 'searchbyproperty' )
+ ->withFieldset()
+ ->addParagraph( $resultMessage )
+ ->addPaging(
+ $this->pageRequestOptions->limit,
+ $this->pageRequestOptions->offset,
+ $resultCount )
+ ->addHorizontalRule()
+ ->addInputField(
+ $this->messageBuilder->getMessage( 'smw_sbv_property' )->text(),
+ 'property',
+ $this->pageRequestOptions->propertyString,
+ 'smw-property-input' )
+ ->addNonBreakingSpace()
+ ->addInputField(
+ $this->messageBuilder->getMessage( 'smw_sbv_value' )->text(),
+ 'value',
+ $this->pageRequestOptions->valueString,
+ 'smw-value-input' )
+ ->addNonBreakingSpace()
+ ->addSubmitButton( $this->messageBuilder->getMessage( 'smw_sbv_submit' )->text() )
+ ->getForm();
+
+ return $html;
+ }
+
+ private function getResultHtml() {
+
+ $resultList = '';
+ $resultMessage = '';
+
+ if ( $this->pageRequestOptions->propertyString === '' || !$this->pageRequestOptions->propertyString ) {
+ return [ $this->messageBuilder->getMessage( 'smw_sbv_docu' )->text(), '', 0 ];
+ }
+
+ // #1728
+ if ( !$this->pageRequestOptions->property->isValid() ) {
+ return [ ProcessingErrorMsgHandler::getMessagesAsString( $this->pageRequestOptions->property->getErrors() ), '', 0 ];
+ }
+
+ if ( $this->pageRequestOptions->valueString !== '' && !$this->pageRequestOptions->value->isValid() ) {
+ return [ ProcessingErrorMsgHandler::getMessagesAsString( $this->pageRequestOptions->value->getErrors() ), '', 0 ];
+ }
+
+ // Find out where the subject is used in connection with a query
+ if ( $this->isAskQueryLinksRelatedRequest() ) {
+ $exactResults = $this->queryResultLookup->doQueryLinksReferences( $this->pageRequestOptions );
+ $exactCount = count( $exactResults );
+ $resultList = $this->makeResultList( $exactResults, $this->pageRequestOptions->limit, true );
+ return [ str_replace( '_', ' ', $resultMessage ), $resultList, $exactCount ];
+ }
+
+ $exactResults = $this->queryResultLookup->doQuery( $this->pageRequestOptions );
+ $exactCount = count( $exactResults );
+
+ if ( $this->canQueryNearbyResults( $exactCount ) ) {
+ return $this->getNearbyResults( $exactResults, $exactCount );
+ }
+
+ if ( $this->pageRequestOptions->valueString === '' ) {
+ $resultMessageKey = 'smw-sp-searchbyproperty-nonvaluequery';
+ } else {
+ $resultMessageKey = 'smw-sp-searchbyproperty-valuequery';
+ }
+
+ $resultMessage = $this->messageBuilder->getMessage(
+ $resultMessageKey,
+ $this->pageRequestOptions->property->getShortHTMLText( $this->linker ),
+ $this->pageRequestOptions->value->getShortHTMLText( $this->linker ) )->text();
+
+ if ( $exactCount > 0 ) {
+ $resultList = $this->makeResultList( $exactResults, $this->pageRequestOptions->limit, true );
+ }
+
+ return [ str_replace( '_', ' ', $resultMessage ), $resultList, $exactCount ];
+ }
+
+ private function getNearbyResults( $exactResults, $exactCount ) {
+
+ $resultList = '';
+
+ $greaterResults = $this->queryResultLookup->doQueryForNearbyResults(
+ $this->pageRequestOptions,
+ $exactCount,
+ true
+ );
+
+ $smallerResults = $this->queryResultLookup->doQueryForNearbyResults(
+ $this->pageRequestOptions,
+ $exactCount,
+ false
+ );
+
+ // Calculate how many greater and smaller results should be displayed
+ $greaterCount = count( $greaterResults );
+ $smallerCount = count( $smallerResults );
+
+ if ( ( $greaterCount + $smallerCount + $exactCount ) > $this->pageRequestOptions->limit ) {
+ $lhalf = round( ( $this->pageRequestOptions->limit - $exactCount ) / 2 );
+
+ if ( $lhalf < $greaterCount ) {
+ if ( $lhalf < $smallerCount ) {
+ $smallerCount = $lhalf;
+ $greaterCount = $lhalf;
+ } else {
+ $greaterCount = $this->pageRequestOptions->limit - ( $exactCount + $smallerCount );
+ }
+ } else {
+ $smallerCount = $this->pageRequestOptions->limit - ( $exactCount + $greaterCount );
+ }
+ }
+
+ if ( ( $greaterCount + $smallerCount + $exactCount ) == 0 ) {
+ return [ '', $resultList, 0 ];
+ }
+
+ $resultMessage = $this->messageBuilder->getMessage(
+ 'smw_sbv_displayresultfuzzy',
+ $this->pageRequestOptions->property->getShortHTMLText( $this->linker ),
+ $this->pageRequestOptions->value->getShortHTMLText( $this->linker ) )->text();
+
+ $resultList .= $this->makeResultList( $smallerResults, $smallerCount, false );
+
+ if ( $exactCount == 0 ) {
+ $resultList .= "&#160;<em><strong><small>" . $this->messageBuilder->getMessage( 'parentheses' )
+ ->rawParams( $this->pageRequestOptions->value->getLongHTMLText() )
+ ->escaped() . "</small></strong></em>";
+ } else {
+ $resultList .= $this->makeResultList( $exactResults, $exactCount, true, true );
+ }
+
+ $resultList .= $this->makeResultList( $greaterResults, $greaterCount, true );
+
+ return [ $resultMessage, $resultList, $greaterCount + $exactCount ];
+ }
+
+ /**
+ * Creates the HTML for a bullet list with all the results of the set
+ * query. Values can be highlighted to show exact matches among nearby
+ * ones.
+ *
+ * @param array $results (array of (array of one or two SMWDataValues))
+ * @param integer $number How many results should be displayed? -1 for all
+ * @param boolean $first If less results should be displayed than
+ * given, should they show the first $number results, or the last
+ * $number results?
+ * @param boolean $highlight Should the results be highlighted?
+ *
+ * @return string HTML with the bullet list, including header
+ */
+ private function makeResultList( $results, $number, $first, $highlight = false ) {
+
+ if ( $number > 0 ) {
+ $results = $first ?
+ array_slice( $results, 0, $number ) :
+ array_slice( $results, $number );
+ }
+
+ $html = '';
+
+ foreach ( $results as $result ) {
+
+ $outputFormat = $result[0]->getOutputFormat();
+ $result[0]->setOutputFormat( $outputFormat ? $outputFormat : 'LOCL' );
+
+ $listitem = $result[0]->getLongHTMLText( $this->linker );
+
+ if ( $this->canShowSearchByPropertyLink( $result[0] ) ) {
+
+ // Copy the instance for the InfoLinker
+ $res = clone $result[0];
+ $res->setOutputFormat( '' );
+
+ $value = $res instanceof StringValue && $res->getLength() < 72 ? $res->getWikiValue() : mb_substr( $res->getWikiValue(), 0, 72 );
+
+ $listitem .= '&#160;&#160;' . Infolink::newPropertySearchLink(
+ '+',
+ $this->pageRequestOptions->propertyString,
+ $value
+ )->getHTML( $this->linker );
+ } elseif ( $result[0]->getTypeID() === '_wpg' ) {
+
+ // Add browsing link for wikipage results
+ // Note: non-wikipage results are possible using inverse properties
+ $listitem .= '&#160;&#160;' . Infolink::newBrowsingLink(
+ '+',
+ $result[0]->getLongWikiText()
+ )->getHTML( $this->linker );
+ }
+
+ // Show value if not equal to the value that was searched
+ // or if the current results are to be highlighted:
+ if ( array_key_exists( 1, $result ) &&
+ ( $result[1] instanceof DataValue ) &&
+ ( !$result[1]->getDataItem() instanceof \SMWDIError ) &&
+ ( !$this->pageRequestOptions->value->getDataItem()->equals( $result[1]->getDataItem() )
+ || $highlight ) ) {
+
+ $outputFormat = $result[1]->getOutputFormat();
+ $result[1]->setOutputFormat( $outputFormat ? $outputFormat : 'LOCL' );
+
+ $listitem .= "&#160;<em><small>" . $this->messageBuilder->getMessage( 'parentheses' )
+ ->rawParams( $result[1]->getLongHTMLText( $this->linker ) )
+ ->escaped() . "</small></em>";
+ }
+
+ // Highlight values
+ if ( $highlight ) {
+ $listitem = "<strong>$listitem</strong>";
+ }
+
+ $html .= "<li>$listitem</li>";
+ }
+
+ return "<ul>$html</ul>";
+ }
+
+ private function canQueryNearbyResults( $exactCount ) {
+ return $exactCount < ( $this->pageRequestOptions->limit / 3 ) && $this->pageRequestOptions->nearbySearch && $this->pageRequestOptions->valueString !== '';
+ }
+
+ private function canShowSearchByPropertyLink ( DataValue $dataValue ) {
+
+ $dataTypeClass = DataTypeRegistry::getInstance()->getDataTypeClassById(
+ $dataValue->getTypeID()
+ );
+
+ return $this->pageRequestOptions->value instanceof $dataTypeClass && $this->pageRequestOptions->valueString === '';
+ }
+
+ private function tryToFindAtLeastOnePropertyTableReferenceFor( DIProperty $property ) {
+
+ $resultList = '';
+ $resultMessage = '';
+ $resultCount = 0;
+ $extra = '';
+
+ $dataItem = ApplicationFactory::getInstance()->getStore()->getPropertyTableIdReferenceFinder()->tryToFindAtLeastOneReferenceForProperty(
+ $property
+ );
+
+ if ( !$dataItem instanceof DIWikiPage ) {
+ $resultMessage = 'No reference found.';
+ return [ $resultMessage, $resultList, $resultCount ];
+ }
+
+ // In case the item has already been marked as deleted but is yet pending
+ // for removal
+ if ( $dataItem->getInterWiki() === ':smw-delete' ) {
+ $resultMessage = 'Item reference "' . $dataItem->getSubobjectName() . '" has already been marked for removal.';
+ $dataItem = new DIWikiPage( $dataItem->getDBKey(), $dataItem->getNamespace() );
+ }
+
+ $dataValue = DataValueFactory::getInstance()->newDataValueByItem(
+ $dataItem
+ );
+
+ $outputFormat = $dataValue->getOutputFormat();
+ $dataValue->setOutputFormat( $outputFormat ? $outputFormat : 'LOCL' );
+
+ if ( $dataValue->isValid() ) {
+ //$resultMessage = 'Item reference for a zero-marked property.';
+ $resultList = $dataValue->getShortHtmlText( $this->linker ) . ' ' . $extra;
+ $resultCount++;
+
+ $resultList .= '&#160;&#160;' . Infolink::newBrowsingLink(
+ '+',
+ $dataValue->getLongWikiText()
+ )->getHTML( $this->linker );
+ }
+
+ return [ $resultMessage, $resultList, $resultCount ];
+ }
+
+ private function isAskQueryLinksRelatedRequest() {
+ return $this->pageRequestOptions->property !== '' &&
+ $this->pageRequestOptions->property->getDataItem()->getKey() === '_ASK' &&
+ $this->pageRequestOptions->value->isValid() &&
+ strpos( $this->pageRequestOptions->value->getWikiValue(), '_QUERY' ) === false;
+ }
+
+}