updated webform, webform_localization, profile2, term_merge, search_api_saved_pages, rules, redirect, overide_node_options
This commit is contained in:
@@ -1,3 +1,32 @@
|
||||
Search API Saved Searches 1.7 (2018-09-17):
|
||||
-------------------------------------------
|
||||
- #2971725 by martin_klima, mh86, drunken monkey: Fixed reaction to a user
|
||||
changing their mail address.
|
||||
- #2907340 by ClassicCut, drunken monkey: Fixed checking alerts via Rules.
|
||||
- #2521976 by natew, drunken monkey, lukedekker: Fixed double-encoding of query
|
||||
parameters when displaying saved searches with Views.
|
||||
- #2795599 by drunken monkey: Increased the maximum length of saved search
|
||||
names.
|
||||
|
||||
Search API Saved Searches 1.6 (2017-07-18):
|
||||
-------------------------------------------
|
||||
- #1118138 by MorinLuc0, drunken monkey: Added Rules integration for sending
|
||||
notifications.
|
||||
- #2856331 by drunken monkey: Fixed access check for the "Create saved search"
|
||||
page.
|
||||
- #2216453 by drunken monkey: Fixed exception for saved searches after fulltext
|
||||
fields change.
|
||||
- #2665578 by drunken monkey: Fixed notices caused by missing $original in
|
||||
hook_user_update().
|
||||
- #2597143 by drunken monkey: Added an option to allow users to edit a saved
|
||||
search's keywords.
|
||||
- #2532078 by krishna savithraj: Added a hidden setting to give the cron job
|
||||
more time to execute.
|
||||
- #2602532 by kaptenkolja, drunken monkey: Fixed handling of multi-valued
|
||||
fields when creating a new saved search manually.
|
||||
- #2564969 by drunken monkey: Fixed escaping of fields option labels.
|
||||
- #1306622 by drunken monkey: Fixed token handling for anonymous users.
|
||||
|
||||
Search API Saved Searches 1.5 (2015-06-08):
|
||||
-------------------------------------------
|
||||
- #2346679 by drunken monkey, dcmul: Added display of saved search
|
||||
|
@@ -11,13 +11,13 @@ Facet, Views or other filters set for the search will also be included in a
|
||||
saved search, thus reflecting exactly the same search results as displayed.
|
||||
|
||||
Bug reports, feature suggestions and latest developments:
|
||||
http://drupal.org/project/issues/search_api_saved_searches
|
||||
https://www.drupal.org/project/issues/search_api_saved_searches
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
* Install the module as usual.
|
||||
See http://drupal.org/documentation/install/modules-themes/modules-7
|
||||
See http://drupal.org/documentation/install/modules-themes/modules-7
|
||||
for further information.
|
||||
* Set the module's permissions (Administer saved searches, Use saved searches).
|
||||
* You can now configure saved searches for each index by going to its
|
||||
@@ -25,3 +25,10 @@ Installation
|
||||
* For being able to actually save searches, you have to enable the
|
||||
"[Index Name]: Save search" block. This block will only appear on pages which
|
||||
contain a Search API search and allow users to save the executed search.
|
||||
|
||||
Hidden variables
|
||||
----------------
|
||||
|
||||
* search_api_saved_search_queue_item_time (default: 10)
|
||||
By default, queue item time is set to 10 seconds. This setting lets you modify
|
||||
the queue item time by providing your own value in seconds.
|
||||
|
@@ -56,6 +56,7 @@ function search_api_saved_searches_index_edit(array $form, array &$form_state, S
|
||||
'choose_name' => FALSE,
|
||||
'registered_user_delete_key' => FALSE,
|
||||
'show_empty_list' => FALSE,
|
||||
'allow_keys_change' => FALSE,
|
||||
'user_select_interval' => TRUE,
|
||||
'interval_options' => array(
|
||||
60 * 60 * 24 => t('Daily'),
|
||||
@@ -82,6 +83,7 @@ If you didn't create this saved search, just ignore this mail and it will be del
|
||||
-- [site:name] team"),
|
||||
);
|
||||
$settings->options['mail']['notify'] += array(
|
||||
'send' => TRUE,
|
||||
'title' => t('New results for your saved search at [site:name]'),
|
||||
'body' => t('[user:name],
|
||||
|
||||
@@ -156,9 +158,10 @@ You can configure your saved searches at the following address:
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['options'] = array(
|
||||
$form['options']['misc']['date_field'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => NULL,
|
||||
'#parents' => array('options', 'date_field'),
|
||||
);
|
||||
}
|
||||
$form['options']['misc']['description'] = array(
|
||||
@@ -227,6 +230,13 @@ You can configure your saved searches at the following address:
|
||||
'#default_value' => $options['show_empty_list'],
|
||||
'#parents' => array('options', 'show_empty_list'),
|
||||
);
|
||||
$form['options']['misc']['allow_keys_change'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow changing of keywords'),
|
||||
'#description' => t("Whether to let users also change the saved search's keywords when editing it."),
|
||||
'#default_value' => $options['allow_keys_change'],
|
||||
'#parents' => array('options', 'allow_keys_change'),
|
||||
);
|
||||
|
||||
// @todo Access options? Maximum number of saved searches per user, maximum
|
||||
// number of results to create saved search, minimum number of filters?
|
||||
@@ -333,11 +343,23 @@ You can configure your saved searches at the following address:
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['options']['mail']['notify_send'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Send mail notifications for new results'),
|
||||
'#description' => t('Depending on the notification interval, send regular mail updates with new results for saved searches. Disable this option if you want to use some other mechanism to notify the user of new results (or if you do not want any notifications at all).'),
|
||||
'#default_value' => $options['mail']['notify']['send'],
|
||||
'#parents' => array('options', 'mail', 'notify', 'send'),
|
||||
);
|
||||
$form['options']['mail']['notify'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Notification mails'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => $settings->enabled,
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[mail][notify][send]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['options']['mail']['notify']['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
@@ -438,7 +460,7 @@ You can configure your saved searches at the following address:
|
||||
if (!empty($index->options['fields'])) {
|
||||
$fields = array();
|
||||
foreach ($index->getFields() as $field => $info) {
|
||||
$fields[$field] = $info['name'];
|
||||
$fields[$field] = check_plain($info['name']);
|
||||
}
|
||||
}
|
||||
if (!empty($fields)) {
|
||||
|
@@ -10,9 +10,8 @@ files[] = views/handler_field_saved_search_interval.inc
|
||||
files[] = views/handler_field_saved_search_link.inc
|
||||
files[] = views/handler_field_saved_search_name.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-06-08
|
||||
version = "7.x-1.5"
|
||||
; Information added by Drupal.org packaging script on 2018-09-17
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "search_api_saved_searches"
|
||||
datestamp = "1433745784"
|
||||
|
||||
datestamp = "1537174700"
|
||||
|
@@ -98,7 +98,7 @@ function search_api_saved_searches_schema() {
|
||||
'name' => array(
|
||||
'description' => 'The displayed name for this saved search.',
|
||||
'type' => 'varchar',
|
||||
'length' => 50,
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'mail' => array(
|
||||
@@ -160,6 +160,7 @@ function search_api_saved_searches_schema() {
|
||||
*/
|
||||
function search_api_saved_searches_uninstall() {
|
||||
variable_del('search_api_saved_searches_search_ids');
|
||||
variable_del('search_api_saved_search_queue_item_time');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,3 +243,16 @@ function search_api_saved_searches_update_7105() {
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the maximum length of the {search_api_saved_search}.name field.
|
||||
*/
|
||||
function search_api_saved_searches_update_7106() {
|
||||
$spec = array(
|
||||
'description' => 'The displayed name for this saved search.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
);
|
||||
db_change_field('search_api_saved_search', 'name', 'name', $spec);
|
||||
}
|
||||
|
@@ -35,8 +35,8 @@ function search_api_saved_searches_menu() {
|
||||
'title' => 'Create saved search',
|
||||
'description' => 'Create a new saved search.',
|
||||
'page callback' => 'search_api_saved_searches_create_manual',
|
||||
'access callback' => 'search_api_saved_search_create_access',
|
||||
'access arguments' => array(NULL, TRUE),
|
||||
'access callback' => 'search_api_saved_search_create_personal_access',
|
||||
'access arguments' => array(1),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
'file' => 'search_api_saved_searches.pages.inc',
|
||||
);
|
||||
@@ -315,6 +315,17 @@ function search_api_saved_searches_user_insert(&$edit, $account, $category) {
|
||||
* changes.
|
||||
*/
|
||||
function search_api_saved_searches_user_update(&$edit, $account, $category) {
|
||||
// Sometimes this update hook is invoked without setting $account->original.
|
||||
// In this case, we need to load the original ourselves.
|
||||
if (empty($account->original)) {
|
||||
if (!empty($account->uid)) {
|
||||
$account->original = entity_load_unchanged('user', $account->uid);
|
||||
}
|
||||
// If the original couldn't be loaded, we cannot do anything here.
|
||||
if (empty($account->original)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// For newly activated users, transfer all saved searches with their mail
|
||||
// address to them.
|
||||
if (!empty($account->status) && empty($account->original->status)) {
|
||||
@@ -334,9 +345,9 @@ function search_api_saved_searches_user_update(&$edit, $account, $category) {
|
||||
}
|
||||
}
|
||||
// If the user's mail address changed, also change the mail address of the
|
||||
// user's saved searches.
|
||||
// user's saved searches from previous (original) to current address.
|
||||
if ($account->mail != $account->original->mail) {
|
||||
foreach (search_api_saved_search_load_multiple(FALSE, array('mail' => $account->mail, 'uid' => $account->uid)) as $search) {
|
||||
foreach (search_api_saved_search_load_multiple(FALSE, array('mail' => $account->original->mail, 'uid' => $account->uid)) as $search) {
|
||||
$search->mail = $account->mail;
|
||||
$search->save();
|
||||
}
|
||||
@@ -352,8 +363,6 @@ function search_api_saved_searches_user_delete($account) {
|
||||
entity_delete_multiple('search_api_saved_search', array_keys(search_api_saved_search_load_multiple(FALSE, array('uid' => $account->uid))));
|
||||
}
|
||||
|
||||
// @todo Rules integration
|
||||
|
||||
/**
|
||||
* Implements hook_search_api_index_update().
|
||||
*
|
||||
@@ -573,6 +582,29 @@ function search_api_saved_search_create_access(SearchApiSavedSearchesSettings $s
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback: Checks access for the user-specific "add search" page.
|
||||
*
|
||||
* @param object $account
|
||||
* The account whose "add search" page is visited.
|
||||
*
|
||||
* @return boolean
|
||||
* TRUE if the current user is allowed to create a new saved search using this
|
||||
* page; FALSE otherwise.
|
||||
*/
|
||||
function search_api_saved_search_create_personal_access($account) {
|
||||
global $user;
|
||||
|
||||
if (user_access('administer search_api_saved_searches')) {
|
||||
return TRUE;
|
||||
}
|
||||
if ($account->uid !== $user->uid) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return search_api_saved_search_create_access(NULL, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine access to the edit interface for saved searches of a given user.
|
||||
*
|
||||
@@ -771,7 +803,7 @@ function search_api_saved_searches_save_form(array $form, array &$form_state, Se
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
'#description' => t('Enter the name that will be displayed for this saved search.'),
|
||||
'#maxlength' => 50,
|
||||
'#maxlength' => 255,
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -787,7 +819,7 @@ function search_api_saved_searches_save_form(array $form, array &$form_state, Se
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
'#maxlength' => 50,
|
||||
'#maxlength' => 255,
|
||||
'#size' => 16,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => _search_api_saved_searches_create_name($form_state['query']),
|
||||
@@ -946,7 +978,16 @@ function search_api_saved_searches_save_form_submit(array $form, array &$form_st
|
||||
unset($fields['search_api_saved_searches_fulltext']);
|
||||
foreach ($fields as $field => $value) {
|
||||
if ($value || is_numeric($value)) {
|
||||
$query['filters'][] = array($field, $value, '=');
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $single_value) {
|
||||
if ($single_value) {
|
||||
$query['filters'][] = array($field, $single_value, '=');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$query['filters'][] = array($field, $value, '=');
|
||||
}
|
||||
}
|
||||
else {
|
||||
unset($fields[$field]);
|
||||
@@ -975,7 +1016,16 @@ function search_api_saved_searches_save_form_submit(array $form, array &$form_st
|
||||
}
|
||||
foreach ($fields as $field => $value) {
|
||||
if (empty($page_options['direct_filter_params'])) {
|
||||
$form_state['page']['query']['filter'][$field][] = '"' . $value . '"';
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $single_value) {
|
||||
if ($single_value) {
|
||||
$form_state['page']['query']['f'][] = $field . ':' . $single_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form_state['page']['query']['f'][] = $field . ':' . $value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form_state['page']['query'][$field] = $value;
|
||||
@@ -1120,17 +1170,7 @@ function search_api_saved_searches_mail($key, array &$message, array $params) {
|
||||
* Queue the saved searches that should be checked for new items.
|
||||
*/
|
||||
function search_api_saved_searches_cron() {
|
||||
// Get all searches whose last execution lies more than the notify_interval
|
||||
// in the past. Add a small amount to the current time, so small differences
|
||||
// in execution time don't result in a delay until the next cron run.
|
||||
$ids = db_select('search_api_saved_search', 's')
|
||||
->fields('s', array('id'))
|
||||
->condition('enabled', 1)
|
||||
->condition('notify_interval', 0, '>=')
|
||||
->where('last_execute >= last_queued')
|
||||
->where('last_queued + notify_interval < :time', array(':time' => REQUEST_TIME + 15))
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$ids = search_api_saved_searches_get_searches_to_be_executed();
|
||||
if (!$ids) {
|
||||
return;
|
||||
}
|
||||
@@ -1142,18 +1182,58 @@ function search_api_saved_searches_cron() {
|
||||
// by settings is necessary since the mails can differ between settings.
|
||||
$user_searches = array();
|
||||
foreach ($searches as $search) {
|
||||
$user_searches[$search->mail . ' ' . $search->settings_id][] = $search->id;
|
||||
// Set the last execution timestamp now, so the interval doesn't move and we
|
||||
// don't get problems if the next cron run occurs before the queue is
|
||||
// completely executed.
|
||||
$search->last_queued = REQUEST_TIME;
|
||||
$search->save();
|
||||
// Check whether notifications are enabled for this search.
|
||||
$settings = search_api_saved_searches_settings_load($search->settings_id);
|
||||
$options = $settings->options;
|
||||
if (!isset($options['mail']['notify']['send']) || $options['mail']['notify']['send']) {
|
||||
$user_searches[$search->mail . ' ' . $search->settings_id][] = $search->id;
|
||||
// Set the last execution timestamp now, so the interval doesn't move and we
|
||||
// don't get problems if the next cron run occurs before the queue is
|
||||
// completely executed.
|
||||
$search->last_queued = REQUEST_TIME;
|
||||
$search->save();
|
||||
}
|
||||
}
|
||||
foreach ($user_searches as $searches) {
|
||||
$queue->createItem($searches);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the saved searches that need to be executed.
|
||||
*
|
||||
* @param string|int|null $settings_id
|
||||
* (optional) The ID or delta of the saved search settings entity for which to
|
||||
* retrieve searches. NULL to retrieve for all.
|
||||
*
|
||||
* @return int[]
|
||||
* The IDs of all searches that need to be executed.
|
||||
*/
|
||||
function search_api_saved_searches_get_searches_to_be_executed($settings_id = NULL) {
|
||||
// Get all searches whose last execution lies more than the notify_interval
|
||||
// in the past. Add a small amount to the current time, so small differences
|
||||
// in execution time don't result in a delay until the next cron run.
|
||||
$select = db_select('search_api_saved_search', 's');
|
||||
$select->fields('s', array('id'))
|
||||
->condition('enabled', 1)
|
||||
->condition('notify_interval', 0, '>=')
|
||||
->where('last_execute >= last_queued')
|
||||
->where('last_queued + notify_interval < :time', array(':time' => REQUEST_TIME + 15));
|
||||
if ($settings_id !== NULL) {
|
||||
// The {search_api_saved_search} table stores the setting as a machine name.
|
||||
// If the caller passed a numeric ID, we need to convert it.
|
||||
if (is_numeric($settings_id)) {
|
||||
$sql = 'SELECT delta FROM {search_api_saved_searches_settings} WHERE id = :id';
|
||||
$settings_id = db_query($sql, array(':id' => $settings_id))->fetchField();
|
||||
if ($settings_id === FALSE) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
$select->condition('settings_id', $settings_id);
|
||||
}
|
||||
return $select->execute()->fetchCol();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron_queue_info().
|
||||
*
|
||||
@@ -1163,7 +1243,7 @@ function search_api_saved_searches_cron_queue_info() {
|
||||
return array(
|
||||
'search_api_saved_searches_check_updates' => array(
|
||||
'worker callback' => 'search_api_saved_searches_check_updates',
|
||||
'time' => 10,
|
||||
'time' => variable_get('search_api_saved_search_queue_item_time', 10),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1208,81 +1288,108 @@ function search_api_saved_searches_check_updates(array $search_ids) {
|
||||
$index = $settings->index();
|
||||
$mail_params = array();
|
||||
foreach ($searches as $search) {
|
||||
try {
|
||||
// Make sure we run the query as the user who owns the saved search.
|
||||
// Otherwise node access will not work properly.
|
||||
$search->query['options']['search_api_access_account'] = $search->uid;
|
||||
// Get actual results for the query.
|
||||
$query = $search->query();
|
||||
|
||||
// If a date field is set, use that to filter results.
|
||||
if (!empty($settings->options['date_field'])) {
|
||||
$query->condition($settings->options['date_field'], $search->last_execute, '>');
|
||||
}
|
||||
$response = $query->execute();
|
||||
if (!empty($response['results'])) {
|
||||
$old = array();
|
||||
$new = $results = drupal_map_assoc(array_keys($response['results']));
|
||||
if (empty($settings->options['date_field'])) {
|
||||
// ID-based method: Compare these results to the old ones.
|
||||
$old = drupal_map_assoc(explode(',', $search->results));
|
||||
$new = array_diff_key($results, $old);
|
||||
}
|
||||
if ($new) {
|
||||
// We have new results: send them to the user.
|
||||
// Only load those items that will be sent.
|
||||
$sent_new = $new;
|
||||
if (!empty($settings->options['mail']['notify']['max_results'])) {
|
||||
$sent_new = array_slice($new, 0, $settings->options['mail']['notify']['max_results']);
|
||||
}
|
||||
$sent_new = $index->loadItems($sent_new);
|
||||
$new_results = $sent_new + $new;
|
||||
// Let other modules alter these results.
|
||||
drupal_alter('search_api_saved_searches_new_results', $new_results, $search);
|
||||
if ($new_results) {
|
||||
// We have to slice again in case some items were moved around or
|
||||
// removed by alter hooks.
|
||||
$sent_new = $new_results;
|
||||
if (!empty($settings->options['mail']['notify']['max_results'])) {
|
||||
$sent_new = array_slice($new_results, 0, $settings->options['mail']['notify']['max_results']);
|
||||
// Now some of the top results might still be unloaded.
|
||||
if ($unloaded = array_filter($sent_new, 'is_scalar')) {
|
||||
$sent_new = $index->loadItems($unloaded) + $sent_new;
|
||||
}
|
||||
}
|
||||
$num_results = count($new_results);
|
||||
$mail_params['searches'][] = array(
|
||||
'search' => $search,
|
||||
'num_results' => $num_results,
|
||||
'results' => $sent_new,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (empty($settings->options['date_field']) && ($new || array_diff($old, $results))) {
|
||||
// The results changed in some way: store the latest version.
|
||||
$search->results = implode(',', $results);
|
||||
}
|
||||
}
|
||||
// Use time() instead of REQUEST_TIME to minimize the potential of sending
|
||||
// duplicate results due to longer-running cron queue workers.
|
||||
$search->last_execute = time();
|
||||
$search->save();
|
||||
$results = search_api_saved_search_fetch_search_results($search);
|
||||
if (!$results['result_count']) {
|
||||
continue;
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
$args = _drupal_decode_exception($e);
|
||||
$args['@id'] = $search->id;
|
||||
throw new SearchApiException(t('%type while trying to check for new results on saved search @id: !message in %function (line %line of %file).', $args));
|
||||
// Load the result items.
|
||||
if ($results['results']) {
|
||||
$results['results'] = $index->loadItems($results['results']);
|
||||
}
|
||||
$mail_params['searches'][] = $results;
|
||||
}
|
||||
// If we set any searches in the mail parameters, send the mail.
|
||||
if ($mail_params) {
|
||||
$mail_params['user'] = user_load($search->uid);
|
||||
$mail_params['settings'] = $settings;
|
||||
$message = drupal_mail('search_api_saved_searches', 'notify', $search->mail,
|
||||
user_preferred_language($mail_params['user']), $mail_params);
|
||||
user_preferred_language($mail_params['user']), $mail_params);
|
||||
if ($message['result']) {
|
||||
watchdog('search_api_saved_searches', 'A mail with new saved search results was sent to @mail.',
|
||||
array('@mail' => $search->mail), WATCHDOG_INFO);
|
||||
array('@mail' => $search->mail), WATCHDOG_INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the results for a given search object.
|
||||
*
|
||||
* @param SearchApiSavedSearch $search
|
||||
* The saved search to check for new results.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with the following keys:
|
||||
* - search: The executed search.
|
||||
* - result_count: The number of new results.
|
||||
* - results: The IDs of the new results.
|
||||
*
|
||||
* @throws SearchApiException
|
||||
* If an error occurred in the search.
|
||||
*/
|
||||
function search_api_saved_search_fetch_search_results(SearchApiSavedSearch $search) {
|
||||
$return = array(
|
||||
'search' => $search,
|
||||
'result_count' => 0,
|
||||
'results' => array(),
|
||||
);
|
||||
|
||||
$settings = $search->settings();
|
||||
try {
|
||||
// Make sure we run the query as the user who owns the saved search.
|
||||
// Otherwise node access will not work properly.
|
||||
$search->query['options']['search_api_access_account'] = $search->uid;
|
||||
// Get actual results for the query.
|
||||
$query = $search->query();
|
||||
|
||||
// If a date field is set, use that to filter results.
|
||||
if (!empty($settings->options['date_field'])) {
|
||||
$query->condition($settings->options['date_field'], $search->last_execute, '>');
|
||||
}
|
||||
$response = $query->execute();
|
||||
if (!empty($response['results'])) {
|
||||
$old = array();
|
||||
$new = $results = drupal_map_assoc(array_keys($response['results']));
|
||||
if (empty($settings->options['date_field'])) {
|
||||
// ID-based method: Compare these results to the old ones.
|
||||
$old = drupal_map_assoc(explode(',', $search->results));
|
||||
$new = array_diff_key($results, $old);
|
||||
}
|
||||
if ($new) {
|
||||
// We have new results: send them to the user.
|
||||
// Only load those items that will be sent.
|
||||
$sent_new = $new;
|
||||
if (!empty($settings->options['mail']['notify']['max_results'])) {
|
||||
$sent_new = array_slice($new, 0, $settings->options['mail']['notify']['max_results']);
|
||||
}
|
||||
$new_results = $sent_new + $new;
|
||||
// Let other modules alter these results.
|
||||
drupal_alter('search_api_saved_searches_new_results', $new_results, $search);
|
||||
if ($new_results) {
|
||||
// We have to slice again in case some items were moved around or
|
||||
// removed by alter hooks.
|
||||
$sent_new = $new_results;
|
||||
if (!empty($settings->options['mail']['notify']['max_results'])) {
|
||||
$sent_new = array_slice($new_results, 0, $settings->options['mail']['notify']['max_results']);
|
||||
}
|
||||
$return['result_count'] = count($new_results);
|
||||
$return['results'] = $sent_new;
|
||||
}
|
||||
}
|
||||
if (empty($settings->options['date_field']) && ($new || array_diff($old, $results))) {
|
||||
// The results changed in some way: store the latest version.
|
||||
$search->results = implode(',', $results);
|
||||
}
|
||||
}
|
||||
// Use time() instead of REQUEST_TIME to minimize the potential of sending
|
||||
// duplicate results due to longer-running cron queue workers.
|
||||
$search->last_execute = time();
|
||||
$search->save();
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
$args = _drupal_decode_exception($e);
|
||||
$args['@id'] = $search->id;
|
||||
throw new SearchApiException(t('%type while trying to check for new results on saved search @id: !message in %function (line %line of %file).', $args));
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@@ -194,10 +194,22 @@ function search_api_saved_searches_search_edit_form(array $form, array &$form_st
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
'#description' => t('The name that will be displayed for this saved search.'),
|
||||
'#maxlength' => 50,
|
||||
'#maxlength' => 255,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $search->name,
|
||||
);
|
||||
if (!empty($settings->options['allow_keys_change'])) {
|
||||
$keywords = $search->query['keys'];
|
||||
if (is_array($keywords)) {
|
||||
$keywords = search_api_saved_searches_unparse_keys($keywords);
|
||||
}
|
||||
$form['keys'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Keywords'),
|
||||
'#description' => t('The keywords to use for this search.'),
|
||||
'#default_value' => $keywords,
|
||||
);
|
||||
}
|
||||
if ($settings->options['user_select_interval'] && count($settings->options['interval_options']) > 1) {
|
||||
$form['notify_interval'] = array(
|
||||
'#type' => 'select',
|
||||
@@ -224,6 +236,33 @@ function search_api_saved_searches_search_edit_form(array $form, array &$form_st
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the search keywords parsing to get string keywords.
|
||||
*
|
||||
* @param array $keys
|
||||
* An array with search keys, as defined by
|
||||
* SearchApiQueryInterface::getKeys().
|
||||
*
|
||||
* @return string
|
||||
* A guess regarding the original keys used to come up with the given keys
|
||||
* array.
|
||||
*/
|
||||
function search_api_saved_searches_unparse_keys(array $keys) {
|
||||
$simple_keys = array();
|
||||
|
||||
foreach (element_children($keys) as $i) {
|
||||
$key = $keys[$i];
|
||||
if (is_scalar($key)) {
|
||||
if (strpos($key, ' ')) {
|
||||
$key = '"' . $key . '"';
|
||||
}
|
||||
$simple_keys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $simple_keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submission handler for search_api_saved_searches_search_edit_form().
|
||||
*
|
||||
@@ -231,12 +270,21 @@ function search_api_saved_searches_search_edit_form(array $form, array &$form_st
|
||||
*/
|
||||
function search_api_saved_searches_search_edit_form_submit(array $form, array &$form_state) {
|
||||
$values = $form_state['values'];
|
||||
/** @var SearchApiSavedSearch $search */
|
||||
$search = $form_state['search'];
|
||||
$search->name = $values['name'];
|
||||
$search->enabled = $values['enabled'];
|
||||
if (isset($values['notify_interval'])) {
|
||||
$search->notify_interval = $values['notify_interval'];
|
||||
}
|
||||
|
||||
if (!empty($form['keys']) && $values['keys'] != $form['keys']['#default_value']) {
|
||||
$search->query['keys'] = ($values['keys'] === '') ? NULL : $values['keys'];
|
||||
// Unsetting the results array will automatically re-calculate the current
|
||||
// results when saving.
|
||||
$search->results = NULL;
|
||||
}
|
||||
|
||||
if ($search->save()) {
|
||||
drupal_set_message(t('Successfully saved your changes.'));
|
||||
if (!empty($form_state['destination'])) {
|
||||
|
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Rules integration for the Search API Saved Searches module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_rules_action_info().
|
||||
*/
|
||||
function search_api_saved_searches_rules_action_info() {
|
||||
return array(
|
||||
'search_api_saved_searches_rules_index_results' => array(
|
||||
'label' => t('Fetch the saved searches'),
|
||||
'parameter' => array(
|
||||
'index_id' => array(
|
||||
'type' => 'integer',
|
||||
'label' => t('Index for which to retrieve searches'),
|
||||
'description' => t('Select the search index for which saved searches should be retrieved.'),
|
||||
'options list' => '_search_api_saved_searches_settings_options_list',
|
||||
),
|
||||
),
|
||||
'provides' => array(
|
||||
'search_api_saved_search' => array(
|
||||
'type' => 'list<integer>',
|
||||
'label' => t('List of the IDs of the saved searches that require executing.'),
|
||||
),
|
||||
),
|
||||
'group' => t('Search API Saved Searches'),
|
||||
),
|
||||
'search_api_saved_searches_rules_get_saved_search_new_items' => array(
|
||||
'label' => t('Fetch the new results for a saved search'),
|
||||
'parameter' => array(
|
||||
'index_id' => array(
|
||||
'type' => 'integer',
|
||||
'label' => t('Saved search ID'),
|
||||
'description' => t('The ID of the saved search for which to retrieve new results.'),
|
||||
),
|
||||
),
|
||||
'provides' => array(
|
||||
'search' => array(
|
||||
'type' => 'search_api_saved_search',
|
||||
'label' => t('The executed search.'),
|
||||
),
|
||||
'result_count' => array(
|
||||
'type' => 'integer',
|
||||
'label' => t('The count of results that were found.'),
|
||||
),
|
||||
'results' => array(
|
||||
'type' => 'list<integer>',
|
||||
'label' => t('The list of new results for the saved search since it was last executed.'),
|
||||
),
|
||||
),
|
||||
'group' => t('Search API Saved Searches'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the options list for selecting a saved search settings entity.
|
||||
*
|
||||
* @return string[]
|
||||
* An associative array mapping saved search settings IDs to index names.
|
||||
*/
|
||||
function _search_api_saved_searches_settings_options_list() {
|
||||
// Fetch the list of saved searches setting and make a list of values.
|
||||
$entities = entity_load('search_api_saved_searches_settings');
|
||||
$ids = array();
|
||||
foreach ($entities as $entity) {
|
||||
$ids[$entity->index_id][] = $entity->id;
|
||||
}
|
||||
|
||||
$indexes = search_api_index_load_multiple(array_keys($ids));
|
||||
$options = array();
|
||||
foreach ($indexes as $index_id => $index) {
|
||||
foreach ($ids[$index_id] as $settings_id) {
|
||||
$options[$settings_id] = $index->label();
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: Implements the "Fetch the saved searches" rules action.
|
||||
*
|
||||
* @param int|null $settings_id
|
||||
* (optional) The ID of the saved search settings entity for which to retrieve
|
||||
* searches. NULL to retrieve for all.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with key "search_api_saved_search" containing the IDs
|
||||
* of all searches that should be executed.
|
||||
*/
|
||||
function search_api_saved_searches_rules_index_results($settings_id) {
|
||||
return array(
|
||||
'search_api_saved_search' => search_api_saved_searches_get_searches_to_be_executed($settings_id),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: Implements the "Fetch the new results for a search" rules action.
|
||||
*
|
||||
* @param int $search_id
|
||||
* The ID of the saved search setting entity.
|
||||
*
|
||||
* @return array
|
||||
* Array of the results count and the results list for the given search ID.
|
||||
*/
|
||||
function search_api_saved_searches_rules_get_saved_search_new_items($search_id) {
|
||||
$search = search_api_saved_search_load($search_id);
|
||||
return search_api_saved_search_fetch_search_results($search);
|
||||
}
|
@@ -191,14 +191,19 @@ class SearchApiSavedSearch extends Entity {
|
||||
* If the saved search's index is disabled.
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->index()->query($this->query['options']);
|
||||
if ($this->query['keys']){
|
||||
$index = $this->index();
|
||||
$query = $index->query($this->query['options']);
|
||||
if ($this->query['keys']) {
|
||||
$query->keys($this->query['keys']);
|
||||
}
|
||||
if ($this->query['fields']){
|
||||
$query->fields($this->query['fields']);
|
||||
if ($this->query['fields']) {
|
||||
$fields = (array) $this->query['fields'];
|
||||
$fields = array_intersect($fields, $index->getFulltextFields());
|
||||
if ($fields) {
|
||||
$query->fields($fields);
|
||||
}
|
||||
}
|
||||
if ($this->query['filters']){
|
||||
if ($this->query['filters']) {
|
||||
$filters = &$query->getFilter()->getFilters();
|
||||
$filters = $this->query['filters'];
|
||||
}
|
||||
|
@@ -149,14 +149,22 @@ function search_api_saved_searches_tokens($type, array $tokens, array $data = ar
|
||||
|
||||
switch ($type) {
|
||||
case 'user':
|
||||
if (!empty($data['user']->uid)) {
|
||||
if (isset($tokens['search-api-saved-searches-url'])) {
|
||||
$replacements[$tokens['search-api-saved-searches-url']] = url('user/' . $data['user']->uid . '/saved-searches', $url_options);
|
||||
if (isset($tokens['search-api-saved-searches-url'])) {
|
||||
$url_tokens = token_find_with_prefix($tokens, 'search-api-saved-searches-url');
|
||||
if (!empty($data['user']->uid)) {
|
||||
$path = 'user/' . $data['user']->uid . '/saved-searches';
|
||||
$replacements[$tokens['search-api-saved-searches-url']] = url($path, $url_options);
|
||||
if ($url_tokens) {
|
||||
$replacements += token_generate('url', $url_tokens, array(
|
||||
'path' => $path,
|
||||
), $options);
|
||||
}
|
||||
}
|
||||
if ($url_tokens = token_find_with_prefix($tokens, 'search-api-saved-searches-url')) {
|
||||
$replacements += token_generate('url', $url_tokens, array(
|
||||
'path' => 'user/' . $data['user']->uid . '/saved-searches',
|
||||
), $options);
|
||||
else {
|
||||
$replacements[$tokens['search-api-saved-searches-url']] = '';
|
||||
foreach ($url_tokens as $token) {
|
||||
$replacements[$token] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@@ -8,9 +8,8 @@ package = Multilingual - Internationalization
|
||||
files[] = search_api_saved_searches_i18n.controller.inc
|
||||
files[] = search_api_saved_searches_i18n.string_wrapper.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-06-08
|
||||
version = "7.x-1.5"
|
||||
; Information added by Drupal.org packaging script on 2018-09-17
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "search_api_saved_searches"
|
||||
datestamp = "1433745784"
|
||||
|
||||
datestamp = "1537174700"
|
||||
|
@@ -10,6 +10,13 @@
|
||||
*/
|
||||
class SearchApiSavedSearchesViewsHandlerFieldName extends views_handler_field {
|
||||
|
||||
/**
|
||||
* The ID of the currently rendered search.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
protected $currentSearchId;
|
||||
|
||||
public function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
@@ -29,24 +36,27 @@ class SearchApiSavedSearchesViewsHandlerFieldName extends views_handler_field {
|
||||
}
|
||||
|
||||
public function render($values) {
|
||||
$value = parent::render($values);
|
||||
if ($value && $this->options['link_to_page']) {
|
||||
$this->render_link($values);
|
||||
}
|
||||
return $value;
|
||||
$this->currentSearchId = isset($values->id) ? $values->id : NULL;
|
||||
return parent::render($values);
|
||||
}
|
||||
|
||||
public function render_link($values) {
|
||||
$search = !empty($values->id) ? search_api_saved_search_load($values->id) : NULL;
|
||||
if (search_api_saved_search_edit_access(NULL, $search) && !empty($search->options['page'])) {
|
||||
$this->options['alter']['make_link'] = TRUE;
|
||||
$page = $search->options['page'] + array(
|
||||
'path' => NULL,
|
||||
'query' => array(),
|
||||
'absolute' => TRUE,
|
||||
);
|
||||
$this->options['alter']['path'] = url($page['path'], $page);
|
||||
public function render_text($alter) {
|
||||
if ($this->options['link_to_page'] && $this->currentSearchId) {
|
||||
$search = search_api_saved_search_load($this->currentSearchId);
|
||||
if ($search && search_api_saved_search_edit_access(NULL, $search) && !empty($search->options['page'])) {
|
||||
$alter['make_link'] = TRUE;
|
||||
$page = $search->options['page'] + array(
|
||||
'path' => NULL,
|
||||
'query' => array(),
|
||||
);
|
||||
$alter['path'] = $page['path'];
|
||||
if ($page['query']) {
|
||||
$query = urldecode(drupal_http_build_query($page['query']));
|
||||
$alter['path'] .= '?' . $query;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::render_text($alter);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user