Completed
Push — dev2 ( fb9917...e574a0 )
by Gordon
03:19
created

ElasticaUtil::addAutocompleteToQueryField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 11
rs 9.4286
cc 2
eloc 9
nc 2
nop 1
1
<?php
2
3
namespace SilverStripe\Elastica;
4
5
/**
6
 * Utility methods to help with searching functions, and also testable without fixtures
7
 */
8
class ElasticaUtil {
9
10
	/**
11
	 * Marker string for pre highlight - can be any string unlikely to appear in a search
12
	 */
13
	private static $pre_marker = " |PREZXCVBNM12345678";
14
15
	/**
16
	 * Marker string for psot highlight - can be any string unlikely to appear in a search
17
	 */
18
	private static $post_marker = "POSTZXCVBNM12345678| ";
19
20
21
	/**
22
	 * Function to display messages only if using the command line
23
	 * @var string $content Text to display when in command line mode
24
	 */
25
	public static function message($content) {
26
		if (\Director::is_cli()) {
27
			echo "$content\n";
28
		}
29
	}
30
31
32
	/*
33
	Display a human readable yes or no
34
	 */
35
	public static function showBooleanHumanReadable($assertion) {
36
		return $assertion ? 'Yes' : 'No';
37
	}
38
39
40
	public static function getPhraseSuggestion($alternativeQuerySuggestions) {
41
		$originalQuery = $alternativeQuerySuggestions[0]['text'];
42
43
		$highlightsCfg = \Config::inst()->get('Elastica', 'Highlights');
44
		$preTags = $highlightsCfg['PreTags'];
45
		$postTags = $highlightsCfg['PostTags'];
46
47
		//Use the first suggested phrase
48
		$options = $alternativeQuerySuggestions[0]['options'];
49
50
		$resultArray = null;
51
52
		if (sizeof($options) > 0) {
53
			//take the first suggestion
54
			$suggestedPhrase = $options[0]['text'];
55
			$suggestedPhraseHighlighted = $options[0]['highlighted'];
56
57
			// now need to fix capitalisation
58
			$originalParts = explode(' ', $originalQuery);
59
			$suggestedParts = explode(' ', $suggestedPhrase);
60
61
			$markedHighlightedParts = ' '.$suggestedPhraseHighlighted.' ';
62
			$markedHighlightedParts = str_replace(' '.$preTags, ' '.self::$pre_marker, $markedHighlightedParts);
63
64
			$markedHighlightedParts = str_replace($postTags.' ', self::$post_marker, $markedHighlightedParts);
65
66
			$markedHighlightedParts = trim($markedHighlightedParts);
67
			$markedHighlightedParts = trim($markedHighlightedParts);
68
69
			$highlightedParts = preg_split('/\s+/', $markedHighlightedParts);
70
71
			//Create a mapping of lowercase to uppercase terms
72
			$lowerToUpper = array();
73
			$lowerToHighlighted = array();
74
			$ctr = 0;
75
			foreach ($suggestedParts as $lowercaseWord) {
76
				$lowerToUpper[$lowercaseWord] = $originalParts[$ctr];
77
				$lowerToHighlighted[$lowercaseWord] = $highlightedParts[$ctr];
78
				$ctr++;
79
			}
80
81
			$plain = array();
82
			$highlighted = array();
83
			foreach ($suggestedParts as $lowercaseWord) {
84
				$possiblyUppercase = $lowerToUpper[$lowercaseWord];
85
				$possiblyUppercaseHighlighted = $lowerToHighlighted[$lowercaseWord];
86
87
				//If the terms are identical other than case, e.g. new => New, then simply swap
88
				if (strtolower($possiblyUppercase) == $lowercaseWord) {
89
					array_push($plain, $possiblyUppercase);
90
					array_push($highlighted, $possiblyUppercase);
91
				} else {
92
					//Need to check capitalisation of terms suggested that are different
93
94
					$chr = mb_substr ($possiblyUppercase, 0, 1, "UTF-8");
95
    				if (mb_strtolower($chr, "UTF-8") != $chr) {
96
    					$upperLowercaseWord = $lowercaseWord;
97
    					$upperLowercaseWord[0] = $chr;
98
99
    					//$possiblyUppercaseHighlighted = str_replace($lowercaseWord, $possiblyUppercase, $possiblyUppercaseHighlighted);
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
100
    					$withHighlights = str_replace($lowercaseWord, $upperLowercaseWord, $possiblyUppercaseHighlighted);
101
102
    					$lowercaseWord[0] = $chr;
103
104
    					//str_replace(search, replace, subject)
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
105
106
    					array_push($plain, $lowercaseWord);
107
    					array_push($highlighted, $withHighlights);
108
    				} else {
109
    					//No need to capitalise, so add suggested word
110
    					array_push($plain, $lowercaseWord);
111
112
    					//No need to capitalise, so add suggested highlighted word
113
    					array_push($highlighted, $possiblyUppercaseHighlighted);
114
    				}
115
				}
116
			}
117
118
			$highlighted = ' '.implode(' ', $highlighted).' ';
119
			$highlighted = str_replace(self::$pre_marker, ' '.$preTags, $highlighted);
120
			$highlighted = str_replace(self::$post_marker, $postTags.' ', $highlighted);
121
122
			$resultArray['suggestedQuery'] = implode(' ', $plain);
123
			$resultArray['suggestedQueryHighlighted'] = trim($highlighted);
124
		}
125
		return $resultArray;
126
	}
127
128
129
	/**
130
	 * The output format of this function is not documented, so at best this is guess work to an
131
	 * extent.  Possible formats are:
132
	 * - ((Title.standard:great Content.standard:ammunition Content.standard:could
133
	 *     Content.standard:bair Content.standard:dancing Content.standard:column
134
	 *     Content.standard:company Content.standard:infantry Content.standard:men
135
	 *     Content.standard:soldier Content.standard:brigade Content.standard:zealand
136
	 *     Content.standard:new)~3)
137
	 *     -ConstantScore(_uid:GutenbergBookExtract#1519)
138
	 *  (Description: bay Description: mannerstram)
139
	 *
140
	 * @param  string $explanation explanation string for more like this terms from Elasticsearch
141
	 * @return array             Array of fieldnames mapped to terms
142
	 */
143
	public static function parseSuggestionExplanation($explanation) {
144
145
		$explanation = explode('-ConstantScore', $explanation)[0];
146
147
        $bracketPos = strpos($explanation, ')~');
148
149
        if (substr($explanation, 0,2) == '((') {
150
        	$explanation = substr($explanation, 2, $bracketPos-2);
151
        } elseif (substr($explanation, 0,1) == '(') {
152
        	$explanation = substr($explanation, 1, $bracketPos-2);
153
        }
154
155
       	$terms = array();
156
157
        //Field name(s) => terms
158
        $splits = explode(' ', $explanation);
159
160
        foreach ($splits as $fieldAndTerm) {
161
        	$splits = explode(':', $fieldAndTerm);
162
163
        	// This is the no terms case
164
        	if (sizeof($splits) < 2) {
165
        		break;
166
        	}
167
168
        	$fieldname = $splits[0];
169
        	$term = $splits[1];
170
171
        	if (!isset($terms[$fieldname])) {
172
        		$terms[$fieldname] = array();
173
        	}
174
175
        	array_push($terms[$fieldname], $term);
176
        }
177
178
        return $terms;
179
	}
180
181
	/**
182
	 * Add attributes necessary for jQuery to execute autocomplete
183
	 * @param FormField &$queryField field used to type a search query
184
	 */
185
	public static function addAutocompleteToQueryField(&$queryField, $classesToSearch, $siteTreeOnly, $link, $slug) {
186
		if($this->AutoCompleteFieldID > 0) {
187
			$queryField->setAttribute('data-autocomplete', 'true');
188
			$queryField->setAttribute('data-autocomplete-field', 'Title');
189
			$queryField->setAttribute('data-autocomplete-classes', $classesToSearch);
190
			$queryField->setAttribute('data-autocomplete-sitetree', $siteTreeOnly);
191
			$queryField->setAttribute('data-autocomplete-source', $link;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ';', expecting ',' or ')'
Loading history...
192
			$queryField->setAttribute('data-autocomplete-function', $slug);
193
		}
194
	}
195
}
196