/**
  * 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;
 }