1

Is there a way to group results by the first letter of their title in a REST export per the screenshot?

enter image description here

My first thought would be perhaps extending Serializer to process the results, at the expense of pagination. In my case, it is only about 100 records, and won't be paginated.

3 Answers 3

2

I am not sure if this is the best solution, but I came up with this:

/**
 * The style plugin for serialized output formats.
 *
 * @ingroup views_style_plugins
 *
 * @ViewsStyle(
 *   id = "serializer_glossary",
 *   title = @Translation("Serializer Glossary"),
 *   help = @Translation("Serializes results and groups them by first letter, for small result lists only."),
 *   display_types = {"data"}
 * )
 */
class SerializerGlossary extends Serializer {

  /**
   * {@inheritdoc}
   */
  public function render() {
    $rows = [];

    foreach ($this->view->result as $row) {
      $entity = $this->view->rowPlugin->render($row);
      $title = $entity->label();
      $first_letter = Unicode::strtoupper($title[0]);
      $rows[$first_letter][] = $this->view->rowPlugin->render($row);
    }

    // Get the content type configured in the display or fallback to the
    // default.
    if ((empty($this->view->live_preview))) {
      $content_type = $this->displayHandler->getContentType();
    }
    else {
      $content_type = !empty($this->options['formats']) ? reset($this->options['formats']) : 'json';
    }

    return $this->serializer->serialize(['results' => ['items' => $rows, 'totalCount' => count($this->view->result)]], $content_type);
  }
}

enter image description here

I am open to other answers if there is a better way.

The frontend is processing this via ReactJS to do the screenshot in the original question. The reason it is wrapped with 'results' and then 'items' is from a request from the frontend developer to have it structured that way.

0
0

I haven't played with REST export so I don't know how it might affect your case, but I don't see why it wouldn't work if you set up your fields right.

Use Trim this field and Grouping field Nr.1

  1. Create the usual Views of your content showing the Title, Body summary or whatever is applicable in your case
  2. Create another Title field or the one you want to group your Views by, even if you already have it from the first step.
  3. Set that field to
    Don't! Create a label
    Exclude from display
    Formatter Plain text
    Rewrite results:

    • Trim this field to a maximum number of characters
    • Maximum number of characters 1
    • Untick “Trim only on a word boundary”
    • Untick “Add "…" at the end of trimmed text”

    This is how you get the Title field to only display the first letter.

  4. Now edit the Format: Settings and under the Grouping field Nr.1 select that field (mind the order of fields since you'll have two)
  5. Add Sorting criteria by Title field
  6. Setup your REST exporter if you haven't already
1
  • 2
    In true Drupal fashion, Views Rest exports don't provide the option to group by a field.
    – John
    Commented Nov 13, 2018 at 19:47
0

There is an open issue at drupal.org to Add grouping to views REST Serializer formatter.

Check out the latest patch there, that allows to enable the grouping on REST views serializer formatter.

After activating the patch, you could do the regular grouping, as @prkos described in his answer.

If you do not want to patch the core, alternatively you can create a custom views style:

<?php

namespace Drupal\my_module\Plugin\views\style;

use Drupal\Core\Render\Element;
use Drupal\rest\Plugin\views\style\Serializer;

/**
 * The style plugin for grouped serializer output format.
 *
 * @ingroup views_style_plugins
 *
 * @ViewsStyle(
 *   id = "serializer_grouped",
 *   title = @Translation("Serializer Grouped"),
 *   help = @Translation("Provides possibility to groups serialized results."),
 *   display_types = {"data"}
 * )
 */
class SerializerGrouped extends Serializer {

  /**
   * {@inheritdoc}
   */
  protected $usesGrouping = TRUE;

  /**
   * {@inheritdoc}
   */
  public function render() {
    $rows = [];

    // Group the rows according to the grouping instructions, if specified.
    $sets = $this->renderGrouping(
      $this->view->result,
      $this->options['grouping'],
      TRUE
    );
    $groups = $this->renderGroupingSets($sets);

    foreach ($groups as $group) {
      foreach (Element::children($group) as $key) {
        $group_id = trim(strip_tags((string) $group['#title']));
        $rows[$group_id][] = $group[$key];
      }
    }

    // Get the content type configured in the display or fallback to the
    // default.
    if ((empty($this->view->live_preview))) {
      $content_type = $this->displayHandler->getContentType();
    }
    else {
      $content_type = !empty($this->options['formats']) ? reset($this->options['formats']) : 'json';
    }

    return $this->serializer->serialize($rows, $content_type, ['views_style_plugin' => $this]);
  }

  /**
   * {@inheritdoc}
   */
  protected function renderRowGroup(array $rows = []) {
    return $rows;
  }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.