Improving developer experience
Drupal Module
by
Shibin Das (D34dMan)
Hides a lot of implementation details while querying solr.
It helps developer focus on business logic.
Website builders and site admins should not need this module unless some other modules has dependency on apachesolr_api.
It does not expose any User interface or admin screen.
Using Git
Using Drush
Using Composer
git clone --branch 7.x-1.x https://git.drupal.org/project/apachesolr_api.gitdrush dl apachesolr_apicomposer require drupal/apachesolr_apiApachesolr API is available on Drupal.org
/**
* Implements hook_apachesolr_api_config().
*/
function mymodule_apachesolr_api_config() {
$data = [
'pages' => [],
];
return $data;
}Initial Setup
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.module
/**
* Implements hook_apachesolr_api_config().
*/
function mymodule_apachesolr_api_config() {
$data = [
'pages' => [
'push_grid_random' => [],
],
];
return $data;
}
/**
* Implements hook_apachesolr_api_config().
*/
function mymodule_apachesolr_api_config() {
$data = [
'pages' => [
'push_grid_random' => [
'apachesolr' => [
'params' => [
'fl' => 'entity_id id',
'fq' => [
'bundle:(article OR page)',
],
],
],
],
],
];
return $data;
}
/**
* Implements hook_apachesolr_api_config().
*/
function mymodule_apachesolr_api_config() {
$data = [
'pages' => [
'push_grid_random' => [
'apachesolr' => [
'params' => [
'fl' => 'entity_id id',
'fq' => [
'bundle:(article OR page)',
],
],
'map' => [
'nid' => 'entity_id',
],
],
],
],
];
return $data;
}
/**
* Implements hook_apachesolr_api_config().
*/
function mymodule_apachesolr_api_config() {
$data = array();
$path = drupal_get_path('module', 'mymodule');
if ($path) {
$filepath = $path . '/apachesolr_api_config.yaml';
$realpath = drupal_realpath($filepath);
$yaml = file_get_contents($filepath);
$data = yaml_parser_parse_string($yaml);
}
return $data;
}Initial Setup (using yaml configuration file)
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
push_grid_random:
apachesolr:
params:
fl: "entity_id id"
fq:
- bundle:(article OR page)Initial Setup (using yaml configuration file)
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml# Use "pages" key to store various query.
pages:
# A custom key that would be used to retrieve the results of a query later.
push_grid_random:
apachesolr:
# The parameters of the solr query.
params:
fl: "entity_id"
fq:
- bundle:(article OR page)Initial Setup (using yaml configuration file)
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml/**
* Get push grid as render array.
*/
function mymodule_get_push_grid() {
$results = apachesolr_api_fetch('push_grid_random', '*', []);
foreach ($results['rows'] as $item) {
// The results can be rendered using a view mode.
$node = node_load($item['entity_id']);
if ($node) {
$items[] = node_view($node, 'teaser');
}
}
$content = [
'#theme' => 'mymodule_push_grid',
'#items' => $items,
];
}Querying apachesolr and display data
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
push_grid_random:
apachesolr:
params:
fl: "entity_id id label url"
fq:
- bundle:(article OR page)Avoiding node_load()
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml/**
* Get push grid as render array.
*/
function mymodule_get_push_grid() {
$results = apachesolr_api_fetch('push_grid_random', '*', []);
$content = [
'#theme' => 'mymodule_push_grid',
'#items' => $results['rows'],
];
}Avoiding node_load()
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
push_grid_random:
apachesolr:
params:
fl: "entity_id id label url"
fq:
- bundle:(article OR page)
map:
nid: entity_id
title: label
link: urlPreprocessing variables for theme
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yamlpages:
search_autocomplete:
url: ajax/rmh-search/%
menu_item:
title: Search Suggestions
page callback: 'mymodule_search_autocomplete_callback'
page arguments:
- 2
access arguments:
- access content
apachesolr:
fuzzy: TRUE
fuzzy_weight: 1
params:
fl: "id, label, content, teaser, entity_id, bundle, entity_type, path, url"
hl: TRUE
hl.fl: "content, label"
rows: 10
hl.simple.pre: "<mark>"
hl.simple.post: "</mark>"
hl.simple.snippets: TRUE
qf:
- "label^20"
- "content^5"
map:
label: label
content: content
url: pathConfiguration for autocomplete callback
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml
/**
* Autocomplete callback.
*/
function mymodule_search_autocomplete_callback($search_string) {
$search_string = empty($search_string) ? "*" : $search_string;
$results = apachesolr_api_fetch('search_autocomplete', $search_string, []);
drupal_json_output($results['rows']);
drupal_exit();
}Autocomplete callback
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
search_detail_page:
url: search-results/%
menu_item:
title: Search results
page callback: 'mymodule_search_details_page_callback'
page arguments:
- 1
access arguments:
- access content
apachesolr:
fuzzy: TRUE
fuzzy_weight: 1
params:
fl: "id, label, content, teaser, entity_id, bundle, entity_type, path, url"
hl: TRUE
hl.fl: "content, label"
rows: 10
hl.snippets: 1
hl.fragsize: 300
hl.simple.pre: "<mark>"
hl.simple.post: "</mark>"
hl.simple.snippets: TRUE
qf:
- "label^20"
- "content^5"
map:
label: label
content: content
url: pathConfiguration for Search Results Page
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml
/**
* Search details page callback.
*/
function mymodule_search_details_page_callback($search_string) {
$search_string = empty($search_string) ? "*" : $search_string;
$results = apachesolr_api_fetch('search_detail_page', $search_string, []);
if ($results['meta']['total_rows']) {
$output = theme('mymodule_search_results', $results);
}
else {
$results['meta']['title'] = t("We're sorry, no results found");
$output = theme('mymodule_search_results_empty', $results);
}
return $output;
}Search Detail Page Callback
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.moduleOut of the box Apache Solr Search module can index nodes and their fields, but Panelizer pages won't be indexed
As discussed in a blog post at previousnext, we could get the rendered output form page_manager, cleaning it using apachesolr clean text function, and setting it as a content of apachesolr document.
panelized content types:
- story
- landing_page
- article_pagePanelizer Configuration
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yamlFlag module does not store its data in normal Drupal fields. So the user interactions are not stored in the index.
Similar to what we do for Panelizer content, inject the flag data into document while it gets build.
flag:
save_for_later:
entity:
node:
bundle:
- module_intro
flag_machine_name: save_for_later
recommend:
entity:
node:
bundle:
- module_intro
flag_machine_name: recommendFlags Configuration
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yamlpages:
documentation_center:
apachesolr:
params:
fl: "entity_id id"
rows: 9
facet: true
facet.field: sm_field_media_collection
facet.mincount: 1
fq:
- bundle:(media_pdf OR media_sample)
sort: ds_changed desc, id desc
map:
nid: entity_idFacets Configuration
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yamlpages:
documentation_center:
apachesolr:
params:
fl: "entity_id id"
rows: 9
facet: true
facet.field: sm_field_media_collection
facet.mincount: 1
fq:
- bundle:(media_pdf OR media_sample)
sort: ds_changed desc, id desc
map:
nid: entity_idFilters configuration (Query)
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yamlpages:
documentation_center:
apachesolr:
filters:
# Filter type. Single boolean query.
query:
# Custom identifier for the filter.
downloadable:
# Dynamic query fragment that will be applied when the filter is active
solr_query: bs_field_media_downloadable:true
# the url query string to hold the filter status
query_string: bif_dc_dwld
params:
fl: "entity_id id"
rows: 9
facet: true
facet.field: sm_field_media_collection
facet.mincount: 1
fq:
- bundle:(media_pdf OR media_sample)
sort: ds_changed desc, id desc
map:
nid: entity_idFilters configuration (Query)
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml
/**
* Some page callback/panel that displays results.
*/
function mymodule_apachesolr_documentation_center_content() {
...
$filters = drupal_get_query_parameters();
$results = apachesolr_api_fetch('documentation_center', "*", [], $filters);
$download_filter = $results['filters']['query']['downloadable'];
// $download_filter is an array which contains status and url for the filter.
...
}Query Filter
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
documentation_center:
apachesolr:
filters:
# Collection of a field facet
facet_fields:
collections:
solr_field: sm_field_media_collection
query_string: bif_dc_cltn
multiple_behaviour: OR
field_type: taxonomy_term
params:
fl: "entity_id id"
rows: 9
fq:
- bundle:(media_pdf OR media_sample)
sort: ds_changed desc, id desc
map:
nid: entity_idFilters configuration (Faceted)
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml
/**
* Some page callback/panel that displays results.
*/
function mymodule_apachesolr_documentation_center_content() {
...
$filters = drupal_get_query_parameters();
$results = apachesolr_api_fetch('documentation_center', "*", [], $filters);
foreach ($results['filters']['facet_field']['collections'] as $key => $filter) {
// $filter contains status and url for the faceted filter.
}
...
}Query Filter
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
documentation_center:
apachesolr:
filters:
# Single boolean query
query:
activated:
solr_query: bs_field_media_activated_order:true
query_string: bif_dc_ao
# Collection of a field facet
facet_fields:
collections:
solr_field: sm_field_media_collection
query_string: bif_dc_cltn
multiple_behaviour: OR
field_type: taxonomy_term
params:
fl: "entity_id id"
rows: 9
facet: true
facet.field: sm_field_media_collection
facet.mincount: 1
fq:
- bundle:(media_pdf OR media_sample)
sort: ds_changed desc, id desc
map:
nid: entity_idFilters configuration (Faceted)
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml
/**
* Some page callback/panel that displays results.
*/
function mymodule_apachesolr_documentation_center_content() {
...
$filters = drupal_get_query_parameters();
$results = apachesolr_api_fetch('documentation_center', "*", [], $filters);
foreach ($results['filters']['facet_field']['collections'] as $key => $filter) {
// $filter contains status and url for the faceted filter.
// $filter also contains count and total count for the current query.
}
...
}Query Filter
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.modulepages:
documentation_center:
apachesolr:
pagination:
type: cursors
query_string: bif_dc_csr
filters:
# Single boolean query
query:
activated:
solr_query: bs_field_media_activated_order:true
query_string: bif_dc_ao
params:
fl: "entity_id id"
rows: 9
facet: true
facet.field: sm_field_media_collection
facet.mincount: 1
fq:
- bundle:(media_pdf OR media_sample)
sort: ds_changed desc, id desc
map:
nid: entity_idPagination Configuration
File : apachesolr_api_config.yaml
Location : sites/all/modules/custom/mymodule/apachesolr_api_config.yaml
/**
* Some page callback/panel that displays results.
*/
function mymodule_apachesolr_documentation_center_content() {
...
$filters = drupal_get_query_parameters();
$results = apachesolr_api_fetch('documentation_center', "*", [], $filters);
$next = $results['meta']['pagination']['next'];
// $next contains the url to load more results as suitable for infinite scroll.
...
}Pagination
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.module/**
* Get push grid as render array.
*/
function mymodule_get_push_grid() {
$params = [];
global $user;
// Add dynamic parameter to restrict results specific to current user as author.
$params['fq'][] = 'is_uid:' . $user->uid;
$results = apachesolr_api_fetch('push_grid_random', '*', $params);
foreach ($results['rows'] as $item) {
// The results can be rendered using a view mode.
$node = node_load($item['nid']);
if ($node) {
$items[] = node_view($node, 'teaser');
}
}
$content = [
'#theme' => 'mymodule_push_grid',
'#items' => $items,
];
}Custom parameters - author is current user
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.module/**
* Get push grid as render array.
*/
function mymodule_get_push_grid() {
$seed = rand();
$params = [
'sort' => "random_$seed desc",
];
$results = apachesolr_api_fetch('push_grid_random', '*', $params);
foreach ($results['rows'] as $item) {
// The results can be rendered using a view mode.
$node = node_load($item['nid']);
if ($node) {
$items[] = node_view($node, 'teaser');
}
}
$content = [
'#theme' => 'mymodule_push_grid',
'#items' => $items,
];
}Custom parameters - randomise
File : mymodule.module
Location : sites/all/modules/custom/mymodule/mymodule.module