Поиск
Содержание
Поиск сущностей
Ядро Elgg предоставляет гибкий elgg_search(), который подготавливает пользовательские предложения поиска и использует elgg_get_entities() для получения результатов.
В дополнение ко всем параметрам, принимаемым elgg_get_entities(), elgg_search() принимает следующее:
queryПоисковый запрос
fieldsМассив имён по типу свойства для поиска (см. пример ниже)
sort_byМассив, содержащий параметры сортировки, включая property, property_type и direction
typeТип сущности для поиска
subtypeНеобязательный подтип сущности для поиска
search_typeПользовательский тип поиска (обязательно, если не предоставленtype)
partial_matchРазрешить частичные совпаденияПо умолчанию разрешены частичные совпадения, что означает, что
elggбудет найдено при поискеel. Точные совпадения могут быть полезны, когда вы хотите сопоставить значения тегов, например, когда вы хотите найти все объекты, которые являютсяred, а неdarkred
tokenizeРазбить поисковый запрос на токеныПо умолчанию поисковые запросы токенизируются, что означает, что мы найдём
elgg has been releasedпри поискеelgg released
// List all users who list United States as their address or mention it in their description
$options = [
'type' => 'user',
'query' => 'us',
'fields' => [
'metadata' => ['description'],
'annotations' => ['location'],
],
'sort_by' => [
'property' => 'zipcode',
'property_type' => 'annotation',
'direction' => 'asc',
],
];
echo elgg_list_entities($options, 'elgg_search');
Поля поиска
Вы можете настроить поля поиска для каждого типа/подтипа сущности, используя событие search:fields:
// Let's remove search in location and add address field instead
elgg_register_event_handler('search:fields', 'user', 'my_plugin_search_user_fields');
function my_plugin_search_user_fields(\Elgg\Event $event) {
$fields = $event->getValue();
$location_key = array_search('location', $fields['annotations']);
if ($location_key) {
unset($fields[$location_key]['annotations']);
}
$fields['metadata'][] = 'address';
return $fields;
}
Поисковые типы
Чтобы зарегистрировать тип сущности для поиска, используйте elgg_entity_enable_capability($type, $subtype, 'searchable') или сделайте это при определении типа сущности в elgg-plugin.php.
Примечание
Плагин поиска использует возможность сущности searchable. Эта возможность определяет, можно ли искать сущность.
Чтобы объединить результаты поиска или отфильтровать, как результаты поиска представляются в плагине поиска, используйте событие 'search:config', 'type_subtype_pairs'.
// Let's add places and place reviews as public facing entities
elgg_entity_enable_capability('object', 'place', 'searchable');
elgg_entity_enable_capability('object', 'place_review', 'searchable');
// Now let's include place reviews in the search results for places
elgg_register_event_handler('search:options', 'object:place', 'my_plugin_place_search_options');
elgg_register_event_handler('search:config', 'type_subtype_pairs', 'my_plugin_place_search_config');
// Add place review to search options as a subtype
function my_plugin_place_search_options(\Elgg\Event $event) {
$params = $event->getParams();
if (isset($params['subtypes'])) {
$subtypes = (array) $params['subtypes'];
} else {
$subtypes = (array) elgg_extract('subtype', $params);
}
if (!in_array('place', $subtypes)) {
return;
}
unset($params["subtype"]);
$subtypes[] = 'place_review';
$params['subtypes'] = $subtypes;
return $params;
}
// Remove place reviews as a separate entry in search sections
function my_plugin_place_search_config(\Elgg\Event $event) {
$types = $event->getValue();
if (empty($types['object'])) {
return;
}
foreach ($types['object'] as $key => $subtype) {
if ($subtype == 'place_review') {
unset($types['object'][$key]);
}
}
return $types;
}
Пользовательские типы поиска
Ядро Elgg поддерживает только поиск сущностей. Вы можете реализовать пользовательский поиск, например, используя поисковый запрос как местоположение и выводя список сущностей по близости к этому местоположению.
// Let's added proximity search type
elgg_register_event_handler('search:config', 'search_types', function (\Elgg\Event $event) {
$search_types = $event->getValue();
$search_types[] = 'promimity';
return $search_types;
});
// Let's add search options that will look for entities that have geo coordinates and order them by proximity to the query location
elgg_register_event_handler('search:options', 'proximity', function (\Elgg\Event $event) {
$query = $event->getParam('query');
$options = $event->getValue();
// Let's presume we have a geocoding API
$coords = geocode($query);
// We are not using standard 'selects' options here, because counting queries do not use custom selects
$options['wheres']['proximity'] = function (QueryBuilder $qb, $alias) use ($lat, $long) {
$dblat = $qb->joinMetadataTable($alias, 'guid', 'geo:lat');
$dblong = $qb->joinMetadataTable($alias, 'guid', 'geo:long');
$qb->addSelect("(((acos(sin(($lat*pi()/180))
*sin(($dblat.value*pi()/180)) + cos(($lat*pi()/180))
*cos(($dblat.value*pi()/180))
*cos((($long-$dblong.value)*pi()/180)))))*180/pi())
*60*1.1515*1.60934
AS proximity");
$qb->orderBy('proximity', 'asc');
return $qb->merge([
$qb->compare("$dblat.value", 'is not null'),
$qb->compare("$dblong.value", 'is not null'),
]);
};
return $options;
});
Конечная точка автодополнения и живого поиска
Ядро предоставляет конечную точку JSON для поиска пользователей и групп. Эти конечные точки используются представлениями input/autocomplete и input/entitypicker.
// Get JSON results of a group search for 'class'
$json = file_get_contents('http://example.com/livesearch/groups?view=json&q=class');
Вы можете добавить пользовательские типы поиска, добавив соответствующее представление ресурса:
// Let's add an endpoint that will search for users that are not members of a group
// and render a userpicker for our invite form
echo elgg_view('input/userpicker', [
'handler' => 'livesearch/non_members',
'options' => [
// this will be sent as URL query elements
'group_guid' => $group_guid,
],
]);
// To enable /livesearch/non_members endpoint, we need to add a view
// in /views/json/resources/livesearch/non_members.php
$limit = get_input('limit', elgg_get_config('default_limit'));
$query = get_input('term', get_input('q'));
$input_name = get_input('name');
// We have passed this value to our input view, and we want to make sure
// external scripts are not using it to mine data on group members
// so let's validate the HMAC that was generated by the userpicker input
$group_guid = (int) get_input('group_guid');
$data = [
'group_guid' => $group_guid,
];
// let's sort by key, in case we have more elements
ksort($data);
$hmac = elgg_build_hmac($data);
if (!$hmac->matchesToken(get_input('mac'))) {
// request does not originate from our input view
throw new \Elgg\Exceptions\Http\EntityPermissionsException();
}
elgg_set_http_header("Content-Type: application/json;charset=utf-8");
$options = [
'query' => $query,
'type' => 'user',
'limit' => $limit,
'sort' => 'name',
'order' => 'ASC',
'fields' => [
'metadata' => ['name', 'username'],
],
'item_view' => 'search/entity',
'input_name' => $input_name,
'wheres' => function (QueryBuilder $qb) use ($group_guid) {
$subquery = $qb->subquery('entity_relationships', 'er');
$subquery->select('1')
->where($qb->compare('er.guid_one', '=', 'e.guid'))
->andWhere($qb->compare('er.relationship', '=', 'member', ELGG_VALUE_STRING))
->andWhere($qb->compare('er.guid_two', '=', $group_guid, ELGG_VALUE_INTEGER));
return "NOT EXISTS ({$subquery->getSQL()})";
}
];
echo elgg_list_entities($options, 'elgg_search');