Phần 1 - Custom Image Search với Solr, Filefield Sources và Ctools

Phần 1 - Custom Image Search với Solr, Filefield Sources và Ctools

Over the years I have been a big fan and user of Apache Solr for search on Drupal sites, in particular using the Apache Solr Search set of modules, mostly because of its speed and ability to create facets for drilling down into search results, along with the flexibilty provided by the module API to customize the functionality as needed. While re-building the NewsBusters site from scratch in D7 last year, one of the issues that the users wanted to address was finding existing images to re-use in blog posts.

The existing functionality used a file browsing functionality in the WYSIWYG, and as the number of images added to the site grew, just loading the browser to search for an image could take a few minutes. Another change we were making in the D7 version was storing all of our images on Amazon S3 (using the S3FS module), so I figured that I would take this chance to create a custom image search that used Solr. This would address speed issues, and would also allow the users to index metadata about images that could be used later to search for images.

>> Hướng dẫn Integrating multisite Drupal với Apache Solr

>> Cài đặt Docker development environment với Vagrant - Phần 3

>> Giới thiệu the future of decoupled Drupal

One module that I have used in the past that allows some image searching functionality is Filefield Sources. For instance, it allows you to get images from remote URLs, search the files directory with an autocomplete textfield, and attach from a server directory. However, I needed to do something custom, and fortunately, the module implementshooks that allows you to create your own custom source. Fortunately the Autocomplete reference field does what I already need to do once I get the image name and fid, so all I need to do is create my search functionality and write the approriate values to the text field.

As I mentioned above, I also wanted to index metadata about the image to allow for better searching, so I needed to find a way to store that data. I initially tried extending the image field in code (with no luck), so after looking at the avaialable options, I settled on the Field Collection module. This allowed me to create a group of four fields for each image:

  • Image
  • Person
  • Organization
  • Year

So to start out, I create a custom module (nb_image_search), and I declare my custom source using hook_filefield_sources_info():

/**
 * Implements hook_filefield_sources_info().
 */
function nb_image_search_filefield_sources_info() {
  $source = array();
  $source['imgsearch'] = array(
    'name' => t('Image search with Solr'),
    'label' => t('Image Search'),
    'description' => t('Search for an existing image using Apache Solr'),
    'process' => 'nb_image_search_image_search_process',
    'value' => 'nb_image_search_image_search_value',
    'weight' => 1,
    'file' => 'includes/image_search.inc',
  );

  return $source;
}

The items in this array are:

  • name - the name of the option displayed in the image field settings for File Sources
  • label - The name of the option that is displayed on the node create/edit form.
  • description - The description of the source
  • process - the name of the process function that does all the heavy-work of creating a form element for searching and populating a field.
  • value - This callback function then takes the value of that field and saves the  file locally.
  • weight - Used for ordering the enabled sources on the node create screen.
  • file - The path to the file where the process and value functions are stored.

A second hook implementation that is needed is hook_theme():

/**
 * Implements hook_theme().
 */
function nb_image_search_theme() {
  return array(
    'nb_image_search_image_search_element' => array(
      'render element' => 'element',
      'file' => 'includes/image_search.inc',
    ),
  );
}

This specifies the theme function that will be used to theme the custom element.

Next up is the process function. This is basically a form function that defines the element for searching.

define('FILEFIELD_SOURCE_IMGSEARCH_HINT_TEXT', 'example.png [fid:123]');

/**
 * A #process callback to extend the filefield_widget element type.
 */
function nb_image_search_image_search_process($element, &$form_state, $form) {
  $element['imgsearch'] = array(
    '#weight' => 100.5,
    '#theme' => 'nb_image_search_image_search_element',
    '#filefield_source' => TRUE, // Required for proper theming.
    '#filefield_sources_hint_text' => FILEFIELD_SOURCE_IMGSEARCH_HINT_TEXT,
  );

  $element['imgsearch']['file_url'] = array(
    '#type' => 'textfield',
    '#maxlength' => NULL,
  );

  // Handle this being a Field Collection entity.
  if (isset($element['#entity']->is_new) && $element['#entity']->is_new == TRUE) {
    $nid = 0;
  }
  else {
    if (isset($element['#entity']->nid)) {
      $nid = $element['#entity']->nid;
    }
    elseif(isset($form_state['node']->nid)) {
      $nid = $form_state['node']->nid;
    }
  }

  // Get id for field within the field collection. Use the position of the languge value since it's right before the number.
  $language = $element['#language'];
  $lang_pos = strpos($element['#id'], $language);
  $id = !is_object($element['#file']) ? substr($element['#id'], $lang_pos + strlen($language) + 1, 1) : 0;

  $element['imgsearch']['search'] = array(
    '#type' => 'markup',
    '#markup' => '<div id="imgsearch">' . l("Search for Image", 'imgsearch/nojs/' . $id . '/' . $element['#bundle'], array('attributes' => array('class' => 'ctools-use-modal ctools-modal-imgsearch-modal-style'))) . '</div>'
  );

  $element['imgsearch']['select'] = array(
    '#name' => implode('_', $element['#array_parents']) . '_imgsearch_select',
    '#type' => 'submit',
    '#value' => t('Select'),
    '#validate' => array(),
    '#submit' => array('filefield_sources_field_submit'),
    '#name' => $element['#name'] . '[imgsearch]',
    '#limit_validation_errors' => array($element['#parents']),
    '#ajax' => array(
      'path' => 'file/ajax/' . implode('/', $element['#array_parents']) . '/' . $form['form_build_id']['#value'],
      'wrapper' => $element['upload_button']['#ajax']['wrapper'],
      'effect' => 'fade',
    ),
  );

  return $element;
}

This creates the links and fields for the source as shown below.

Most of this is copied from the reference source, but there are a couple custom things going on here.

First, a Field Collection is a completely separate entity attached to the node, so it requires some custom code to get the node id.

Second, the $element['imgsearch']['search'] markup is a link to a custom page function (detailed in a later post) that generates the ctools modal window. There are two ctools classes applied to the link:

  • ctools-use-modal - opens the page callback being called in a modal window
  • ctools-modal-imgsearch-modal-style - a class to match custom settings for the modal that  defined in hook_node_prepare():
/**
 * Implementation of hook_node_prepare
 */
function nb_image_search_node_prepare($node) {
  if ($node->type == 'blog') {
    ctools_include('modal');
    ctools_modal_add_js();

    // Add custom settings for form size.
    drupal_add_js(array(
      'imgsearch-modal-style' => array(
        'modalSize' => array(
          'type' => 'fixed',
          'width' => 1000,
          'height' => 1200,
        ),
        'animation' => 'fadeIn',
        'closeText' => t('Close Search Window'),
        'loadingText' => t('Loading the Image Search window'),
      ),
    ), 'setting');
  }
}

When clicked on, this link will open up your modal window. Details of the window content will be covered in the next post.

Bạn thấy bài viết này như thế nào?: 
No votes yet
Ảnh của Tommy Tran

Tommy owner Express Magazine

Drupal Developer having 9+ year experience, implementation and having strong knowledge of technical specifications, workflow development. Ability to perform effectively and efficiently in team and individually. Always enthusiastic and interseted to study new technologies

  • Skype ID: tthanhthuy

Tìm kiếm bất động sản

 

Advertisement

 

jobsora

Dich vu khu trung tphcm

Dich vu diet chuot tphcm

Dich vu diet con trung

Quảng Cáo Bài Viết

 
Những kỹ thuật trong Ajax

Những kỹ thuật trong Ajax

AJAX (Asynchronous JavaScript and XML - nghĩa là "JavaScript và XML không đồng bộ") là một nhóm các công nghệ phát triển web được sử dụng để tạo các ứng dụng web động

Sẽ giảm lãi suất (LS) các món nợ cũ cho tất cả doanh nghiệp (DN) và hộ dân xuống 15%/năm?

Sẽ giảm lãi suất (LS) các món nợ cũ cho tất cả doanh nghiệp (DN) và hộ dân xuống 15%/năm?

Tuyên bố chắc như đinh đóng cột sẽ giảm lãi suất (LS) các món nợ cũ cho tất cả doanh nghiệp (DN) và hộ dân xuống 15%/năm, nhưng không ít ngân hàng (NH) cố tình vẽ ra các điều kiện ngặt nghèo để "ngáng đường" DN.

Ai đang ứng dụng Cloud Computing?

Ai đang ứng dụng Cloud Computing?

Có thể nói, điện toán đám mây chính là xu hướng phát triển mới của ứng dụng trong tương lai. Các ông lớn như IBM, Google, Microsoft cũng đang rục rịch chuẩn bị cho nền tảng điện toán đám mây của riêng mình.

Công ty diệt chuột T&C

 

Diet con trung