[BUGFIX] Indexed search broken after moving "SearchResultContentObject" 66/36566/3
authorBenjamin Mack <benni@typo3.org>
Sun, 1 Feb 2015 12:09:31 +0000 (13:09 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Tue, 3 Feb 2015 19:24:55 +0000 (20:24 +0100)
Indexed search still uses the old cobject in both
plugins.

The problem arieses in just to call one method from
SearchResultContentObject->register_and_explode_search_string()

The necessary functions are moved to the common
IndexedSearchUtility.

Resolves: #64716
Releases: master
Change-Id: I386330f1f66342ee838e3616cac7f0924bd31522
Reviewed-on: http://review.typo3.org/36566
Reviewed-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Tested-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/indexed_search/Classes/Controller/SearchController.php
typo3/sysext/indexed_search/Classes/Controller/SearchFormController.php
typo3/sysext/indexed_search/Classes/Utility/IndexedSearchUtility.php

index c77586e..91c3cc5 100644 (file)
@@ -729,12 +729,9 @@ class SearchController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControlle
                                        array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8', $GLOBALS['TSFE']->csConvObj->utf8_encode(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('localizedOperandOr', 'indexed_search'), $GLOBALS['TSFE']->renderCharset), 'toLower'), 'OR'),
                                        array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8', $GLOBALS['TSFE']->csConvObj->utf8_encode(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('localizedOperandNot', 'indexed_search'), $GLOBALS['TSFE']->renderCharset), 'toLower'), 'AND NOT')
                                );
-                               $search = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\ContentObject\SearchResultContentObject::class);
-                               $search->default_operator = $defaultOperator == 1 ? 'OR' : 'AND';
-                               $search->operator_translate_table = $operatorTranslateTable;
-                               $search->register_and_explode_search_string($searchWords);
-                               if (is_array($search->sword_array)) {
-                                       $sWordArray = $this->procSearchWordsByLexer($search->sword_array);
+                               $swordArray = \TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility::getExplodedSearchString($searchWords, $defaultOperator == 1 ? 'OR' : 'AND', $operatorTranslateTable);
+                               if (is_array($swordArray)) {
+                                       $sWordArray = $this->procSearchWordsByLexer($swordArray);
                                }
                        }
                }
index 45d9f2e..dbf5cca 100644 (file)
@@ -117,7 +117,7 @@ class SearchFormController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin {
                $this->initialize();
                // Do search:
                // If there were any search words entered...
-               if (is_array($this->sWArr)) {
+               if (is_array($this->sWArr) && !empty($this->sWArr)) {
                        $content = $this->doSearch($this->sWArr);
                }
                // Finally compile all the content, form, messages and results:
@@ -354,12 +354,9 @@ class SearchFormController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin {
                                // type = Sentence
                                $sWordArray = array(array('sword' => trim($inSW), 'oper' => 'AND'));
                        } else {
-                               $search = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\ContentObject\SearchResultContentObject::class);
-                               $search->default_operator = $defOp == 1 ? 'OR' : 'AND';
-                               $search->operator_translate_table = $this->operator_translate_table;
-                               $search->register_and_explode_search_string($inSW);
-                               if (is_array($search->sword_array)) {
-                                       $sWordArray = $this->procSearchWordsByLexer($search->sword_array);
+                               $searchWords = \TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility::getExplodedSearchString($inSW, $defOp == 1 ? 'OR' : 'AND', $this->operator_translate_table);
+                               if (is_array($searchWords)) {
+                                       $sWordArray = $this->procSearchWordsByLexer($searchWords);
                                }
                        }
                }
index 35b1bed..7bd29fd 100644 (file)
@@ -18,8 +18,6 @@ namespace TYPO3\CMS\IndexedSearch\Utility;
  * Class with common methods used across various classes in the indexed search.
  * Impementation is provided by various people from the TYPO3 community.
  *
- * This class is final because it contains only static methods.
- *
  * @author Dmitry Dulepov <dmitry@typo3.com>
  */
 class IndexedSearchUtility {
@@ -48,4 +46,117 @@ class IndexedSearchUtility {
                return hexdec(substr(md5($stringToHash), 0, 7));
        }
 
+
+       /**
+        * Takes a search-string (WITHOUT SLASHES or else it'll be a little sppooky , NOW REMEMBER to unslash!!)
+        * Sets up search words with operators.
+        *
+        * @param string $sword The input search-word string.
+        * @param string $defaultOperator
+        * @param array $operatorTranslateTable
+        * @return array
+        */
+       public static function getExplodedSearchString($sword, $defaultOperator, $operatorTranslateTable) {
+               $swordArray = array();
+               $sword = trim($sword);
+               if ($sword) {
+                       $components = self::split($sword);
+                       if (is_array($components)) {
+                               $i = 0;
+                               $lastoper = '';
+                               foreach ($components as $key => $val) {
+                                       $operator = self::getOperator($val, $operatorTranslateTable);
+                                       if ($operator) {
+                                               $lastoper = $operator;
+                                       } elseif (strlen($val) > 1) {
+                                               // A searchword MUST be at least two characters long!
+                                               $swordArray[$i]['sword'] = $val;
+                                               $swordArray[$i]['oper'] = $lastoper ?: $defaultOperator;
+                                               $lastoper = '';
+                                               $i++;
+                                       }
+                               }
+                       }
+               }
+               return $swordArray;
+       }
+
+       /**
+        * Used to split a search-word line up into elements to search for. This function will detect boolean words like AND and OR, + and -, and even find sentences encapsulated in ""
+        * This function could be re-written to be more clean and effective - yet it's not that important.
+        *
+        * @param string $origSword The raw sword string from outside
+        * @param string $specchars Special chars which are used as operators (+- is default)
+        * @param string $delchars Special chars which are deleted if the append the searchword (+-., is default)
+        * @return mixed Returns an ARRAY if there were search words, otherwise the return value may be unset.
+        */
+       protected static function split($origSword, $specchars = '+-', $delchars = '+.,-') {
+               $value = NULL;
+               $sword = $origSword;
+               $specs = '[' . preg_quote($specchars, '/') . ']';
+               // As long as $sword is TRUE (that means $sword MUST be reduced little by little until its empty inside the loop!)
+               while ($sword) {
+                       // There was a double-quote and we will then look for the ending quote.
+                       if (preg_match('/^"/', $sword)) {
+                               // Removes first double-quote
+                               $sword = preg_replace('/^"/', '', $sword);
+                               // Removes everything till next double-quote
+                               preg_match('/^[^"]*/', $sword, $reg);
+                               // reg[0] is the value, should not be trimmed
+                               $value[] = $reg[0];
+                               $sword = preg_replace('/^' . preg_quote($reg[0], '/') . '/', '', $sword);
+                               // Removes last double-quote
+                               $sword = trim(preg_replace('/^"/', '', $sword));
+                       } elseif (preg_match('/^' . $specs . '/', $sword, $reg)) {
+                               $value[] = $reg[0];
+                               // Removes = sign
+                               $sword = trim(preg_replace('/^' . $specs . '/', '', $sword));
+                       } elseif (preg_match('/[\\+\\-]/', $sword)) {
+                               // Check if $sword contains + or -
+                               // + and - shall only be interpreted as $specchars when there's whitespace before it
+                               // otherwise it's included in the searchword (e.g. "know-how")
+                               // explode $sword to single words
+                               $a_sword = explode(' ', $sword);
+                               // get first word
+                               $word = array_shift($a_sword);
+                               // Delete $delchars at end of string
+                               $word = rtrim($word, $delchars);
+                               // add searchword to values
+                               $value[] = $word;
+                               // re-build $sword
+                               $sword = implode(' ', $a_sword);
+                       } else {
+                               // There are no double-quotes around the value. Looking for next (space) or special char.
+                               preg_match('/^[^ ' . preg_quote($specchars, '/') . ']*/', $sword, $reg);
+                               // Delete $delchars at end of string
+                               $word = rtrim(trim($reg[0]), $delchars);
+                               $value[] = $word;
+                               $sword = trim(preg_replace('/^' . preg_quote($reg[0], '/') . '/', '', $sword));
+                       }
+               }
+               return $value;
+       }
+
+       /**
+        * This returns an SQL search-operator (eg. AND, OR, NOT) translated from the current localized set of operators (eg. in danish OG, ELLER, IKKE).
+        *
+        * @param string $operator The possible operator to find in the internal operator array.
+        * @param array $operatorTranslateTable an array of possible operators
+        * @return string If found, the SQL operator for the localized input operator.
+        * @access private
+        */
+       protected static function getOperator($operator, $operatorTranslateTable) {
+               $operator = trim($operator);
+               // case-conversion is charset insensitive, but it doesn't spoil
+               // anything if input string AND operator table is already converted
+               $operator = strtolower($operator);
+               foreach ($operatorTranslateTable as $key => $val) {
+                       $item = $operatorTranslateTable[$key][0];
+                       // See note above.
+                       $item = strtolower($item);
+                       if ($operator == $item) {
+                               return $operatorTranslateTable[$key][1];
+                       }
+               }
+       }
 }