Support for views REST export settings

Created on 15 September 2021, about 3 years ago
Updated 11 June 2024, 6 months ago

Apologies if this has been answer elsewhere but I could not find it.

Does this module support in views 'REST export settings' ?

Our search is served using views restful api and I'm try to get the 'Did you mean' word in the api?

💬 Support request
Status

Active

Version

3.0

Component

Miscellaneous

Created by

🇬🇧United Kingdom drs2034

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇫🇷France gaspounet

    Two years and a half later I'm asking the same question: how to implement spellcheck in the context of a rest export?

    For example, is it possible to include the "did you mean" suggestion inside a metadata as pager or facets do?

  • 🇫🇷France gaspounet

    OK, I answer to my own question,

    For those who are interested, here is some code to create a custom serializer to use within a REST Export display which shows spellcheck suggestions in a "spellcheck" metadata inside the JSON response.

    modules/custom/my_custom_module/Plugin/views/style/CustomSerializer.php

    <?php
    namespace Drupal\my_custom_module\Plugin\views\style;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\rest\Plugin\views\style\Serializer;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Symfony\Component\Serializer\SerializerInterface;
    /**
     * The style plugin for serialized output formats.
     *
     * @ingroup views_style_plugins
     *
     * @ViewsStyle(
     *   id = "my_custom_serializer",
     *   title = @Translation( "My Custom serializer" ),
     *   help = @Translation( "Serializes views row data using the Serializer component." ),
     *   display_types = { "data" }
     * )
     */
    class CustomSerializer extends Serializer {
      public static function create( ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition ) {
        return new static(
          $configuration,
          $plugin_id,
          $plugin_definition,
          $container -> get( 'serializer' ),
          $container -> getParameter( 'serializer.formats' ),
          $container -> getParameter( 'serializer.format_providers' )
        );
      }
      public function __construct( array $configuration, $plugin_id, $plugin_definition, SerializerInterface $serializer, array $serializer_formats, array $serializer_format_providers ) {
        parent::__construct( $configuration, $plugin_id, $plugin_definition, $serializer, $serializer_formats, $serializer_format_providers );
      }
      protected function defineOptions() {
        $options = parent::defineOptions();
        $options[ 'spellcheck_count' ] = [ 'default' => 1 ];
        return $options;
      }
      public function buildOptionsForm( &$form, FormStateInterface $form_state ) {
        parent::buildOptionsForm( $form, $form_state );
        $form[ 'spellcheck_count' ] = [
          '#type' => 'number',
          '#title' => $this -> t( 'Spellcheck, amount of results to show' ),
          '#default_value' => $this -> options[ 'spellcheck_count' ],
        ];
      }
      public function render() {
        $rows = [];
        foreach ( $this -> view -> result as $row_index => $row ) {
          $this -> view -> row_index = $row_index;
          $row = $this -> view -> rowPlugin -> render( $row );
          //YOUR OWN CODE IF YOU WANT TO MAKE SOME MODIFICATION ON EACH ROW
          $rows[] = $row;
        }
        unset( $this -> view -> row_index) ;
        if ( empty( $this -> view -> live_preview ) ) {
          $content_type = $this -> displayHandler -> getContentType();
        } else {
          $content_type = !empty( $this -> options[ 'formats' ] ) ? reset( $this -> options[ 'formats' ] ) : 'json';
        }
        $fields = [];
        foreach ( $this -> view -> field as $field_name => $field ) {
          if ( $field -> options[ 'exclude' ] == 0 && $field -> label() ) {
            $fields[ $field_name ] = $field -> label();
          }
        }
        $current_page = 0;
        $total_items = 0;
        $total_pages = 0;
        $items_per_page = 0;
        $pager = $this -> view -> pager;
        if ( $pager ) {
          $class = get_class( $pager );
          $current_page = $pager -> getCurrentPage() ?? 0;
          $items_per_page = $pager -> getItemsPerPage();
          $total_items = $pager -> getTotalItems();
          if ( !in_array( $class, [
            'Drupal\views\Plugin\views\pager\None',
            'Drupal\views\Plugin\views\pager\Some',
          ] ) ) {
            $total_pages = $pager -> getPagerTotal();
          }
        } else {
          $current_page = intval( \Drupal::request() -> query -> get( 'page' ) );
          $items_per_page = 1;
          $total_pages = count( $rows );
          $total_items = count( $rows );
        }
        $spellcheck_suggestions = [];
        $query = $this -> view -> query;
        if ( $query instanceof \Drupal\search_api\Plugin\views\query\SearchApiQuery && $query -> getIndex() -> getServerInstance()-> supportsFeature( 'search_api_spellcheck' ) ) {
          $search_api_query = $query -> getSearchApiQuery();
          $index = $search_api_query -> getIndex();
          $backend = $index -> getServerInstance() -> getBackend();
          $connector = $backend -> getSolrConnector();
          $solarium_query = $connector -> getSelectQuery();
          $spellcheck = $solarium_query -> getSpellcheck();
          $schema_languages = $backend -> getSchemaLanguageStatistics();
          $dictionaries = [];
          foreach ( \Drupal\search_api_solr\Utility\Utility::ensureLanguageCondition( $search_api_query ) as $language_id ) {
            if ( isset( $schema_languages[ $language_id ] ) && $schema_languages[ $language_id ] ) {
              $dictionaries[] = $schema_languages[ $language_id ];
            }
          }
          if ( $dictionaries ) {
            $spellcheck -> setDictionary( $dictionaries );
          } else {
            $spellcheck -> setDictionary( \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED );
          }
          $keys = $query -> getKeys();
          if ( $keys && is_array( $keys ) ) {
            $spellcheck -> setQuery( implode( ' ', array_filter( $keys, 'is_int', ARRAY_FILTER_USE_KEY ) ) );
          }
          $spellcheck -> setCount( $this -> options[ 'spellcheck_count' ] );
          $spellcheck -> setBuild( TRUE );
          $spellcheck -> setCollate( TRUE );
          $spellcheck -> setExtendedResults( TRUE );
          $spellcheck -> setCollateExtendedResults( TRUE );
          $resultset = $connector -> execute( $solarium_query );
          $spellcheck_results = $resultset -> getSpellcheck();
          $spellcheck_suggestions = [];
          if ( $spellcheck_results ) {
            foreach ( $spellcheck_results -> getSuggestions() as $suggestion ) {
              $spellcheck_suggestions[] = [
                'word' => $suggestion -> getWord(),
                'numFound' => $suggestion -> getNumFound(),
                'startOffset' => $suggestion -> getStartOffset(),
                'endOffset' => $suggestion -> getEndOffset(),
                'suggestion' => $suggestion -> getWords()
              ];
            }
          }
        }
        return $this -> serializer -> serialize( [
          'title' => $this -> view -> getTitle(),
          'rows' => $rows,
          'spellcheck' => $spellcheck_suggestions,
          'fields' => $fields,
          'pager' => [
            'current_page' => $current_page,
            'total_items' => $total_items,
            'total_pages' => $total_pages,
            'items_per_page' => $items_per_page,
          ]
        ], $content_type, [ 'views_style_plugin' => $this ] );
      }
    }
    

    For example, if I set an exposed search_api_fulltext filter (be careful that this is not working for "direct parse") and if I search for the word "spac", I obtain the following JSON response:

    {"title":"My view",rows":[],"spellcheck":[{"word":"space","numFound":10,"startOffset":0,"endOffset":4,"suggestion":[{"word":"space","freq":60},{"word":"spacex","freq":7},{"word":"spain","freq":7},{"word":"scaf","freq":6},{"word":"spare","freq":6},{"word":"sdas","freq":3},{"word":"spot","freq":3},{"word":"seal","freq":2},{"word":"seas","freq":2},{"word":"spaces","freq":2}]}],"fields":{"date":"Date","description":"Description","country":"Country","source":"Source","tag":"Tag(s)","created":"Edited on"},"pager":{"current_page":0,"total_items":0,"total_pages":0,"items_per_page":50}}

    It's just a first shot, I know it can be improved

Production build 0.71.5 2024