Steps to reproduce:

  • create a text field called "series"
  • Map it as a facet with the code below
  • Enable the new facet at /admin/config/search/apachesolr/settings/solr/facets
  • Enable the new block at /admin/structure/block
  • Create a node with an apostrophe in the series field
  • Run cron, wait
  • Search for your node
function mymodule_apachesolr_field_mappings_alter(&$mappings) {
  // Single string fields
  $ss_mapping = $mappings['list_text'];
  $ss_mapping['map callback'] = '';
  $mappings['per-field']['field_series'] = $ss_mapping;
  $mappings['per-field']['field_series']['multiple'] = FALSE;
}

function mymodule_facetapi_facet_info() {
  $facets['ss_field_series'] = array(
    'name' => 'ss_field_series',
    'label' => 'Series',
    'description' => 'Series',
  );
  return $facets;
}

CommentFileSizeAuthor
#5 1778476.patch1.21 KBgrendzy
#1 facetapi_1778476.patch791 bytesgrendzy
encoded_facets.png49.49 KBgrendzy

Comments

grendzy’s picture

Status: Active » Needs review
StatusFileSize
new791 bytes

Since apachesolr stores text html-encoded (not sure why, but it does), it needs to be decoded before rendering (see the source of apachesolr_l()).

This patch uses html_entity_decode() instead of the Drupal equivalent function, following the example in apachesolr_l().

grendzy’s picture

Project: Facet API » Apache Solr Search
Issue summary: View changes

fix php

cpliakas’s picture

Project: Apache Solr Search » Facet API

Hi grendzy.

Thanks for the detailed steps on how to reproduce this issue and the excellent debugging. My one comment on this patch, though, is that I don't want to make assumptions in Facet API based on the backend. For example, if the core Search module doesn't return encoded HTML strings, than it should not run through a link function that decodes html elements to account for how Apache Solr stores it's values.

What I would recommend is creating a "map callback" for your facet to act on the values accordingly. For example, modify your snippet using the code below:

function mymodule_apachesolr_field_mappings_alter(&$mappings) {
  // Single string fields
  $ss_mapping = $mappings['list_text'];
  $ss_mapping['map callback'] = 'mymodule_map_series';
  $mappings['per-field']['field_series'] = $ss_mapping;
  $mappings['per-field']['field_series']['multiple'] = FALSE;
}

function mymodule_facetapi_facet_info() {
  $facets['ss_field_series'] = array(
    'name' => 'ss_field_series',
    'label' => 'Series',
    'description' => 'Series',
  );
  return $facets;
}

function mymodule_map_series(array $values, array $options) {
  $map = array();
  foreach ($values as $value) {
    $map[$value] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
  }
  return $map;
}

This will have the benefit of decoding the HTML entities only for the effected facet.

Thanks,
Chris

grendzy’s picture

Component: Code » Documentation
Category: bug » task
Status: Needs review » Needs work

Thanks for the thoughtful reply, I wasn't aware of the implications for non-solr backends. I'd like to leave this open as a documentation issue for the moment, if that's OK. I'll try to study a bit more with the goal of a documentation or handbook patch.

BTW, do you know if the hook_facetapi_facet_info() is necessary in this case, or is there an alternative way to make text facets visible through the apachesolr module (since it implements the facetapi hook as well)? The reason I ask is while I agree the map callback a a straightforward fix, it seems like a leaky abstraction, I wouldn't expect to be handling encoding at such a high level.

cpliakas’s picture

grendzy,

Sounds good. I will leave it open.

Regarding hook_facetapi_facet_info(), Apache Solr Search Integration does have a higher level hook which defines all Solr fields, and then implements hook_facetapi_facet_info() automatically. Check out the hook_apachesolr_field_mappings() implementations for examples of how this is done. Some of the keys are simply passed along to Facet API, for example the "query type" and "map callback" keys just to name a couple. This way you can define a field that is available to Apache Solr Search Integration and expose it as a facet all in one shot.

Hope this helps,
Chris

grendzy’s picture

Project: Facet API » Apache Solr Search
Component: Documentation » Code
Category: task » bug
Status: Needs work » Needs review
StatusFileSize
new1.21 KB

I found the relevant documentation is in apachesolr.api.php.

I couldn't think of a sensible way to document this without actually adding a callback to the module, so this patch includes a new function: apachesolr_string_facet_map_callback().

nick_vh’s picture

Status: Needs review » Closed (works as designed)

I don't think this should be in the main module but in a custom module of your own? I am going to close this one but it is very useful for future references as I can imagine more people will have similar questions.

grendzy’s picture

Status: Closed (works as designed) » Needs work

Thanks for the feedback, would you consider a documentation-only patch to apachesolr.api.php?

As it's written, I think the documentation for hook_apachesolr_field_mappings_alter() is incorrect. If a user follows the documentation to "Enable indexing for text fields" this problem will occur every time. It's also a costly problem to debug (it took me about 12 hours to get to the bottom of it).

nick_vh’s picture

I'd surely consider an API only patch. Feel free to provide one, with a link to this issue.

nick_vh’s picture

Status: Needs work » Closed (fixed)

Closing this as fixed since the solution is here but no documentation patch was written. At least people can find it here :)

nick_vh’s picture

Issue summary: View changes

add missing cron step