/** * Build Teasercontent * * @param string $content The whole resultcontent * @return string The cutted recultcontent */ public function buildTeaserContent($content) { if (is_array($this->pObj->swords) && count($this->pObj->swords)) { $amountOfSearchWords = count($this->pObj->swords); $content = strip_tags($content); // with each new searchword and all the croppings here the teaser for each word will become too small/short // I decided to add 20 additional letters for each searchword. It looks much better and is more readable $charsForEachSearchWord = ceil($this->conf['resultChars'] / $amountOfSearchWords) + 20; $charsBeforeAfterSearchWord = ceil($charsForEachSearchWord / 2); $aSearchWordWasFound = false; $isSearchWordAtTheBeginning = false; foreach ($this->pObj->swords as $word) { $word = ' ' . $word; // our searchengine searches for wordbeginnings $pos = stripos($content, $word); if ($pos === false) { // if the word was not found it could be within brakets => (searchWord) // so give it a second try $pos = stripos($content, trim($word)); if ($pos === false) { continue; } } $aSearchWordWasFound = true; // if searchword is the first word if ($pos === 0) { $isSearchWordAtTheBeginning = true; } // find search starting point $startPos = $pos - $charsBeforeAfterSearchWord; if ($startPos < 0) { $startPos = 0; } // crop some words behind searchword $partWithSearchWord = substr($content, $startPos); $temp = $this->cObj->crop($partWithSearchWord, $charsForEachSearchWord . '|...|1'); // crop some words before searchword // after last cropping our text is too short now. So we have to find a new cutting position $startPos > 10 ? $length = strlen($temp) - 10 : ($length = strlen($temp)); $teaserArray[] = $this->cObj->crop($temp, '-' . $length . '||1'); } // When the searchword was found in title but not in content the teaser is empty // in that case we have to get the first x letters without containing any searchword if ($aSearchWordWasFound === false) { $teaser = $this->cObj->crop($content, $this->conf['resultChars'] . '||1'); } elseif ($isSearchWordAtTheBeginning === true) { $teaser = implode(' ', $teaserArray); } else { $teaser = '...' . implode(' ', $teaserArray); } // highlight hits? if ($this->conf['highlightSword']) { $teaser = $this->highlightArrayOfWordsInContent($this->pObj->swords, $teaser); } return $teaser; } else { return $this->cObj->crop($content, $this->conf['resultChars'] . '|...|1'); } }
/** * Render the cropped text * * @param integer $maxCharacters Place where to truncate the string * @param string $append What to append, if truncation happened * @param boolean $respectBoundaries If TRUE and division is in the middle of a word, the remains of that word is removed. * @param boolean $respectHtml If TRUE the cropped string will respect HTML tags and entities. Technically that means, that cropHTML() is called rather than crop() * @return string cropped text * @author Andreas Pattynama <*****@*****.**> * @author Sebastian Kurfürst <*****@*****.**> * @author Bastian Waidelich <*****@*****.**> * @author Felix Oertel <*****@*****.**> */ public function render($maxCharacters, $append = '...', $respectWordBoundaries = TRUE, $respectHtml = TRUE) { $stringToTruncate = $this->renderChildren(); if (TYPO3_MODE === 'BE') { $this->simulateFrontendEnvironment(); } if ($respectHtml) { $content = $this->contentObject->cropHTML($stringToTruncate, $maxCharacters . '|' . $append . '|' . $respectWordBoundaries); } else { $content = $this->contentObject->crop($stringToTruncate, $maxCharacters . '|' . $append . '|' . $respectWordBoundaries); } if (TYPO3_MODE === 'BE') { $this->resetFrontendEnvironment(); } return $content; }
/** * Render the cropped text * * @param integer $maxCharacters Place where to truncate the string * @param string $append What to append, if truncation happened * @param boolean $respectBoundaries If TRUE and division is in the middle of a word, the remains of that word is removed. This is currently ignored in backend mode! * @return string cropped text * @author Andreas Pattynama <*****@*****.**> * @author Sebastian Kurfürst <*****@*****.**> * @author Bastian Waidelich <*****@*****.**> * @author Felix Oertel <*****@*****.**> */ public function render($maxCharacters, $append = '...', $respectWordBoundaries = TRUE) { $stringToTruncate = $this->renderChildren(); if (TYPO3_MODE === 'BE') { if (strlen($stringToTruncate) > $maxCharacters) { $stringToTruncate = substr($stringToTruncate, 0, $maxCharacters - strlen($append)) . $append; } return $stringToTruncate; } else { if (strip_tags($stringToTruncate) != $stringToTruncate) { return $this->contentObject->cropHTML($stringToTruncate, $maxCharacters . '|' . $append . '|' . $respectWordBoundaries); } else { return $this->contentObject->crop($stringToTruncate, $maxCharacters . '|' . $append . '|' . $respectWordBoundaries); } } }
/** * Highlighting of terms within a text * * @param string $text Text * @param string|\Zend_Search_Lucene_Search_Query $search Terms to be highlighted (string or lucene search query) * @param int $crop Max. number of characters length * @param string $append Suffix in case of text being cropped at the end * @param string $prepend Prefix in case of text being cropped at the beginning * @param string $field Lucene document field to be used (if the search terms have to be found retroactively) * @return string Text with highlighting * @see http://www.mail-archive.com/fw-general@lists.zend.com/msg09013.html */ public function render($text = null, $search = null, $crop = null, $append = ' ...', $prepend = ' ... ', $field = 'bodytext') { $text = trim(strlen(trim($text)) ? $text : $this->renderChildren()); $terms = array(); // If there is a reasonable text given if (strlen($text)) { // If a list with search terms have been given ... if (is_array($search)) { $terms = $search; usort($terms, array($this, 'sortByLengthDesc')); // Else: If query hits have been given ... } elseif ($search instanceof \Tollwerk\TwLucenesearch\Domain\Model\QueryHits) { $terms = (array) $search->getHighlight($field); usort($terms, array($this, 'sortByLengthDesc')); // Else: If a lucene search query or a literal search term has been given } elseif ($search instanceof \Zend_Search_Lucene_Search_Query || strlen($search)) { // Instanciation of the lucene index service /* @var $indexerService \Tollwerk\TwLucenesearch\Service\Lucene */ $indexerService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstanceService('index', 'lucene'); if ($indexerService instanceof \TYPO3\CMS\Core\Service\AbstractService) { // Converting search term to lucene search query if necessary if (!$search instanceof \Zend_Search_Lucene_Search_Query) { $search = $indexerService->query($search); } // If there is a valid lucene search query available if ($search instanceof \Zend_Search_Lucene_Search_Query) { $searchHash = md5("{$search}"); if (!array_key_exists($searchHash, self::$_queryTermCache)) { self::$_queryTermCache[$searchHash] = array(); foreach ($indexerService->getQueryTerms($search) as $termField => $fieldTerms) { usort($fieldTerms, array($this, 'sortByLengthDesc')); self::$_queryTermCache[$searchHash][$termField] = $fieldTerms; } } $terms = self::$_queryTermCache[$searchHash]; $field = trim($field); $terms = strlen($field) && array_key_exists($field, $terms) ? $terms[$field] : array(); } } } } // Check if the text has to be cropped ... $crop = $crop !== null && intval($crop) && strlen($text) > $crop ? intval($crop) : false; // If the text is more than 33% too long and highlighting has to be applied: Cropping also at the beginning of the text if ($crop && strlen($text) / $crop > 1.5 && count($terms)) { // Find the first highlighting in the text ... $firstHighlight = $this->firstMatch($terms, $text); // If there is at least one highlighting ... if ($firstHighlight !== false) { $beforeHighlight = strrev(trim(substr($text, 0, $firstHighlight))); // Keep the last 3 words before the highlighting ... $words = preg_split("%\\s+%", $beforeHighlight, 4); if (count($words) > 3) { $beforeHighlight = strrev(implode(' ', array_slice($words, 0, 3))); $text = $prepend . $beforeHighlight . ' ' . substr($text, $firstHighlight); } } } // If there are search terms to be highlighted in the text ... if (count($terms)) { $text = $this->highlight($terms, $text, $crop); } // If the text has to be cropped ... if ($crop) { if (TYPO3_MODE === 'BE') { $this->simulateFrontendEnvironment(); } $respectHtml = true; $text = $respectHtml ? $this->contentObject->cropHTML($text, $crop . '|' . $append . '|1') : $this->contentObject->crop($text, $crop . '|' . $append . '|1'); if (TYPO3_MODE === 'BE') { $this->resetFrontendEnvironment(); } } return $text; }