/** * Actually render the page content. * @param string $sParameter URL parameters to special page. * @return string Rendered HTML output. */ public function execute($sParameter) { parent::execute($sParameter); $this->getOutput()->addModuleStyles('ext.bluespice.extendedsearch.specialpage.style'); $this->getOutput()->addModules('ext.bluespice.extendedsearch.specialpage'); $oExtendedsearchBase = new ExtendedSearchBase($this); $oView = $oExtendedsearchBase->renderSpecialpage(); $this->getOutput()->addHTML($oView->execute()); }
/** * Processes incoming search request */ public function readInSearchRequest() { global $wgCanonicalNamespaceNames, $wgExtraNamespaces, $wgContentNamespaces; $this->aOptions['searchStringRaw'] = $this->oSearchRequest->sInput; $this->aOptions['searchStringOrig'] = ExtendedSearchBase::preprocessSearchInput($this->oSearchRequest->sInput); self::$searchStringRaw = $this->aOptions['searchStringRaw']; $sCustomerId = $this->getCustomerId(); $sLogOp = ' OR '; $aFq = array(); $aBq = array(); $oRequest = RequestContext::getMain()->getRequest(); $scope = $oRequest->getVal('search_scope', BsConfig::get('MW::ExtendedSearch::DefScopeUser')) == 'title' ? 'title' : 'text'; $this->aOptions['scope'] = $scope; $vNamespace = $this->checkSearchstringForNamespace($this->aOptions['searchStringRaw'], $this->aOptions['searchStringOrig'], $aFq, BsConfig::get('MW::ExtendedSearch::ShowFacets')); $this->aOptions['searchStringWildcarded'] = SearchService::wildcardSearchstring($this->aOptions['searchStringOrig']); $this->aOptions['searchStringForStatistics'] = $this->aOptions['searchStringWildcarded']; $aSearchTitle = array('title:(' . $this->aOptions['searchStringOrig'] . ')^5', 'titleWord:(' . $this->aOptions['searchStringOrig'] . ')^2', 'titleReverse:(' . $this->aOptions['searchStringWildcarded'] . ')', 'redirects:(' . $this->aOptions['searchStringOrig'] . ')'); $aSearchText = array('textWord:(' . $this->aOptions['searchStringOrig'] . ')^2', 'textReverse:(' . $this->aOptions['searchStringWildcarded'] . ')', 'sections:(' . $this->aOptions['searchStringOrig'] . ')'); $sSearchStringTitle = implode($sLogOp, $aSearchTitle); $sSearchStringText = implode($sLogOp, $aSearchText); $this->aOptions['searchStringFinal'] = $this->aOptions['scope'] === 'title' ? $sSearchStringTitle : $sSearchStringTitle . $sLogOp . $sSearchStringText; // filter query $aFq[] = 'redirect:0'; $aFq[] = 'special:0'; $aFq[] = 'wiki:(' . $sCustomerId . ')'; // $this->aOptions['namespaces'] HAS TO BE an array with numeric indices of type string! $this->aOptions['namespaces'] = $this->oSearchRequest->aNamespaces; $aNamespaces = array_slice($wgCanonicalNamespaceNames, 2); $aNamespaces = $aNamespaces + $wgExtraNamespaces; $bTagNamespace = false; if ($vNamespace === false) { $this->aOptions['files'] = $this->oSearchRequest->bSearchFiles === true ? true : false; $oUser = RequestContext::getMain()->getUser(); if (!$oUser->getOption('searcheverything')) { if (empty($this->aOptions['namespaces']) && $this->oSearchRequest->bNoSelect === false) { $this->aOptions['namespaces'] = array(); $aOptions = $oUser->getOptions(); foreach ($aOptions as $sOpt => $sValue) { if (strpos($sOpt, 'searchNs') !== false && $sValue == true) { $this->aOptions['namespaces'][] = '' . str_replace('searchNs', '', $sOpt); } } $aAllowedTypes = explode(',', BsConfig::get('MW::ExtendedSearch::IndexFileTypes')); $aAllowedTypes = array_map('trim', $aAllowedTypes); $aSearchFilesFacet = array_intersect($this->oSearchRequest->aType, $aAllowedTypes); if (($this->aOptions['files'] === true || !empty($aSearchFilesFacet)) && $oUser->isAllowed('searchfiles')) { $this->aOptions['namespaces'][] = '999'; $this->aOptions['namespaces'][] = '998'; } } else { $bTagNamespace = true; $aTmp = array(); foreach ($this->aOptions['namespaces'] as $iNs) { if (BsNamespaceHelper::checkNamespacePermission($iNs, 'read') === true) { $aTmp[] = $iNs; } } $this->aOptions['namespaces'] = $aTmp; } } else { if (empty($this->aOptions['namespaces'])) { $aTmp = array(); foreach ($aNamespaces as $iNs) { if (BsNamespaceHelper::checkNamespacePermission($iNs, 'read') === true) { $this->aOptions['namespaces'][] = $iNs; } } } else { $bTagNamespace = true; $aTmp = array(); foreach ($this->aOptions['namespaces'] as $iNs) { if (!BsNamespaceHelper::checkNamespacePermission($iNs, 'read')) { $aTmp[] = $iNs; } } if (!empty($aTmp)) { $this->aOptions['namespaces'] = array_diff($this->aOptions['namespaces'], $aTmp); } } } } else { $bTagNamespace = true; $this->aOptions['namespaces'][] = '' . $vNamespace; } $this->aOptions['namespaces'] = array_unique($this->aOptions['namespaces']); if (!empty($this->aOptions['namespaces'])) { $aFqNamespaces = array(); foreach ($this->aOptions['namespaces'] as $sNamespace) { $aFqNamespaces[] = $sNamespace; if ($sNamespace == '999') { $filesAlreadyAddedInLoopBefore = true; } } if (!isset($filesAlreadyAddedInLoopBefore) && $this->aOptions['files'] === true && $oUser->isAllowed('searchfiles')) { $aFqNamespaces[] = '999'; } $bTagNamespace = true; $aFq[] = BsConfig::get('MW::ExtendedSearch::ShowFacets') ? '{!tag=na}namespace:("' . implode('" "', $aFqNamespaces) . '")' : 'namespace:("' . implode('" "', $aFqNamespaces) . '")'; } // $this->aOptions['cats'] = $this->oSearchRequest->sCat; // string, defaults to '' if 'search_cat' not set in REQUEST $this->aOptions['cats'] = $this->oSearchRequest->sCategories; // array of strings or empty array if (!empty($this->aOptions['cats'])) { if (isset($this->oSearchRequest->sOperator)) { switch ($this->oSearchRequest->sOperator) { case 'AND': $sLogOp = ' AND '; break; default: } } $sFqCategories = BsConfig::get('MW::ExtendedSearch::ShowFacets') ? '{!tag=ca}' : ''; $sFqCategories .= 'cat:("' . implode('"' . $sLogOp . '"', $this->aOptions['cats']) . '")'; $aFq[] = $sFqCategories; } $this->aOptions['type'] = $this->oSearchRequest->aType; if (!empty($this->aOptions['type'])) { $sFqType = BsConfig::get('MW::ExtendedSearch::ShowFacets') ? '{!tag=ty}' : ''; $sFqType .= 'type:("' . implode('"' . $sLogOp . '"', $this->aOptions['type']) . '")'; $aFq[] = $sFqType; } $this->aOptions['editor'] = $this->oSearchRequest->sEditor; if (!empty($this->aOptions['editor'])) { // there may be spaces in name of editor. solr analyses those to two // terms (editor's names) thus we wrap the name into quotation marks // todo: better: in schema.xml define field editor not to be tokenized // at whitespace // but: +editor:("Robert V" "Mathias S") is already split correctly! $sFqEditor = BsConfig::get('MW::ExtendedSearch::ShowFacets') ? '{!tag=ed}' : ''; $sFqEditor .= 'editor:("' . implode('"' . $sLogOp . '"', $this->aOptions['editor']) . '")'; $aFq[] = $sFqEditor; } // Boost query foreach ($wgContentNamespaces as $iNs) { $aBq[] = "namespace:{$iNs}^2"; } // We want that files are also seen as a content namespace $aBq[] = "namespace:999^2"; $searchLimit = BsConfig::get('MW::ExtendedSearch::LimitResults'); $this->aOptions['offset'] = $this->oSearchRequest->iOffset; $this->aOptions['order'] = $this->oSearchRequest->sOrder; $this->aOptions['asc'] = $this->oSearchRequest->sAsc; $this->aOptions['searchLimit'] = $searchLimit == 0 ? 15 : $searchLimit; $this->aOptions['titleExists'] = ExtendedSearchBase::titleExists($this->oSearchRequest->sInput, $this->aOptions); $this->aOptions['bExtendedForm'] = $this->oSearchRequest->bExtendedForm; $this->aSearchOptions['defType'] = 'edismax'; $this->aSearchOptions['fl'] = 'uid,type,title,path,namespace,cat,ts,redirects,overall_type'; $this->aSearchOptions['fq'] = $aFq; $this->aSearchOptions['sort'] = $this->aOptions['order'] . ' ' . $this->aOptions['asc']; $this->aSearchOptions['hl'] = 'on'; $this->aSearchOptions['hl.fl'] = 'titleWord, titleReverse, sections, textWord, textReverse'; $this->aSearchOptions['hl.snippets'] = BsConfig::get('MW::ExtendedSearch::HighlightSnippets'); $this->aSearchOptions['bq'] = implode(' ', $aBq); if (BsConfig::get('MW::ExtendedSearch::ShowFacets')) { $this->aSearchOptions['facet'] = 'on'; $this->aSearchOptions['facet.sort'] = 'false'; $this->aSearchOptions['facet.mincount'] = '1'; $this->aSearchOptions['facet.missing'] = 'true'; $this->aSearchOptions['facet.field'] = array(); $this->aSearchOptions['facet.field'][] = $bTagNamespace === true ? '{!ex=na}namespace' : 'namespace'; $this->aSearchOptions['facet.field'][] = isset($sFqCategories) ? '{!ex=ca}cat' : 'cat'; $this->aSearchOptions['facet.field'][] = isset($sFqType) ? '{!ex=ty}type' : 'type'; $this->aSearchOptions['facet.field'][] = isset($sFqEditor) ? '{!ex=ed}editor' : 'editor'; } }
/** * Returns rendered inner part of search results page. Used for faceting and paging. AJAX function. * @return string JSON encoded HTML of search results page. */ public static function getRequestJson() { $viewContentsSpecialPage = ExtendedSearchBase::getInstance(RequestContext::getMain())->getResults(true); $oDummy = new StdClass(); $oDummy->data = array('bodytext' => $viewContentsSpecialPage->execute()); wfRunHooks('ExtendedSearchBeforeAjaxResponse', array(null, &$oDummy)); return json_encode(array('contents' => $oDummy->data['bodytext'])); }
/** * Renders the HTML for the admin section within WikiAdmin * @return string HTML output to be displayed */ public function getForm() { if (wfReadOnly()) { throw new ReadOnlyError(); } global $wgScriptPath; RequestContext::getMain()->getOutput()->addModules('ext.bluespice.extendedsearch.admin'); $sForm = ''; if (SearchService::getInstance()->ping(2) === false) { RequestContext::getMain()->getOutput()->addHTML('<br /><div style="color:#F00; font-size:20px;">' . wfMessage('bs-extendedsearch-server-not-available')->escaped() . '</div><br />'); return false; } if (!ExtendedSearchBase::isCurlActivated()) { RequestContext::getMain()->getOutput()->addHTML('<br /><div style="color:#F00; font-size:20px;">' . wfMessage('bs-extendedsearch-curl-not-active')->escaped() . '</div><br />'); return false; } if ($this->checkLockExistence() === false) { $aSearchAdminButtons = array('create' => array('href' => '#', 'onclick' => 'bs.util.toggleMessage( bs.util.getAjaxDispatcherUrl( \'ExtendedSearchAdmin::getProgressBar\', [\'createForm\'] ), \'' . addslashes(wfMessage('bs-extendedsearch-create-index')->plain()) . '\', 400, 300);setTimeout(\'bsExtendedSearchStartCreate()\', 1000);', 'label' => wfMessage('bs-extendedsearch-create-index')->escaped(), 'image' => "{$wgScriptPath}/extensions/BlueSpiceExtensions/ExtendedSearch/resources/images/bs-searchindex-rebuild.png"), 'delete' => array('href' => '#', 'onclick' => 'bs.util.toggleMessage( bs.util.getAjaxDispatcherUrl( \'ExtendedSearchAdmin::getProgressBar\', [\'delete\'] ), \'' . addslashes(wfMessage('bs-extendedsearch-delete-index')->plain()) . '\', 400, 300);', 'label' => wfMessage('bs-extendedsearch-delete-index')->escaped(), 'image' => "{$wgScriptPath}/extensions/BlueSpiceExtensions/ExtendedSearch/resources/images/bs-searchindex-delete.png"), 'overwrite' => array('href' => '#', 'onclick' => 'bs.util.toggleMessage( bs.util.getAjaxDispatcherUrl( \'ExtendedSearchAdmin::getProgressBar\', [\'createForm\'] ), \'' . addslashes(wfMessage('bs-extendedsearch-overwrite-index')->plain()) . '\', 400, 300);setTimeout(\'bsExtendedSearchStartCreate()\', 1000);', 'label' => wfMessage('bs-extendedsearch-overwrite-index')->escaped(), 'image' => "{$wgScriptPath}/extensions/BlueSpiceExtensions/ExtendedSearch/resources/images/bs-searchindex-optimization.png")); } else { $aSearchAdminButtons = array('deleteLock' => array('href' => '#', 'onclick' => 'bsExtendedSearchConfirm( \'' . wfMessage('bs-extendedsearch-warning')->escaped() . '\', \'' . wfMessage('bs-extendedsearch-lockfiletext')->escaped() . '\')', 'label' => wfMessage('bs-extendedsearch-delete-lock')->escaped(), 'image' => "{$wgScriptPath}/extensions/BlueSpiceExtensions/ExtendedSearch/resources/images/bs-searchindex-delete.png")); $sForm .= '<h3><font color=\'red\'>' . wfMessage('bs-extendedsearch-indexinginprogress')->escaped() . '</font></h3><br />'; } wfRunHooks('BSExtendedSearchAdminButtons', array($this, &$aSearchAdminButtons)); foreach ($aSearchAdminButtons as $key => $params) { $sForm .= '<div class="bs-admincontrolbtn">'; $sForm .= '<a href="' . $params['href'] . '"'; if ($params['onclick']) { $sForm .= ' onclick="' . $params['onclick'] . '"'; } $sForm .= '>'; $sForm .= '<img src="' . $params['image'] . '" alt="' . $params['label'] . '" title="' . $params['label'] . '">'; $sForm .= '<div class="bs-admin-label">'; $sForm .= $params['label']; $sForm .= '</div>'; $sForm .= '</a>'; $sForm .= '</div>'; } return $sForm; }
/** * Return a instance of ExtendedSearchBase. * @return ExtendedSearchBase Instance of ExtendedSearchBase */ public static function getInstance($Context) { wfProfileIn('BS::' . __METHOD__); if (self::$oInstance === null) { self::$oInstance = new self($Context); } wfProfileOut('BS::' . __METHOD__); return self::$oInstance; }