1 | <?php |
||
2 | |||
3 | namespace Elgg\Search; |
||
4 | |||
5 | use ElggEntity; |
||
6 | use ElggUser; |
||
7 | |||
8 | /** |
||
9 | * Populates volatile data with details needed to render a search view |
||
10 | * |
||
11 | * @access private |
||
12 | */ |
||
13 | class Formatter { |
||
14 | |||
15 | /** |
||
16 | * @var ElggEntity |
||
17 | */ |
||
18 | protected $entity; |
||
19 | |||
20 | /** |
||
21 | * @var array |
||
22 | */ |
||
23 | protected $params = []; |
||
24 | |||
25 | /** |
||
26 | * @var Highlighter |
||
27 | */ |
||
28 | protected $highlighter; |
||
29 | |||
30 | /** |
||
31 | * Formatter constructor. |
||
32 | * |
||
33 | * @param ElggEntity $entity Entity |
||
34 | * @param Search $service Service |
||
35 | */ |
||
36 | 2 | public function __construct(ElggEntity $entity, Search $service) { |
|
37 | 2 | $this->entity = $entity; |
|
38 | 2 | $this->params = $service->getParams(); |
|
39 | 2 | $this->highlighter = $service->getHighlighter(); |
|
40 | 2 | } |
|
41 | |||
42 | /** |
||
43 | * Populate search-related volatile data |
||
44 | * @return void |
||
45 | */ |
||
46 | 2 | public function format() { |
|
47 | 2 | _elgg_services()->hooks->trigger('search:format', 'entity', $this->params, $this->entity); |
|
48 | |||
49 | 2 | $this->formatTitle(); |
|
50 | 2 | $this->formatDescription(); |
|
51 | 2 | $this->formatExtras(); |
|
52 | 2 | $this->formatIcon(); |
|
53 | 2 | $this->formatURL(); |
|
54 | 2 | $this->formatTime(); |
|
55 | 2 | } |
|
56 | |||
57 | /** |
||
58 | * Format title |
||
59 | * @return void |
||
60 | */ |
||
61 | 2 | protected function formatTitle() { |
|
62 | |||
63 | 2 | if ($this->entity->getVolatileData('search_matched_title')) { |
|
64 | 1 | return; |
|
65 | } |
||
66 | |||
67 | 1 | $title = $this->entity->getDisplayName(); |
|
68 | 1 | if ($this->entity instanceof ElggUser) { |
|
69 | $title .= " (@{$this->entity->username})"; |
||
70 | } |
||
71 | |||
72 | 1 | $title = $this->highlighter->highlight($title, 1, 300); |
|
73 | 1 | $this->entity->setVolatileData('search_matched_title', $title); |
|
74 | 1 | } |
|
75 | |||
76 | /** |
||
77 | * Format description |
||
78 | * @return void |
||
79 | */ |
||
80 | 2 | protected function formatDescription() { |
|
81 | |||
82 | 2 | if ($this->entity->getVolatileData('search_matched_description')) { |
|
83 | return; |
||
84 | } |
||
85 | |||
86 | 2 | $description = $this->entity->description; |
|
87 | 2 | $description = $this->highlighter->highlight($description, 10, 300); |
|
88 | 2 | $this->entity->setVolatileData('search_matched_description', $description); |
|
89 | 2 | } |
|
90 | |||
91 | /** |
||
92 | * Format extras |
||
93 | * @return void |
||
94 | */ |
||
95 | 2 | protected function formatExtras() { |
|
96 | 2 | if ($this->entity->getVolatileData('search_matched_extra')) { |
|
97 | return; |
||
98 | } |
||
99 | |||
100 | 2 | $extra = []; |
|
101 | 2 | $matches = $this->getPropertyMatches(); |
|
102 | |||
103 | 2 | foreach ($matches as $property_type => $fields) { |
|
104 | 1 | foreach ($fields as $field => $match) { |
|
105 | 1 | $label = elgg_format_element('strong', [ |
|
106 | 1 | 'class' => 'search-match-extra-label', |
|
107 | 1 | ], $this->getFieldLabel($property_type, $field)); |
|
108 | |||
109 | |||
110 | 1 | $extra_row = elgg_format_element('p', [ |
|
111 | 1 | 'class' => 'elgg-output search-match-extra', |
|
112 | 1 | ], $label . ': ' . implode(', ', $match)); |
|
113 | |||
114 | 1 | $extra[] = $extra_row; |
|
115 | } |
||
116 | } |
||
117 | |||
118 | 2 | $this->entity->setVolatileData('search_matched_extra', implode('', $extra)); |
|
119 | 2 | } |
|
120 | |||
121 | /** |
||
122 | * Format entity properties |
||
123 | * |
||
124 | * @todo Match individual words instead of entire query |
||
125 | * |
||
126 | * @return array |
||
127 | */ |
||
128 | 2 | protected function getPropertyMatches() { |
|
129 | |||
130 | 2 | $type = $this->entity->getType(); |
|
131 | 2 | $query = elgg_extract('query', $this->params); |
|
132 | 2 | $fields = elgg_extract('fields', $this->params); |
|
133 | |||
134 | 2 | switch ($type) { |
|
135 | case 'user' : |
||
136 | $exclude = ['metadata' => ['name', 'username', 'description']]; |
||
137 | break; |
||
138 | case 'group' : |
||
139 | $exclude = ['metadata' => ['name', 'description']]; |
||
140 | break; |
||
141 | case 'object' : |
||
142 | 2 | $exclude = ['metadata' => ['title', 'description']]; |
|
143 | 2 | break; |
|
144 | } |
||
145 | |||
146 | 2 | $matches = []; |
|
147 | 2 | if (!empty($fields)) { |
|
148 | 1 | foreach ($fields as $property_type => $property_type_fields) { |
|
149 | 1 | foreach ($property_type_fields as $field) { |
|
150 | 1 | if (!empty($exclude[$property_type]) && in_array($field, $exclude[$property_type])) { |
|
151 | continue; |
||
152 | } |
||
153 | |||
154 | 1 | switch ($property_type) { |
|
155 | case 'attributes' : |
||
156 | case 'metadata' : |
||
157 | 1 | $property_values = $this->entity->$field; |
|
158 | 1 | break; |
|
159 | |||
160 | case 'annotations' : |
||
161 | $property_values = []; |
||
162 | $annotations = $this->entity->getAnnotations([ |
||
163 | 'annotation_names' => $field, |
||
164 | 'limit' => 0, |
||
165 | ]); |
||
166 | foreach ($annotations as $annotation) { |
||
167 | $property_values[] = $annotation->value; |
||
168 | } |
||
169 | break; |
||
170 | |||
171 | case 'private_settings' : |
||
172 | $property_values = $this->entity->getPrivateSetting($field); |
||
173 | break; |
||
174 | } |
||
175 | |||
176 | 1 | if (is_array($property_values)) { |
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
177 | foreach ($property_values as $text) { |
||
178 | if (stristr($text, $query)) { |
||
179 | $matches[$property_type][$field][] = $this->highlighter->highlight($text, 1, 300); |
||
180 | } |
||
181 | } |
||
182 | } else { |
||
183 | 1 | if (stristr($property_values, $query)) { |
|
184 | 1 | $matches[$property_type][$field][] = $this->highlighter->highlight($property_values, 1, 300); |
|
185 | } |
||
186 | } |
||
187 | } |
||
188 | } |
||
189 | } |
||
190 | |||
191 | 2 | return $matches; |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * Get label for a property |
||
196 | * |
||
197 | * @param string $property_type Property type |
||
198 | * @param string $property_name Property name |
||
199 | * |
||
200 | * @return string |
||
201 | */ |
||
202 | 1 | protected function getFieldLabel($property_type, $property_name) { |
|
203 | |||
204 | 1 | $type = $this->entity->getType(); |
|
205 | 1 | $subtype = $this->entity->getSubtype(); |
|
206 | |||
207 | 1 | $prefix = 'search'; |
|
208 | |||
209 | 1 | switch ($type) { |
|
210 | case 'user' : |
||
211 | $prefix = 'profile'; |
||
212 | break; |
||
213 | case 'group' : |
||
214 | $prefix = 'group'; |
||
215 | break; |
||
216 | case 'object' : |
||
217 | 1 | $prefix = 'tag_names'; |
|
218 | 1 | break; |
|
219 | } |
||
220 | |||
221 | $keys = [ |
||
222 | 1 | "$type:$subtype:$property_type:field:$property_name", |
|
223 | 1 | "$type:$property_type:$property_name", |
|
224 | 1 | "$prefix:$property_type:$property_name", |
|
225 | 1 | "$type:$subtype:field:$property_name", |
|
226 | 1 | "$type:$property_name", |
|
227 | 1 | "$prefix:$property_name", |
|
228 | ]; |
||
229 | |||
230 | 1 | $label = elgg_echo("tag_names:$property_name"); |
|
231 | |||
232 | 1 | foreach ($keys as $key) { |
|
233 | 1 | if (elgg_language_key_exists($key)) { |
|
234 | $label = elgg_echo($key); |
||
235 | 1 | break; |
|
236 | } |
||
237 | } |
||
238 | |||
239 | 1 | return $label; |
|
240 | } |
||
241 | |||
242 | /** |
||
243 | * Format icon |
||
244 | * @return void |
||
245 | */ |
||
246 | 2 | protected function formatIcon() { |
|
247 | 2 | if ($this->entity->getVolatileData('search_icon')) { |
|
248 | return; |
||
249 | } |
||
250 | |||
251 | 2 | $type = $this->entity->getType(); |
|
252 | 2 | $owner = $this->entity->getOwnerEntity(); |
|
253 | 2 | $container = $this->entity->getContainerEntity(); |
|
254 | |||
255 | 2 | $size = elgg_extract('size', $this->params, 'small'); |
|
256 | |||
257 | 2 | $icon = ''; |
|
258 | |||
259 | 2 | if ($this->entity->hasIcon($size) || $this->entity instanceof \ElggFile) { |
|
260 | $icon = elgg_view_entity_icon($this->entity, $size); |
||
261 | 2 | } else if ($type == 'user' || $type == 'group') { |
|
262 | $icon = elgg_view_entity_icon($this->entity, $size); |
||
263 | 2 | } else if ($owner instanceof ElggUser) { |
|
264 | $icon = elgg_view_entity_icon($owner, $size); |
||
265 | 2 | } else if ($container instanceof ElggUser) { |
|
266 | // display a generic icon if no owner, though there will probably be |
||
267 | // other problems if the owner can't be found. |
||
268 | $icon = elgg_view_entity_icon($this->entity, $size); |
||
269 | } |
||
270 | |||
271 | 2 | $this->entity->setVolatileData('search_icon', $icon); |
|
272 | 2 | } |
|
273 | |||
274 | /** |
||
275 | * Format URL |
||
276 | * @return void |
||
277 | */ |
||
278 | 2 | protected function formatURL() { |
|
279 | 2 | if (!$this->entity->getVolatileData('search_url')) { |
|
280 | 2 | $url = $this->entity->getURL(); |
|
281 | 2 | $this->entity->setVolatileData('search_url', $url); |
|
282 | } |
||
283 | 2 | } |
|
284 | |||
285 | /** |
||
286 | * Format time |
||
287 | * @return void |
||
288 | */ |
||
289 | 2 | protected function formatTime() { |
|
290 | 2 | if (!$this->entity->getVolatileData('search_time')) { |
|
291 | 2 | $this->entity->setVolatileData('search_time', $this->entity->time_created); |
|
292 | } |
||
293 | 2 | } |
|
294 | } |
||
295 |