Completed
Push — dev2 ( dd5bec...049fe2 )
by Gordon
39:28 queued 36:22
created

SearchableHelper::findOrCreateSearchableField()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
ccs 0
cts 20
cp 0
rs 8.5806
cc 4
eloc 17
nc 5
nop 4
crap 20
1
<?php
2
namespace SilverStripe\Elastica;
3
4
class SearchableHelper {
5
6
7 2
	public static function addIndexedFields($name, &$spec, $ownerClassName) {
8
		// in the case of a relationship type will not be set
9 2
		if(isset($spec['type'])) {
10 2
			if($spec['type'] == 'string') {
11 2
				$unstemmed = array();
12 2
				$unstemmed['type'] = "string";
13 2
				$unstemmed['analyzer'] = "unstemmed";
14 2
				$unstemmed['term_vector'] = "yes";
15 2
				$extraFields = array('standard' => $unstemmed);
16
17 2
				$shingles = array();
18 2
				$shingles['type'] = "string";
19 2
				$shingles['analyzer'] = "shingles";
20 2
				$shingles['term_vector'] = "yes";
21 2
				$extraFields['shingles'] = $shingles;
22
23
				//Add autocomplete field if so required
24 2
				$autocomplete = \Config::inst()->get($ownerClassName, 'searchable_autocomplete');
25
26 2
				if(isset($autocomplete) && in_array($name, $autocomplete)) {
27 2
					$autocompleteField = array();
28 2
					$autocompleteField['type'] = "string";
29 2
					$autocompleteField['index_analyzer'] = "autocomplete_index_analyzer";
30 2
					$autocompleteField['search_analyzer'] = "autocomplete_search_analyzer";
31 2
					$autocompleteField['term_vector'] = "yes";
32 2
					$extraFields['autocomplete'] = $autocompleteField;
33 2
				}
34
35 2
				$spec['fields'] = $extraFields;
36
				// FIXME - make index/locale specific, get from settings
37 2
				$spec['analyzer'] = 'stemmed';
38 2
				$spec['term_vector'] = "yes";
39 2
			}
40 2
		}
41 2
	}
42
43
44
	/**
45
	 * @param string &$name
46
	 * @param boolean $storeMethodName
47
	 * @param boolean $recurse
48
	 */
49 2
	public static function assignSpecForRelationship(&$name, $resultType, &$spec, $storeMethodName, $recurse) {
50 2
		$resultTypeInstance = \Injector::inst()->create($resultType);
51 2
		$resultTypeMapping = array();
52
		// get the fields for the result type, but do not recurse
53 2
		if($recurse) {
54 2
			$resultTypeMapping = $resultTypeInstance->getElasticaFields($storeMethodName, false);
55 2
		}
56 2
		$resultTypeMapping['ID'] = array('type' => 'integer');
57 2
		if($storeMethodName) {
58
			$resultTypeMapping['__method'] = $name;
59
		}
60 2
		$spec = array('properties' => $resultTypeMapping);
61
		// we now change the name to the result type, not the method name
62 2
		$name = $resultType;
63 2
	}
64
65
66
	/**
67
	 * @param string $name
68
	 */
69 2
	public static function assignSpecForStandardFieldType($name, $class, &$spec, &$html_fields, &$mappings) {
0 ignored issues
show
Coding Style Naming introduced by
The parameter $html_fields is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
70 2
		if(($pos = strpos($class, '('))) {
71
			// Valid in the case of Varchar(255)
72 2
			$class = substr($class, 0, $pos);
73 2
		}
74
75 2
		if(array_key_exists($class, $mappings)) {
76 2
			$spec['type'] = $mappings[$class];
77 2
			if($spec['type'] === 'date') {
78 2
				$spec['format'] = SearchableHelper::getFormatForDate($class);
1 ignored issue
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
79 2
			}
80
81 2
			if($class === 'HTMLText' || $class === 'HTMLVarchar') {
82 2
				array_push($html_fields, $name);
83 2
			}
84 2
		}
85 2
	}
86
87
88 2
	public static function getFormatForDate($class) {
89 2
		$format = 'y-M-d'; // default
90
		switch ($class) {
91 2
			case 'Date':
92 2
				$format = 'y-M-d';
93 2
				break;
94 2
			case 'SS_Datetime':
95 2
				$format = 'y-M-d H:m:s';
96 2
				break;
97 2
			case 'Datetime':
98 2
				$format = 'y-M-d H:m:s';
99 2
				break;
100 2
			case 'Time':
101 2
				$format = 'H:m:s';
102 2
				break;
103
		}
104
105 2
		return $format;
106
	}
107
108
109
110 2
	public static function getListRelationshipMethods($instance) {
111 2
		$has_manys = $instance->has_many();
112 2
		$many_manys = $instance->many_many();
113
114
		// array of method name to retuned object ClassName for relationships returning lists
115 2
		$has_lists = $has_manys;
116 2
		foreach(array_keys($many_manys) as $key) {
117 2
			$has_lists[$key] = $many_manys[$key];
118 2
		}
119
120 2
		return $has_lists;
121
	}
122
123
124 1
	public static function isInSiteTree($classname) {
125 1
		$inSiteTree = ($classname === 'SiteTree' ? true : false);
126 1
		if(!$inSiteTree) {
127 1
			$class = new \ReflectionClass($classname);
128 1
			while($class = $class->getParentClass()) {
129 1
				$parentClass = $class->getName();
130 1
				if($parentClass == 'SiteTree') {
131 1
					$inSiteTree = true;
132 1
					break;
133
				}
134 1
			}
135 1
		}
136 1
		return $inSiteTree;
137
	}
138
139
140
	public static function storeMethodTextValue($instance, $field, &$fields, $html_fields) {
0 ignored issues
show
Coding Style Naming introduced by
The parameter $html_fields is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
141
		if(in_array($field, $html_fields)) {
142
			// Parse short codes in HTML, and then convert to text
143
			$fields[$field] = $instance->$field;
144
			$html = \ShortcodeParser::get_active()->parse($instance->$field());
145
			$txt = \Convert::html2raw($html);
146
			$fields[$field] = $txt;
147
		} else {
148
			// Plain text
149
			$fields[$field] = $instance->$field();
150
		}
151
	}
152
153
154
	public static function storeFieldHTMLValue($instance, $field, &$fields) {
155
		$fields[$field] = $instance->$field;
156
		if(gettype($instance->$field) !== 'NULL') {
157
			$html = \ShortcodeParser::get_active()->parse($instance->$field);
158
			$txt = \Convert::html2raw($html);
159
			$fields[$field] = $txt;
160
		}
161
	}
162
163
164
	public static function storeRelationshipValue($instance, $field, &$fields, $config, $recurse) {
165
		if(isset($config['properties']['__method'])) {
166
			$methodName = $config['properties']['__method'];
167
			$data = $instance->$methodName();
168
			$relArray = array();
169
170
			$has_ones = $instance->has_one();
171
			// get the fields of a has_one relational object
172
			if(isset($has_ones[$methodName])) {
173
				if($data->ID > 0) {
174
					$item = $data->getFieldValuesAsArray(false);
175
					$relArray = $item;
176
				}
177
178
			// get the fields for a has_many or many_many relational list
179
			} else {
180
				foreach($data->getIterator() as $item) {
181
					if($recurse) {
182
						// populate the subitem but do not recurse any further if more relationships
183
						$itemDoc = $item->getFieldValuesAsArray(false);
184
						array_push($relArray, $itemDoc);
185
					}
186
				}
187
			}
188
			// save the relation as an array (for now)
189
			$fields[$methodName] = $relArray;
190
		} else {
191
			$fields[$field] = $instance->$field;
192
		}
193
	}
194
195
196
	public static function findOrCreateSearchableClass($classname) {
197
		$doSC = \SearchableClass::get()->filter(array('Name' => $classname))->first();
198
		if(!$doSC) {
199
			$doSC = new \SearchableClass();
200
			$doSC->Name = $classname;
201
			$inSiteTree = SearchableHelper::isInSiteTree($classname);
1 ignored issue
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
202
			$doSC->InSiteTree = $inSiteTree;
203
			$doSC->write();
204
		}
205
		return $doSC;
206
	}
207
208
209
	public static function findOrCreateSearchableField($className, $fieldName, $searchableField, $searchableClass) {
210
		$filter = array('ClazzName' => $className, 'Name' => $fieldName);
211
		$doSF = \SearchableField::get()->filter($filter)->first();
212
213
214
		if(!$doSF) {
215
			$doSF = new \SearchableField();
216
			$doSF->ClazzName = $className;
217
			$doSF->Name = $fieldName;
218
219
			if(isset($searchableField['type'])) {
220
				$doSF->Type = $searchableField['type'];
221
			} else {
222
				$doSF->Name = $searchableField['properties']['__method'];
223
				$doSF->Type = 'relationship';
224
			}
225
			$doSF->SearchableClassID = $searchableClass->ID;
226
227
			if(isset($searchableField['fields']['autocomplete'])) {
228
				$doSF->Autocomplete = true;
229
			}
230
231
			$doSF->write();
232
			\DB::alteration_message("Created new searchable editable field " . $fieldName, "changed");
233
		}
234
	}
235
236
237
	/*
238
	Evaluate each field, e.g. 'Title', 'Member.Name'
239
	 */
240 2
	public static function fieldsToElasticaConfig($fields) {
241
		// Copied from DataObject::searchableFields() as there is no separate accessible method
242 2
		$rewrite = array();
243 2
		foreach($fields as $name => $specOrName) {
244 2
			$identifer = (is_int($name)) ? $specOrName : $name;
245 2
			$rewrite[$identifer] = array();
246 2
			if(!isset($rewrite[$identifer]['title'])) {
247 2
				$rewrite[$identifer]['title'] = (isset($labels[$identifer]))
248 2
					? $labels[$identifer] : \FormField::name_to_label($identifer);
249 2
			}
250 2
			if(!isset($rewrite[$identifer]['filter'])) {
251 2
				$rewrite[$identifer]['filter'] = 'PartialMatchFilter';
252 2
			}
253 2
		}
254
255 2
		return $rewrite;
256
	}
257
258
259
260
}
261