'Search pages', 'description' => 'Create and configure search pages.', 'page callback' => 'search_api_page_admin_overview', 'access arguments' => array('administer search_api'), 'file' => 'search_api_page.admin.inc', 'type' => MENU_LOCAL_TASK, ); $items[$pre . '/add'] = array( 'title' => 'Add search page', 'description' => 'Add a new search page.', 'page callback' => 'drupal_get_form', 'page arguments' => array('search_api_page_admin_add'), 'access arguments' => array('administer search_api'), 'file' => 'search_api_page.admin.inc', 'type' => MENU_LOCAL_ACTION, ); $items[$pre . '/%search_api_page'] = array( 'title' => 'Edit search page', 'description' => 'Configure or delete a search page.', 'page callback' => 'drupal_get_form', 'page arguments' => array('search_api_page_admin_edit', 5), 'access arguments' => array('administer search_api'), 'file' => 'search_api_page.admin.inc', ); // During uninstallation, this would lead to a fatal error otherwise. if (module_exists('search_api_page')) { foreach (search_api_page_load_multiple(FALSE, array('enabled' => TRUE)) as $page) { $items[$page->path] = array( 'title' => $page->name, 'description' => $page->description ? $page->description : '', 'page callback' => 'search_api_page_view', 'page arguments' => array((string) $page->machine_name), 'access arguments' => array('access search_api_page'), 'file' => 'search_api_page.pages.inc', 'type' => MENU_SUGGESTED_ITEM, ); } } $ret['results']['#theme'] = 'materiobase_results'; $ret['results']['#index'] = search_api_index_load($page->index_id); $ret['results']['#results'] = $results; $ret['results']['#view_mode'] = isset($page->options['view_mode']) ? $page->options['view_mode'] : 'search_api_page_result'; $ret['results']['#keys'] = $keys; $ret['results']['#page_machine_name'] = $page->machine_name; return $items; } /** * Implements hook_theme(). */ function search_api_page_theme() { $themes['search_api_page_results'] = array( 'variables' => array( 'index' => NULL, 'results' => array('result count' => 0), 'items' => array(), 'view_mode' => 'search_api_page_result', 'keys' => '', 'page_machine_name' => NULL, 'spellcheck' => NULL, 'pager' => NULL, ), 'file' => 'search_api_page.pages.inc', 'template' => 'search-api-page-results', ); $themes['search_api_page_result'] = array( 'variables' => array( 'index' => NULL, 'result' => NULL, 'item' => NULL, 'keys' => '', 'list_classes' => '', ), 'file' => 'search_api_page.pages.inc', 'template' => 'search-api-page-result', ); $themes['search_performance'] = array( 'render element' => 'element', ); $themes['search_results_list'] = array( 'render element' => 'element', ); return $themes; } /** * Implements theme for rendering search-performance */ function theme_search_performance($variables) { $element = array_shift($variables); return $element['#markup']; } /** * Returns HTML for a list of search results. * Taken from theme_item_list(). * * @param $variables * An associative array containing: * - items: An array of items to be displayed in the list. If an item is a * string, then it is used as is. If an item is an array, then the "data" * element of the array is used as the contents of the list item. If an item * is an array with a "children" element, those children are displayed in a * nested list. All other elements are treated as attributes of the list * item element. * - type: The type of list to return (e.g. "ul", "ol"). * - attributes: The attributes applied to the list element. */ function theme_search_results_list($variables) { // Pull Element array from the $variables array. $variables = $variables['element']; $items = $variables['items']; // Full data $type = $variables['type']; // CSS classes for ul $attributes = (!empty($variables['attributes'])) ? $variables['attributes'] : array(); $attributes['class'] = array_merge( array('item-list', 'search-results-list'), (isset($attributes['class'])) ? $attributes['class'] : array() ); // Render items within a list if (!empty($items)) { $output = "<$type" . drupal_attributes($attributes) . '>'; $num_items = count($items); // Parse search results as tokens to access items with full data. $i = 0; foreach ($variables['results'] as $result) { // Set css classes. $item_attributes = array(); if ($i == 0) { $item_attributes['class'][] = 'first'; } if ($i == $num_items - 1) { $item_attributes['class'][] = 'last'; } (($i+1)%2) ? $item_attributes['class'][] = 'odd': $item_attributes['class'][] = 'even'; // Define render array. $data = theme( 'search_api_page_result', array( 'index' => $variables['index'], // Use full results index. 'result' => $result, 'item' => isset($items[$result['id']]) ? $items[$result['id']] : NULL, 'keys' => $variables['keys'], 'list_classes' => drupal_attributes($item_attributes), ) ); $output .= $data . "\n"; $i++; } $output .= ""; return $output; } } /** * Implements hook_permission(). */ function search_api_page_permission() { return array( 'access search_api_page' => array( 'title' => t('Access search pages'), 'description' => t('Execute searches using the Search pages module.'), ), ); } /** * Implements hook_block_info(). */ function search_api_page_block_info() { $blocks = array(); foreach (search_api_page_load_multiple(FALSE, array('enabled' => TRUE)) as $page) { $blocks[$page->machine_name] = array( 'info' => t('Search block: !name', array('!name' => $page->name)), ); } return $blocks; } /** * Implements hook_block_view(). */ function search_api_page_block_view($delta) { $page = search_api_page_load($delta); if ($page) { $block = array(); $block['subject'] = t($page->name); $block['content'] = drupal_get_form('search_api_page_search_form_' . $page->machine_name, $page, NULL, TRUE); return $block; } } /** * Implements hook_forms(). */ function search_api_page_forms($form_id, $args) { $forms = array(); foreach (search_api_page_load_multiple(FALSE, array('enabled' => TRUE)) as $page) { $forms['search_api_page_search_form_' . $page->machine_name] = array( 'callback' => 'search_api_page_search_form', 'callback arguments' => array(), ); } return $forms; } /** * Implements hook_entity_info(). */ function search_api_page_entity_info() { $info['search_api_page'] = array( 'label' => t('Search page'), 'controller class' => 'EntityAPIControllerExportable', 'metadata controller class' => FALSE, 'entity class' => 'Entity', 'base table' => 'search_api_page', 'uri callback' => 'search_api_page_url', 'module' => 'search_api_page', 'exportable' => TRUE, 'entity keys' => array( 'id' => 'id', 'label' => 'name', 'name' => 'machine_name', ), ); return $info; } /** * Implements hook_entity_property_info(). */ function search_api_page_entity_property_info() { $info['search_api_page']['properties'] = array( 'id' => array( 'label' => t('ID'), 'type' => 'integer', 'description' => t('The primary identifier for a search page.'), 'schema field' => 'id', 'validation callback' => 'entity_metadata_validate_integer_positive', ), 'index_id' => array( 'label' => t('Index ID'), 'type' => 'token', 'description' => t('The machine name of the index this search page uses.'), 'schema field' => 'index_id', ), 'index' => array( 'label' => t('Index'), 'type' => 'search_api_index', 'description' => t('The index this search page uses.'), 'getter callback' => 'search_api_page_get_index', ), 'name' => array( 'label' => t('Name'), 'type' => 'text', 'description' => t('The displayed name for a search page.'), 'schema field' => 'name', 'required' => TRUE, ), 'machine_name' => array( 'label' => t('Machine name'), 'type' => 'token', 'description' => t('The internally used machine name for a search page.'), 'schema field' => 'machine_name', 'required' => TRUE, ), 'description' => array( 'label' => t('Description'), 'type' => 'text', 'description' => t('The displayed description for a search page.'), 'schema field' => 'description', 'sanitize' => 'filter_xss', ), 'enabled' => array( 'label' => t('Enabled'), 'type' => 'boolean', 'description' => t('A flag indicating whether the search page is enabled.'), 'schema field' => 'enabled', ), ); return $info; } /** * Implements hook_search_api_index_update(). */ function search_api_page_search_api_index_update(SearchApiIndex $index) { if (!$index->enabled && $index->original->enabled) { foreach (search_api_page_load_multiple(FALSE, array('index_id' => $index->machine_name, 'enabled' => 1)) as $page) { search_api_page_edit($page->id, array('enabled' => 0)); } } } /** * Implements hook_search_api_index_delete(). */ function search_api_page_search_api_index_delete(SearchApiIndex $index) { // Only react on real delete, not revert. if ($index->hasStatus(ENTITY_IN_CODE)) { return; } foreach (search_api_page_load_multiple(FALSE, array('index_id' => $index->machine_name)) as $page) { search_api_page_delete($page->id); } } /** * Implements hook_search_api_page_insert(). * * Rebuilds the menu table if a search page is created. */ function search_api_page_search_api_page_insert(Entity $page) { menu_rebuild(); } /** * Implements hook_search_api_page_update(). * * Rebuilds the menu table if a search page is edited. */ function search_api_page_search_api_page_update(Entity $page) { if ($page->enabled != $page->original->enabled || $page->path != $page->original->path) { menu_rebuild(); } } /** * Implements hook_search_api_page_delete(). * * Rebuilds the menu table if a search page is removed. */ function search_api_page_search_api_page_delete(Entity $page) { menu_rebuild(); } /** * Entity URI callback. */ function search_api_page_url(Entity $page) { return array('path' => $page->path); } /** * Entity property getter callback. */ function search_api_page_get_index(Entity $page) { return search_api_index_load($page->index_id); } /** * Loads a search page. * * @param $id * The page's id or machine name. * @param $reset * Whether to reset the internal cache. * * @return Entity * A completely loaded page object, or NULL if no such page exists. */ function search_api_page_load($id, $reset = FALSE) { $ret = entity_load_multiple_by_name('search_api_page', array($id), array(), $reset); return $ret ? reset($ret) : FALSE; } /** * Load multiple search pages at once. * * @see entity_load() * * @param $ids * An array of page IDs or machine names, or FALSE to load all pages. * @param $conditions * An array of conditions on the {search_api_page} table in the form * 'field' => $value. * @param $reset * Whether to reset the internal entity_load cache. * * @return array * An array of page objects keyed by machine name. */ function search_api_page_load_multiple($ids = FALSE, array $conditions = array(), $reset = FALSE) { return entity_load_multiple_by_name('search_api_page', $ids, $conditions, $reset); } /** * Inserts a new search page into the database. * * @param array $values * An array containing the values to be inserted. * * @return * The newly inserted page's id, or FALSE on error. */ function search_api_page_insert(array $values) { foreach (array('name', 'machine_name', 'index_id', 'path') as $var) { if (!isset($values[$var])) { throw new SearchApiException(t('Property @field has to be set for the new search page.', array('@field' => $var))); } } if (empty($values['description'])) { $values['description'] = NULL; } if (empty($values['options'])) { $values['options'] = array(); } $fields = array( 'name' => $values['name'], 'machine_name' => $values['machine_name'], 'description' => $values['description'], 'enabled' => empty($values['enabled']) ? 0 : 1, 'index_id' => $values['index_id'], 'path' => $values['path'], 'options' => $values['options'], ); if (isset($values['id'])) { $fields['id'] = $values['id']; } $page = entity_create('search_api_page', $fields); $page->save(); return $page->id; } /** * Changes a page's settings. * * @param $id * The edited page's ID. * @param array $fields * The new field values to set. * * @return * 1 if fields were changed, 0 if the fields already had the desired values. */ function search_api_page_edit($id, array $fields) { $page = search_api_page_load($id, TRUE); $changeable = array('name' => 1, 'description' => 1, 'path' => 1, 'options' => 1, 'enabled' => 1, 'result_page_search_form'=>1); foreach ($fields as $field => $value) { if (isset($changeable[$field]) || $value === $page->$field) { $page->$field = $value; $new_values = TRUE; } } // If there are no new values, just return 0. if (empty($new_values)) { return 0; } $page->save(); return 1; } /** * Deletes a search page. * * @param $id * The ID of the search page to delete. * * @return * TRUE on success, FALSE on failure. */ function search_api_page_delete($id) { $page = search_api_page_load($id, TRUE); if (!$page) { return FALSE; } $page->delete(); menu_rebuild(); return TRUE; } /** * Display a search form. * * @param Entity $page * The search page for which this form is displayed. * @param $keys * The search keys. * @param $compact * Whether to display a compact form (e.g. for blocks) instead of a normal one. */ function search_api_page_search_form(array $form, array &$form_state, Entity $page, $keys = NULL, $compact = FALSE) { $form['keys_' . $page->id] = array( '#type' => 'textfield', '#title' => t('Enter your keywords'), '#title_display' => $compact ? 'invisible' : 'before', '#default_value' => $keys, '#size' => $compact ? 15 : 30, ); $form['base_' . $page->id] = array( '#type' => 'value', '#value' => $page->path, ); $form['id'] = array( '#type' => 'hidden', '#value' => $page->id, ); $form['submit_' . $page->id] = array( '#type' => 'submit', '#value' => t('Search'), ); if (!$compact) { $form = array( '#type' => 'fieldset', '#title' => $page->name, 'form' => $form, ); if ($page->description) { $form['text']['#markup'] = '

' . nl2br(check_plain($page->description)) . '

'; $form['text']['#weight'] = -5; } } return $form; } /** * Validation callback for search_api_page_search_form(). */ function search_api_page_search_form_validate(array $form, array &$form_state) { if (!trim($form_state['values']['keys_' . $form_state['values']['id']])) { form_set_error('keys_' . $form_state['values']['id'], t('Please enter at least one keyword.')); } } /** * Submit callback for search_api_page_search_form(). */ function search_api_page_search_form_submit(array $form, array &$form_state) { $keys = trim($form_state['values']['keys_' . $form_state['values']['id']]); // @todo Take care of "/"s in the keys $form_state['redirect'] = $form_state['values']['base_' . $form_state['values']['id']] . '/' . $keys; }