You are here

public function ViewsPropertyExtractionTest::testPropertyExtraction in Search API 8

Tests whether property extraction works correctly.

@dataProvider propertyExtractionDataProvider

Parameters

string $property_path: The combined property path of the field.

string|string[] $expected: The expected value(s) on the row.

bool $pre_set: (optional) Whether to pre-set the values on the row (to check whether they're correctly passed through).

bool $return_fields: (optional) Whether to return any fields for the index.

bool $set_highlighting: (optional) Whether to set highlighting data on the field. (Only makes sense if $return_fields is TRUE.)

string|string[]|null $processor_property_value: (optional) If set, the value(s) to set for processor-generated properties.

File

tests/src/Kernel/Views/ViewsPropertyExtractionTest.php, line 56

Class

ViewsPropertyExtractionTest
Tests whether Views pages correctly create search display plugins.

Namespace

Drupal\Tests\search_api\Kernel\Views

Code

public function testPropertyExtraction($property_path, $expected, $pre_set = FALSE, $return_fields = TRUE, $set_highlighting = FALSE, $processor_property_value = NULL) {
  $datasource_id = 'entity:user';

  /** @var \Drupal\search_api\IndexInterface|\PHPUnit\Framework\MockObject\MockObject $index */
  $index = $this
    ->createMock(IndexInterface::class);
  $property2 = $this
    ->createMock(ConfigurablePropertyInterface::class);
  $property2
    ->method('getProcessorId')
    ->willReturn('processor2');
  $property2
    ->method('getDataType')
    ->willReturn('string');
  $property2
    ->method('defaultConfiguration')
    ->willReturn([]);
  $property2
    ->method('getClass')
    ->willReturn(StringData::class);
  $index
    ->method('getPropertyDefinitions')
    ->willReturnMap([
    [
      NULL,
      [
        'property1' => new ProcessorProperty([
          'processor_id' => 'processor1',
        ]),
      ],
    ],
    [
      $datasource_id,
      [
        'property2' => $property2,
      ],
    ],
  ]);
  $generate_add_field_values = function ($value) {
    return function (ItemInterface $item) use ($value) {
      foreach ($item
        ->getFields() as $field) {
        $values = (array) $value;
        $config = $field
          ->getConfiguration();
        if (is_scalar($value) && !empty($config[$value])) {
          $values = (array) $config[$value];
        }
        $field
          ->setValues($values);
      }
    };
  };
  $processor1 = $this
    ->createMock(ProcessorInterface::class);
  $processor2 = $this
    ->createMock(ProcessorInterface::class);

  // When we pre-set the row values we don't expect the processor to be called
  // for field value extraction.
  if ($pre_set) {
    $exception = new \Exception('Should not be called.');
    $processor1
      ->method('addFieldValues')
      ->willThrowException($exception);
    $processor2
      ->method('addFieldValues')
      ->willThrowException($exception);
  }
  else {
    $value1 = $processor_property_value ?: 'Processor 1';
    $processor1
      ->method('addFieldValues')
      ->willReturnCallback($generate_add_field_values($value1));
    $value2 = $processor_property_value ?: 'Processor 2';
    $processor2
      ->method('addFieldValues')
      ->willReturnCallback($generate_add_field_values($value2));
  }
  $index
    ->method('getProcessor')
    ->willReturnMap([
    [
      'processor1',
      $processor1,
    ],
    [
      'processor2',
      $processor2,
    ],
  ]);
  $fields_helper = $this->container
    ->get('search_api.fields_helper');
  $property_path_split = Utility::splitCombinedId($property_path);
  $fields = [];
  if ($return_fields) {
    $fields = [
      'foo' => $fields_helper
        ->createField($index, 'foo', [
        'datasource_id' => $property_path_split[0],
        'property_path' => $property_path_split[1],
        'configuration' => [
          'Processor 2' => 'foobar',
        ],
      ]),
      'test' => $fields_helper
        ->createField($index, 'test', [
        'datasource_id' => $property_path_split[0],
        'property_path' => $property_path_split[1],
        'configuration' => [
          'Processor 2' => 'Override',
        ],
      ]),
    ];
  }
  $index
    ->method('getFields')
    ->willReturn($fields);
  $query = $this
    ->getMockBuilder(SearchApiQuery::class)
    ->disableOriginalConstructor()
    ->getMock();
  $query
    ->method('getIndex')
    ->willReturn($index);

  /** @var \Drupal\views\ViewExecutable $view */
  $view = $this
    ->getMockBuilder(ViewExecutable::class)
    ->disableOriginalConstructor()
    ->getMock();
  $view->query = $query;

  /** @var \Drupal\views\Plugin\views\display\DisplayPluginBase $display */
  $display = $this
    ->getMockBuilder(DisplayPluginBase::class)
    ->disableOriginalConstructor()
    ->getMock();
  $configuration = [
    'real field' => $property_path,
    'search_api field' => 'test',
  ];
  $field = new SearchApiStandard($configuration, '', []);
  $options = [
    'use_highlighting' => TRUE,
  ];
  $field
    ->init($view, $display, $options);
  $field
    ->query();
  $user = User::create([
    'name' => 'Test user',
  ]);
  $object = $user
    ->getTypedData();
  $id = Utility::createCombinedId($datasource_id, $user
    ->id());
  $item = $fields_helper
    ->createItemFromObject($index, $object, $id);
  $row = new ResultRow([
    '_item' => $item,
    '_object' => $object,
    '_relationship_objects' => [
      NULL => [
        $object,
      ],
    ],
  ]);

  // For the configurable property, change the property path if it matches a
  // field.
  if ($property_path === 'entity:user/property2') {
    $original_property_path = $property_path;
    $property_path = "{$property_path}|test";
  }
  if ($pre_set) {
    $row->{$property_path} = [
      'Pre-set',
    ];
  }
  if ($set_highlighting) {
    $item
      ->setExtraData('highlighted_fields', [
      'test' => [
        '<strong>Highlighted</strong> value',
      ],
    ]);
  }
  $values = [
    $row,
  ];
  $field
    ->preRender($values);
  $this
    ->assertObjectHasAttribute($property_path, $row);
  $this
    ->assertEquals((array) $expected, $row->{$property_path});

  // Check that $field->propertyReplacements was set correctly (if
  // applicable).
  $property_replacements = new \ReflectionProperty($field, 'propertyReplacements');
  $property_replacements
    ->setAccessible(TRUE);
  $property_replacements = $property_replacements
    ->getValue($field);
  if (isset($original_property_path)) {
    $this
      ->assertArrayHasKey($original_property_path, $property_replacements);
    $this
      ->assertEquals($property_path, $property_replacements[$original_property_path]);
  }
  else {
    $this
      ->assertEmpty($property_replacements);
  }
}