/**
  * check if an allowed tag (defined in a filteroption) was found in the current result list
  *
  * @param string $tag The tag to match against the searchresult
  * @return boolean TRUE if tag was found. Else FALSE
  */
 public function checkIfTagMatchesRecords($tag)
 {
     // if tag list is empty, fetch them from the result list
     // otherwise use the cached result list
     if (!$this->tagsInSearchResult) {
         $this->tagsInSearchResult = $this->pObj->tagsInSearchResult = $this->db->getTagsFromSearchResult();
         $GLOBALS['TSFE']->fe_user->setKey('ses', 'ke_search.tagsInSearchResults', $tagsInSearchResult);
     }
     return array_key_exists($tag, $this->tagsInSearchResult);
 }
 /**
  * The main entry point of this class
  * It will return the complete sorting HTML
  *
  * @return string HTML
  */
 public function renderSorting()
 {
     // show sorting:
     // if show Sorting is activated in FlexForm
     // if a value to sortBy is set in FlexForm (title, relevance, sortdate, what ever...)
     // if there are any entries in current search results
     if ($this->conf['showSortInFrontend'] && !empty($this->conf['sortByVisitor']) && $this->pObj->numberOfResults) {
         // loop all allowed orderings
         foreach ($this->sortBy as $field) {
             // we can't sort by score if there is no sword given
             if ($this->pObj->sword != '' || $field != 'score') {
                 $sortByDir = $this->getDefaultSortingDirection($field);
                 if (TYPO3_VERSION_INTEGER >= 7000000) {
                     $dbOrdering = TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(' ', $this->db->getOrdering());
                 } else {
                     $dbOrdering = t3lib_div::trimExplode(' ', $this->db->getOrdering());
                 }
                 /* if ordering direction is the same change it
                  *
                  * Explaintation:
                  * No ordering is active. Default Ordering by db is "sortdate desc".
                  * Default ordering by current field is also "sortdate desc".
                  * So...if you click the link for sortdate it will sort the results by "sortdate desc" again
                  * To prevent this we change the default ordering here
                  */
                 if ($field == $dbOrdering[0] && $sortByDir == $dbOrdering[1]) {
                     $sortByDir = $this->changeOrdering($sortByDir);
                 }
                 $markerArray['###FIELDNAME###'] = $field;
                 $markerArray['###URL###'] = $this->generateSortingLink($field, $sortByDir);
                 $markerArray['###CLASS###'] = $this->getClassNameForUpDownArrow($field, $dbOrdering);
                 $links .= $this->cObj->substituteMarkerArray($this->subpartArray['###SORT_LINK###'], $markerArray);
             }
         }
         $content = $this->cObj->substituteSubpart($this->subpartArray['###ORDERNAVIGATION###'], '###SORT_LINK###', $links);
         $content = $this->cObj->substituteMarker($content, '###LABEL_SORT###', $this->pObj->pi_getLL('label_sort'));
         return $content;
     } else {
         return '';
     }
 }
 /**
  * creates the search result list
  * 1. does the actual searching (fetches the results to $rows)
  * 2. fills fluid variables for fluid templates to $this->fluidTemplateVariables
  *
  */
 public function getSearchResults()
 {
     // fetch the search results
     $limit = $this->db->getLimit();
     $rows = $this->db->getSearchResults();
     // TODO: Check how Sphinx handles this, seems to return full result set
     if (count($rows) > $limit[1]) {
         $rows = array_slice($rows, $limit[0], $limit[1]);
     }
     // set number of results
     $this->numberOfResults = $this->db->getAmountOfSearchResults();
     // count searchword with ke_stats
     $this->countSearchWordWithKeStats($this->sword);
     // count search phrase in ke_search statistic tables
     if ($this->conf['countSearchPhrases']) {
         $this->countSearchPhrase($this->sword, $this->swords, $this->numberOfResults, $this->tagsAgainst);
     }
     // render "no results" text and stop here
     if ($this->numberOfResults == 0) {
         return $this->setNoResultsText();
     }
     // set switch for too short words
     $this->fluidTemplateVariables['wordsTooShort'] = $this->hasTooShortWords ? 1 : 0;
     // init counter and loop through the search results
     $resultCount = 1;
     $this->searchResult = GeneralUtility::makeInstance('tx_kesearch_lib_searchresult', $this);
     $this->fluidTemplateVariables['resultrows'] = array();
     foreach ($rows as $row) {
         $this->searchResult->setRow($row);
         $tempMarkerArray = array('orig_uid' => $row['orig_uid'], 'orig_pid' => $row['orig_pid'], 'title' => $this->searchResult->getTitle(), 'teaser' => $this->searchResult->getTeaser());
         // hook for additional markers in result row
         if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ke_search']['additionalResultMarker'])) {
             // make curent row number available to hook
             $this->currentRowNumber = $resultCount;
             foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ke_search']['additionalResultMarker'] as $_classRef) {
                 $_procObj =& GeneralUtility::getUserObj($_classRef);
                 $_procObj->additionalResultMarker($tempMarkerArray, $row, $this);
             }
             unset($this->currentRowNumber);
         }
         // add type marker
         // for file results just use the "file" type, not the file extension (eg. "file:pdf")
         list($type) = explode(':', $row['type']);
         $tempMarkerArray['type'] = str_replace(' ', '_', $type);
         // use the markers array as a base for the fluid template values
         $resultrowTemplateValues = $tempMarkerArray;
         // set result url
         $resultUrl = $this->searchResult->getResultUrl($this->conf['renderResultUrlAsLink']);
         $resultrowTemplateValues['url'] = $resultUrl;
         // set result numeration
         $resultNumber = $resultCount + $this->piVars['page'] * $this->conf['resultsPerPage'] - $this->conf['resultsPerPage'];
         $resultrowTemplateValues['number'] = $resultNumber;
         // set score (used for plain score output and score scale)
         $resultScore = number_format($row['score'], 2, ',', '');
         $resultrowTemplateValues['score'] = $resultScore;
         // set date (formatted and raw as a timestamp)
         $resultDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $row['sortdate']);
         $resultrowTemplateValues['date'] = $resultDate;
         $resultrowTemplateValues['date_timestamp'] = $row['sortdate'];
         // set percental score
         $resultrowTemplateValues['percent'] = $row['percent'];
         // show tags?
         $tags = $row['tags'];
         $tags = str_replace('#', ' ', $tags);
         $resultrowTemplateValues['tags'] = $tags;
         // set preview image
         $renderedImage = $this->renderPreviewImageOrTypeIcon($row);
         $resultrowTemplateValues['imageHtml'] = $renderedImage;
         // set end date for cal events
         if ($type == 'cal') {
             $resultrowTemplateValues['cal'] = $this->getCalEventEnddate($row['orig_uid']);
         }
         // add result row to the variables array
         $this->fluidTemplateVariables['resultrows'][] = $resultrowTemplateValues;
         // increase result counter
         $resultCount++;
     }
 }
 /**
  * creates the search result list
  * 1. does the actual searching (fetches the results to $rows)
  * 2. fills the marker for marker based templating and renders the resultlist
  * 3. fills fluid variables for fluid based templating to $this->fluidTemplateVariables
  *
  * @return string rendered searchbox (for static or ajax templating, not for fluid templating)
  */
 public function getSearchResults()
 {
     // generate and add onload image
     $this->onloadImage = $this->createHideSpinner();
     // fetch the search results
     $limit = $this->db->getLimit();
     $rows = $this->db->getSearchResults();
     // TODO: Check how Sphinx handles this, seems to return full result set
     if (count($rows) > $limit[1]) {
         $rows = array_slice($rows, $limit[0], $limit[1]);
     }
     // set number of results
     $this->numberOfResults = $this->db->getAmountOfSearchResults();
     // count searchword with ke_stats
     $this->countSearchWordWithKeStats($this->sword);
     // count search phrase in ke_search statistic tables
     if ($this->conf['countSearchPhrases']) {
         $this->countSearchPhrase($this->sword, $this->swords, $this->numberOfResults, $this->tagsAgainst);
     }
     // render "no results" text and stop here
     if ($this->numberOfResults == 0) {
         return $this->renderNoResultsText();
     }
     if ($this->hasTooShortWords) {
         $content = $this->renderTooShortWordsText();
         $this->fluidTemplateVariables['wordsTooShort'] = 1;
     }
     // init counter and loop through the search results
     $resultCount = 1;
     $this->searchResult = GeneralUtility::makeInstance('tx_kesearch_lib_searchresult', $this);
     $this->fluidTemplateVariables['resultrows'] = array();
     foreach ($rows as $row) {
         // generate row content
         $tempContent = $this->cObj->getSubpart($this->templateCode, '###RESULT_ROW###');
         $this->searchResult->setRow($row);
         $tempMarkerArray = array('title' => $this->searchResult->getTitle(), 'teaser' => $this->searchResult->getTeaser());
         // hook for additional markers in result (only valid for maker based templating)
         if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ke_search']['additionalResultMarker'])) {
             // make curent row number available to hook
             $this->currentRowNumber = $resultCount;
             foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ke_search']['additionalResultMarker'] as $_classRef) {
                 $_procObj =& GeneralUtility::getUserObj($_classRef);
                 $_procObj->additionalResultMarker($tempMarkerArray, $row, $this);
             }
             unset($this->currentRowNumber);
         }
         // add type marker
         // for file results just use the "file" type, not the file extension (eg. "file:pdf")
         list($type) = explode(':', $row['type']);
         $tempMarkerArray['type'] = str_replace(' ', '_', $type);
         // replace markers
         $tempContent = $this->cObj->substituteMarkerArray($tempContent, $tempMarkerArray, $wrap = '###|###', $uppercase = 1);
         $resultrowTemplateValues = $tempMarkerArray;
         // show result url?
         $resultUrl = $this->searchResult->getResultUrl($this->conf['renderResultUrlAsLink']);
         if ($this->conf['showResultUrl']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_RESULTURL###');
             $subContent = $this->cObj->substituteMarker($subContent, '###LABEL_RESULTURL###', $this->pi_getLL('label_resulturl'));
             $subContent = $this->cObj->substituteMarker($subContent, '###RESULTURL###', $resultUrl);
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_RESULTURL###', $subContent, $recursive = 1);
         $resultrowTemplateValues['url'] = $resultUrl;
         // show result numeration?
         $resultNumber = $resultCount + $this->piVars['page'] * $this->conf['resultsPerPage'] - $this->conf['resultsPerPage'];
         if ($this->conf['resultsNumeration']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_NUMERATION###');
             $subContent = $this->cObj->substituteMarker($subContent, '###NUMBER###', $resultNumber);
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_NUMERATION###', $subContent, $recursive = 1);
         $resultrowTemplateValues['number'] = $resultNumber;
         // show score?
         $resultScore = number_format($row['score'], 2, ',', '');
         if ($this->conf['showScore'] && $row['score']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_SCORE###');
             $subContent = $this->cObj->substituteMarker($subContent, '###LABEL_SCORE###', $this->pi_getLL('label_score'));
             $subContent = $this->cObj->substituteMarker($subContent, '###SCORE###', $resultScore);
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_SCORE###', $subContent, $recursive = 1);
         $resultrowTemplateValues['score'] = $resultScore;
         // show date?
         $resultDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $row['sortdate']);
         if ($this->conf['showDate'] && $row['sortdate']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_DATE###');
             $subContent = $this->cObj->substituteMarker($subContent, '###LABEL_DATE###', $this->pi_getLL('label_date'));
             $subContent = $this->cObj->substituteMarker($subContent, '###DATE###', $resultDate);
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_DATE###', $subContent, $recursive = 1);
         $resultrowTemplateValues['date'] = $resultDate;
         // show percental score?
         if ($this->conf['showPercentalScore'] && $row['percent']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_SCORE_PERCENT###');
             $subContent = $this->cObj->substituteMarker($subContent, '###LABEL_SCORE_PERCENT###', $this->pi_getLL('label_score_percent'));
             $subContent = $this->cObj->substituteMarker($subContent, '###SCORE_PERCENT###', $row['percent']);
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_SCORE_PERCENT###', $subContent, $recursive = 1);
         $resultrowTemplateValues['percent'] = $row['percent'];
         // show score scale?
         if ($this->conf['showScoreScale'] && $row['percent']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_SCORE_SCALE###');
             $subContent = $this->cObj->substituteMarker($subContent, '###SCORE###', $row['percent']);
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_SCORE_SCALE###', $subContent, $recursive = 1);
         // show tags?
         $tags = $row['tags'];
         $tags = str_replace('#', ' ', $tags);
         if ($this->conf['showTags']) {
             $subContent = $this->cObj->getSubpart($this->templateCode, '###SUB_TAGS###');
             $subContent = $this->cObj->substituteMarker($subContent, '###LABEL_TAGS###', $this->pi_getLL('label_tags'));
             $subContent = $this->cObj->substituteMarker($subContent, '###TAGS###', htmlspecialchars($tags));
         } else {
             $subContent = '';
         }
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_TAGS###', $subContent, $recursive = 1);
         $resultrowTemplateValues['tags'] = $tags;
         // preview image
         $renderedImage = $this->renderPreviewImageOrTypeIcon($row);
         $resultrowTemplateValues['imageHtml'] = $renderedImage[0];
         $tempContent = $this->cObj->substituteSubpart($tempContent, '###SUB_TYPE_ICON###', $renderedImage[1], $recursive = 1);
         // fluid templating: add result row to the variables array
         $this->fluidTemplateVariables['resultrows'][] = $resultrowTemplateValues;
         // marker based templating: add temp content to result list
         $content .= $tempContent;
         // increase result counter
         $resultCount++;
     }
     // hook for additional content AFTER the result list
     if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ke_search']['additionalContentAfterResultList'])) {
         foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ke_search']['additionalContentAfterResultList'] as $_classRef) {
             $_procObj =& GeneralUtility::getUserObj($_classRef);
             $content .= $_procObj->additionalContentAfterResultList($this);
         }
     }
     // add onload image if in AJAX mode
     if ($this->conf['renderMethod'] != 'static') {
         $content .= $this->onloadImage;
     }
     return $content;
 }
 /**
  * Test ordering if a searchword was given
  * - show sorting in FE is allowed
  * - admin presorts are uninteresting
  * - FE-User is allowed to choose between sortdate,tstamp and title
  * - allowed piVars are given
  *
  * @test
  */
 public function checkOrderingWithSearchwordAndUserCanSortWithAllowedPiVars()
 {
     $this->pObj->sword = 'Hallo';
     $this->pObj->conf = array('sortWithoutSearchword' => 'tstamp asc', 'showSortInFrontend' => true, 'sortByVisitor' => 'sortdate,tstamp,title', 'sortByAdmin' => 'sortdate desc');
     $this->pObj->piVars = array('orderByField' => 'title', 'orderByDir' => 'asc');
     $this->pObj->piVars = $this->div->cleanPiVars($this->pObj->piVars);
     $db = new tx_kesearch_db($this->pObj);
     $this->assertEquals('title asc', $db->getOrdering());
 }