drupal-graphql / graphql-search-api

GraphQL & Drupal Search API integration.
10 stars 22 forks source link

Mulitvalued custom field results are incomplete #40

Open kwiechmann opened 3 years ago

kwiechmann commented 3 years ago

Original request was opened here: https://www.drupal.org/project/graphql_search_api/issues/3183710 @kyubbi instructed to open here on github instead of Drupal.org

Hi! I would appreciate some guidance from someone that has already been there and has the battle scars to share. AdvThanksance!!!

The module stack is pretty tall and it has been difficult to narrow down any further. Looking into the Common pitfalls and FAQs has not led to any inspiration. I thought to post now but I will look at upgrading to the latest recommended versions of the module. Previous recommendations to upgrade to search_aol_solr to 4.1 from 8.x-1.5 did not resulted in any improvement.

Givens:

Knowns:

Relevant versions and enabled modules:

Evidence 1: Custom field definition

namespace Drupal\brqc_custom\Plugin\search_api\processor;

use Drupal\search_api\Datasource\DatasourceInterface;
use Drupal\search_api\Item\ItemInterface;
use Drupal\search_api\Processor\ProcessorPluginBase;
use Drupal\search_api\Processor\ProcessorProperty;

/**
 * Adds a custom field to the indexed data.
 *
 * @SearchApiProcessor(
 *   id = "group__members",
 *   label = @Translation("Group Members"),
 *   description = @Translation("Add a custom field of group members to search index."),
 *   stages = {
 *     "add_properties" = 0,
 *   },
 *   locked = true,
 *   hidden = false,
 * )
 */
class GroupMembers extends ProcessorPluginBase {

  /**
   * machine name of the processor.
   * @var string
   */
  protected $processor_id = 'group__members';

  /**
   * {@inheritdoc}
   */
  public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) {
    $properties = array();

    if (!$datasource) {
      $definition = array(
        'label' => $this->t('Group Members'),
        'description' => $this->t('Custom field for storing all members that belong to this group.'),
        'type' => 'string',
        'processor_id' => $this->getPluginId(),
      );
      $properties[$this->processor_id] = new ProcessorProperty($definition);
    }

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public function addFieldValues(ItemInterface $item) {
    $entity = $item->getOriginalObject()->getValue();
    $entity_type = $entity->getEntityTypeId();

    // Use $entity to get custom field.
    // Determine the correct content type.
    if ($entity_type == 'group') {
      // Get members from the group. Temporarily using superhero secret identities.
      $members = [
        'John Doe',
        'Peter Parker',
        'Bruce Wayne',
        'Clark Kent',
        'Diana Prince',
        'Arthur Curry',
        'Jack Napier',
        'James Howlett',
      ];
      $temp_members = [];
      $random = rand(0, count($members));
      $member_keys = array_rand($members, $random);
      if (!is_array($member_keys)) {
        $temp_members[] = $members[$member_keys];
      }
      else {
        foreach ($member_keys as $member_key) {
          $temp_members[] = $members[$member_key];
        }
      }
      $members = $temp_members;

      // Add the group members in individually.
      if (count($members) > 0) {
        $fields = $this->getFieldsHelper()
          ->filterForPropertyPath($item->getFields(), NULL, $this->processor_id);
        foreach ($fields as $field) {
          foreach ($members as $member) {
            $field->addValue($member);
          }
        }
      }
    }
  }

}

Evidence 2: Selected portions of query results from Solr admin.

{
  "response": {
    "numFound": 1,
    "start": 0,
    "docs": [
      {
        … stuff deleted
        "sm_group__members": [
          "John Doe",
          "Peter Parker",
          "Bruce Wayne",
          "Clark Kent",
          "Diana Prince",
          "Arthur Curry",
          "Jack Napier",
          "James Howlett"
        ],
       … stuff deleted
      }
    ]
  }
}

Evidence 3: GraphQL Explorer results

{
  "data": {
    "searchAPISearch": {
      "count": 1,
      "facets": [
        {
          "name": "group__type",
          "values": [
            {
              "count": 1,
              "filter": "!"
            }
          ]
        },
        {
          "name": "group__members",
          "values": [
            {
              "count": 1,
              "filter": "Arthur Curry"
            },
            {
              "count": 1,
              "filter": "Bruce Wayne"
            },
            {
              "count": 1,
              "filter": "Clark Kent"
            },
            {
              "count": 1,
              "filter": "Diana Prince"
            },
            {
              "count": 1,
              "filter": "Jack Napier"
            },
            {
              "count": 1,
              "filter": "James Howlett"
            },
            {
              "count": 1,
              "filter": "John Doe"
            },
            {
              "count": 1,
              "filter": "Peter Parker"
            }
          ]
        }
      ],
      "documents": [
        {
          … stuff deleted
          "group__members": "John Doe",
          … stuff deleted
        }
      ]
    }
  }
}
carolpettirossi commented 3 years ago

Hi @kwiechmann,

Thanks for the very explained problem and all the evidence. It helped me to understand what you are facing.

I've added support for multivalue fields defined via search API processor.

Can you please help me validating this? You should be able to test by applying this patch: https://patch-diff.githubusercontent.com/raw/drupal-graphql/graphql-search-api/pull/46.patch

Also, you will also need to update the $definition adding the is_list to it:

       $definition = array(
        'label' => $this->t('Group Members'),
        'description' => $this->t('Custom field for storing all members that belong to this group.'),
        'type' => 'string',
        'is_list' => TRUE, // <= added this
        'processor_id' => $this->getPluginId(),
      );