Completed
Push — dev2 ( 24a813...6eabe6 )
by Gordon
04:20
created

SearchableHelper::findOrCreateSearchableField()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
rs 8.5806
cc 4
eloc 17
nc 5
nop 4
1
<?php
2
namespace SilverStripe\Elastica;
3
4
class SearchableHelper {
5
6
7
	public static function addIndexedFields($name, &$spec, $ownerClassName) {
8
		// in the case of a relationship type will not be set
9
		if(isset($spec['type'])) {
10
			if($spec['type'] == 'string') {
11
				$unstemmed = array();
12
				$unstemmed['type'] = "string";
13
				$unstemmed['analyzer'] = "unstemmed";
14
				$unstemmed['term_vector'] = "yes";
15
				$extraFields = array('standard' => $unstemmed);
16
17
				$shingles = array();
18
				$shingles['type'] = "string";
19
				$shingles['analyzer'] = "shingles";
20
				$shingles['term_vector'] = "yes";
21
				$extraFields['shingles'] = $shingles;
22
23
				//Add autocomplete field if so required
24
				$autocomplete = \Config::inst()->get($ownerClassName, 'searchable_autocomplete');
25
26
				if(isset($autocomplete) && in_array($name, $autocomplete)) {
27
					$autocompleteField = array();
28
					$autocompleteField['type'] = "string";
29
					$autocompleteField['index_analyzer'] = "autocomplete_index_analyzer";
30
					$autocompleteField['search_analyzer'] = "autocomplete_search_analyzer";
31
					$autocompleteField['term_vector'] = "yes";
32
					$extraFields['autocomplete'] = $autocompleteField;
33
				}
34
35
				$spec['fields'] = $extraFields;
36
				// FIXME - make index/locale specific, get from settings
37
				$spec['analyzer'] = 'stemmed';
38
				$spec['term_vector'] = "yes";
39
			}
40
		}
41
	}
42
43
44
	/**
45
	 * @param string &$name
46
	 * @param boolean $storeMethodName
47
	 * @param boolean $recurse
48
	 */
49
	public static function assignSpecForRelationship(&$name, $resultType, &$spec, $storeMethodName, $recurse) {
50
		$resultTypeInstance = \Injector::inst()->create($resultType);
51
		$resultTypeMapping = array();
52
		// get the fields for the result type, but do not recurse
53
		if($recurse) {
54
			$resultTypeMapping = $resultTypeInstance->getElasticaFields($storeMethodName, false);
55
		}
56
		$resultTypeMapping['ID'] = array('type' => 'integer');
57
		if($storeMethodName) {
58
			$resultTypeMapping['__method'] = $name;
59
		}
60
		$spec = array('properties' => $resultTypeMapping);
61
		// we now change the name to the result type, not the method name
62
		$name = $resultType;
63
	}
64
65
66
	/**
67
	 * @param string $name
68
	 */
69
	public static function assignSpecForStandardFieldType($name, $class, &$spec, &$html_fields, &$mappings) {
70
		if(($pos = strpos($class, '('))) {
71
			// Valid in the case of Varchar(255)
72
			$class = substr($class, 0, $pos);
73
		}
74
75
		if(array_key_exists($class, $mappings)) {
76
			$spec['type'] = $mappings[$class];
77
			if($spec['type'] === 'date') {
78
				$spec['format'] = SearchableHelper::getFormatForDate($class);
79
			}
80
81
			if($class === 'HTMLText' || $class === 'HTMLVarchar') {
82
				array_push($html_fields, $name);
83
			}
84
		}
85
	}
86
87
88
	public static function getFormatForDate($class) {
89
		$format = 'y-M-d'; // default
90
		switch ($class) {
91
			case 'Date':
92
				$format = 'y-M-d';
93
				break;
94
			case 'SS_Datetime':
95
				$format = 'y-M-d H:m:s';
96
				break;
97
			case 'Datetime':
98
				$format = 'y-M-d H:m:s';
99
				break;
100
			case 'Time':
101
				$format = 'H:m:s';
102
				break;
103
		}
104
105
		return $format;
106
	}
107
108
109
110
	public static function getListRelationshipMethods($instance) {
111
		$has_manys = $instance->has_many();
112
		$many_manys = $instance->many_many();
113
114
		// array of method name to retuned object ClassName for relationships returning lists
115
		$has_lists = $has_manys;
116
		foreach(array_keys($many_manys) as $key) {
117
			$has_lists[$key] = $many_manys[$key];
118
		}
119
120
		return $has_lists;
121
	}
122
123
124
	public static function isInSiteTree($classname) {
125
		$inSiteTree = ($classname === 'SiteTree' ? true : false);
126
		if(!$inSiteTree) {
127
			$class = new \ReflectionClass($classname);
128
			while($class = $class->getParentClass()) {
129
				$parentClass = $class->getName();
130
				if($parentClass == 'SiteTree') {
131
					$inSiteTree = true;
132
					break;
133
				}
134
			}
135
		}
136
		return $inSiteTree;
137
	}
138
139
140
	public static function storeMethodTextValue($instance, $field, &$fields, $html_fields) {
0 ignored issues
show
Unused Code introduced by
The parameter $html_fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
141
		if(in_array($field, $fields)) {
142
			// Parse short codes in HTML, and then convert to text
143
			$fields[$field] = $this->owner->$field;
0 ignored issues
show
Bug introduced by
The property owner does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
144
			$html = ShortcodeParser::get_active()->parse($this->owner->$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;
1 ignored issue
show
Documentation introduced by
The property Name does not exist on object<SearchableClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
201
			$inSiteTree = SearchableHelper::isInSiteTree($classname);
202
			$doSC->InSiteTree = $inSiteTree;
1 ignored issue
show
Documentation introduced by
The property InSiteTree does not exist on object<SearchableClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
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;
1 ignored issue
show
Documentation introduced by
The property ClazzName does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
217
			$doSF->Name = $fieldName;
1 ignored issue
show
Documentation introduced by
The property Name does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
218
219
			if(isset($searchableField['type'])) {
220
				$doSF->Type = $searchableField['type'];
1 ignored issue
show
Documentation introduced by
The property Type does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
221
			} else {
222
				$doSF->Name = $searchableField['properties']['__method'];
1 ignored issue
show
Documentation introduced by
The property Name does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
223
				$doSF->Type = 'relationship';
1 ignored issue
show
Documentation introduced by
The property Type does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
224
			}
225
			$doSF->SearchableClassID = $searchableClass->ID;
1 ignored issue
show
Documentation introduced by
The property SearchableClassID does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
226
227
			if(isset($searchableField['fields']['autocomplete'])) {
228
				$doSF->Autocomplete = true;
1 ignored issue
show
Documentation introduced by
The property Autocomplete does not exist on object<SearchableField>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
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
	public static function fieldsToElasticaConfig($fields) {
241
		// Copied from DataObject::searchableFields() as there is no separate accessible method
242
		$rewrite = array();
243
		foreach($fields as $name => $specOrName) {
244
			$identifer = (is_int($name)) ? $specOrName : $name;
245
			$rewrite[$identifer] = array();
246
			if(!isset($rewrite[$identifer]['title'])) {
247
				$rewrite[$identifer]['title'] = (isset($labels[$identifer]))
248
					? $labels[$identifer] : \FormField::name_to_label($identifer);
249
			}
250
			if(!isset($rewrite[$identifer]['filter'])) {
251
				$rewrite[$identifer]['filter'] = 'PartialMatchFilter';
252
			}
253
		}
254
255
		return $rewrite;
256
	}
257
258
259
260
}
261