Passed
Push — master ( c0a3a7...3b84a4 )
by Jeroen
58:51
created

Search   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 297
Duplicated Lines 0 %

Test Coverage

Coverage 62.59%

Importance

Changes 0
Metric Value
dl 0
loc 297
ccs 87
cts 139
cp 0.6259
rs 9.2
c 0
b 0
f 0
wmc 34

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A getHighlighter() 0 2 1
A getParams() 0 2 1
A prepareEntity() 0 3 1
A getSearchView() 0 23 3
B listResults() 0 54 9
F initParams() 0 101 14
A getSearchTypes() 0 12 2
A getTypeSubtypePairs() 0 12 2
1
<?php
2
3
namespace Elgg\Search;
4
5
use ElggEntity;
6
use InvalidParameterException;
7
8
/**
9
 * Search plugin
10
 */
11
class Search {
12
13
	/**
14
	 * @var array
15
	 */
16
	protected $params;
17
18
	/**
19
	 * Constructor
20
	 *
21
	 * @param array $params Search params
22
	 */
23 6
	public function __construct(array $params = []) {
24 6
		$this->initParams($params);
25 6
	}
26
27
	/**
28
	 * Returns search params
29
	 * @return array
30
	 */
31 4
	public function getParams() {
32 4
		return $this->params;
33
	}
34
35
	/**
36
	 * Prepares a new highlighter
37
	 * @return Highlighter
38
	 */
39 3
	public function getHighlighter() {
40 3
		return new Highlighter($this->getParams());
41
	}
42
43
	/**
44
	 * Returns searchable type/subtype pairs
45
	 *
46
	 * <code>
47
	 * [
48
	 *    'user' => [],
49
	 *    'object' => [
50
	 *       'blog',
51
	 *    ]
52
	 * ]
53
	 * </code>
54
	 *
55
	 * @return array
56
	 */
57 2
	public function getTypeSubtypePairs() {
58 2
		$type_subtype_pairs = get_registered_entity_types();
59
60 2
		if (_elgg_services()->hooks->hasHandler('search_types', 'get_queries')) {
61
			elgg_deprecated_notice("
62
			'search_types','get_queries' hook has been deprecated.
63
			Use 'search:config','type_subtype_pairs' hook.
64
			", '3.0');
65
			$type_subtype_pairs = elgg_trigger_plugin_hook('search_types', 'get_queries', $this->params, $type_subtype_pairs);
66
		}
67
68 2
		return elgg_trigger_plugin_hook('search:config', 'type_subtype_pairs', $this->params, $type_subtype_pairs);
0 ignored issues
show
Bug Best Practice introduced by
The expression return elgg_trigger_plug...s, $type_subtype_pairs) returns the type false which is incompatible with the documented return type array.
Loading history...
69
	}
70
71
	/**
72
	 * Returns search types
73
	 *
74
	 * @return array
75
	 */
76 2
	public function getSearchTypes() {
77 2
		$search_types = [];
78
79 2
		if (_elgg_services()->hooks->hasHandler('search_types', 'get_types')) {
80
			elgg_deprecated_notice("
81
			'search_types','get_types' hook has been deprecated.
82
			Use 'search:config','search_types' hook.
83
			", '3.0');
84
			$search_types = elgg_trigger_plugin_hook('search_types', 'get_types', $this->params, $search_types);
85
		}
86
87 2
		return elgg_trigger_plugin_hook('search:config', 'search_types', $this->params, $search_types);
88
	}
89
90
	/**
91
	 * Populate search-related volatile data
92
	 *
93
	 * @param ElggEntity $entity Found entity
94
	 *
95
	 * @return void
96
	 */
97 1
	public function prepareEntity(ElggEntity $entity) {
98 1
		$formatter = new Formatter($entity, $this);
99 1
		$formatter->format();
100 1
	}
101
102
	/**
103
	 * List search results for given search type
104
	 *
105
	 * @param string $search_type Search type
106
	 * @param string $type        Entity type
107
	 * @param string $subtype     Subtype
108
	 * @param bool   $count       Count
109
	 *
110
	 * @return int|string
111
	 * @throws InvalidParameterException
112
	 */
113 1
	public function listResults($search_type, $type = null, $subtype = null, $count = false) {
114 1
		$current_params = $this->params;
115 1
		$current_params['search_type'] = $search_type;
116 1
		$current_params['type'] = $type;
117 1
		$current_params['subtype'] = $subtype;
118
119 1
		switch ($search_type) {
120
			case 'entities' :
121 1
				if ($subtype && _elgg_services()->hooks->hasHandler('search', "$type:$subtype")) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $subtype of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
122
					$hook_type = "$type:$subtype";
123
				} else {
124 1
					$hook_type = $type;
125
				}
126 1
				break;
127
128
			default :
129
				$hook_type = $search_type;
130
				break;
131
		}
132
133
		$results = [
134 1
			'entities' => [],
135
			'count' => 0,
136
		];
137
138 1
		if (_elgg_services()->hooks->hasHandler('search', $hook_type)) {
139
			elgg_deprecated_notice("
140
			'search','$hook_type' plugin hook has been deprecated and may be removed.
141
			Please consult the documentation for the new core search API
142
			and update your use of search hooks.
143
		", '3.0');
144
			$results = elgg_trigger_plugin_hook('search', $hook_type, $current_params, $results);
145
			if ($count) {
146
				return (int) $results['count'];
147
			}
148
		} else {
149 1
			$current_params['count'] = true;
150 1
			$results['count'] = (int) elgg_search($current_params);
151 1
			if ($count) {
152 1
				return $results['count'];
153
			}
154 1
			if (!empty($results['count'])) {
155
				unset($current_params['count']);
156
				$results['entities'] = elgg_search($current_params);
157
			}
158
		}
159
160 1
		if (empty($results['entities'])) {
161 1
			return '';
162
		}
163
164
		return elgg_view('search/list', [
165
			'results' => $results,
166
			'params' => $current_params,
167
		]);
168
169
	}
170
171
	/**
172
	 * Returns the name of the view to render an entity in search results
173
	 * @return string
174
	 */
175
	public function getSearchView() {
176
177
		$type = elgg_extract('type', $this->params);
178
		$subtype = elgg_extract('subtype', $this->params);
179
		$search_type = elgg_extract('search_type', $this->params);
180
181
		$views = [
182
			"search/$search_type/$type/$subtype",
183
			"search/$search_type/$type/default",
184
			"search/$type/$subtype/entity", // BC
185
			"search/$type/entity", // BC
186
			"search/$type/$subtype",
187
			"search/$type/default",
188
			"search/$search_type/entity", // BC
189
		];
190
191
		foreach ($views as $view) {
192
			if (elgg_view_exists($view)) {
193
				return $view;
194
			}
195
		}
196
197
		return '';
198
	}
199
200
	/**
201
	 * Prepare search params from request query elements
202
	 *
203
	 * @param array $params Params
204
	 *
205
	 * @return void
206
	 */
207 6
	protected function initParams(array $params = []) {
208
209
		// $search_type == all || entities || trigger plugin hook
210 6
		$search_type = get_input('search_type', 'all');
211 6
		if ($search_type == 'tags') {
212
			elgg_deprecated_notice('"tags" search type has been deprecated. By default, "entities" search performs search within registered tags.', '3.0');
213
			$search_type = 'entities';
214
			$partial_match = false;
215
			$fields = get_input('tag_names');
216
			if (!$fields) {
217
				$fields = (array) elgg_get_registered_tag_metadata_names();
218
			}
219
		} else {
220 6
			$partial_match = true;
221 6
			$fields = get_input('fields');
222
		}
223
224 6
		$query = get_input('q', get_input('tag', ''));
225
226 6
		if (preg_match('/\"(.*)\"/i', $query)) {
227
			// if query is quoted, e.g. "elgg has been released", perform literal search
228 1
			$tokenize = false;
229 1
			$query = preg_replace('/\"(.*)\"/i', '$1', $query);
230
		} else {
231 5
			$tokenize = true;
232
		}
233
234 6
		if ($search_type == 'all') {
235
			// We only display 2 results per search type
236 5
			$limit = 2;
237 5
			$offset = 0;
238 5
			$pagination = false;
239
		} else {
240 1
			$limit = max((int) get_input('limit'), elgg_get_config('default_limit'));
241 1
			$offset = get_input('offset', 0);
242 1
			$pagination = true;
243
		}
244
245 6
		$entity_type = get_input('entity_type', ELGG_ENTITIES_ANY_VALUE);
246 6
		if ($entity_type) {
247 1
			$entity_subtype = get_input('entity_subtype', ELGG_ENTITIES_ANY_VALUE);
248
		} else {
249 5
			$entity_subtype = ELGG_ENTITIES_ANY_VALUE;
250
		}
251
252 6
		$owner_guid = get_input('owner_guid', ELGG_ENTITIES_ANY_VALUE);
253 6
		$container_guid = get_input('container_guid', ELGG_ENTITIES_ANY_VALUE);
254
255 6
		$sort = get_input('sort');
256 6
		$order = get_input('order', '');
257
258 6
		switch ($sort) {
259 6
			case 'action_on' :
260
				$sort = 'last_action';
261
				break;
262
263 6
			case 'created' :
264
				$sort = 'time_created';
265
				break;
266
267 6
			case 'updated' :
268
				$sort = 'time_updated';
269
				break;
270
271 6
			case 'alpha' :
272
				if (!$order || !in_array(strtoupper($order), ['ASC', 'DESC'])) {
273
					$order = 'ASC';
274
				}
275
				$sort = 'name';
276
				break;
277
278
			default :
279 6
				$sort = 'time_created';
280 6
				$order = 'desc';
281
		}
282
283
		$current_params = [
284 6
			'query' => $query,
285 6
			'offset' => $offset,
286 6
			'limit' => $limit,
287 6
			'sort' => $sort,
288 6
			'order' => $order,
289 6
			'search_type' => $search_type,
290 6
			'fields' => $fields,
291 6
			'partial_match' => $partial_match,
292 6
			'tokenize' => $tokenize,
293 6
			'type' => $entity_type,
294 6
			'subtype' => $entity_subtype,
295 6
			'owner_guid' => $owner_guid,
296 6
			'container_guid' => $container_guid,
297 6
			'pagination' => $pagination,
298
		];
299
300 6
		$params = array_merge($current_params, $params);
301
302 6
		$this->params = _elgg_services()->search->normalizeOptions($params);
303
304 6
		if ($search_type == 'all' && empty(array_filter($this->params['fields']))) {
305
			// Plugin hooks did not provide a specific set of fields to use
306
			// We will let params to repopulate the fields for type specific searches
307 4
			unset($this->params['fields']);
308
		}
309 6
	}
310
}
311