Chris@0: setUpFieldStorages(3); Chris@0: Chris@0: // Setup a field with cardinality > 1. Chris@0: $this->fieldStorages[3] = FieldStorageConfig::create([ Chris@0: 'field_name' => 'field_name_3', Chris@0: 'entity_type' => 'node', Chris@0: 'type' => 'string', Chris@0: 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, Chris@0: ]); Chris@0: $this->fieldStorages[3]->save(); Chris@0: // Setup a field that will have no value. Chris@0: $this->fieldStorages[4] = FieldStorageConfig::create([ Chris@0: 'field_name' => 'field_name_4', Chris@0: 'entity_type' => 'node', Chris@0: 'type' => 'string', Chris@0: 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, Chris@0: ]); Chris@0: $this->fieldStorages[4]->save(); Chris@0: Chris@0: // Setup a text field. Chris@0: $this->fieldStorages[5] = FieldStorageConfig::create([ Chris@0: 'field_name' => 'field_name_5', Chris@0: 'entity_type' => 'node', Chris@0: 'type' => 'text', Chris@0: ]); Chris@0: $this->fieldStorages[5]->save(); Chris@0: Chris@0: // Setup a text field with access control. Chris@0: // @see field_test_entity_field_access() Chris@0: $this->fieldStorages[6] = FieldStorageConfig::create([ Chris@0: 'field_name' => 'field_no_view_access', Chris@0: 'entity_type' => 'node', Chris@0: 'type' => 'text', Chris@0: ]); Chris@0: $this->fieldStorages[6]->save(); Chris@0: Chris@0: $this->setUpFields(); Chris@0: Chris@0: // Create some nodes. Chris@0: $this->nodes = []; Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $edit = ['type' => 'page']; Chris@0: Chris@0: foreach ([0, 1, 2, 5] as $key) { Chris@0: $field_storage = $this->fieldStorages[$key]; Chris@0: $edit[$field_storage->getName()][0]['value'] = $this->randomMachineName(8); Chris@0: } Chris@0: // Add a hidden value for the no-view field. Chris@0: $edit[$this->fieldStorages[6]->getName()][0]['value'] = 'ssh secret squirrel'; Chris@0: for ($j = 0; $j < 5; $j++) { Chris@0: $edit[$this->fieldStorages[3]->getName()][$j]['value'] = $this->randomMachineName(8); Chris@0: } Chris@0: // Set this field to be empty. Chris@0: $edit[$this->fieldStorages[4]->getName()] = [['value' => NULL]]; Chris@0: Chris@0: $this->nodes[$i] = $this->drupalCreateNode($edit); Chris@0: } Chris@0: Chris@0: $this->container->get('views.views_data')->clear(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets up the testing view with random field data. Chris@0: * Chris@0: * @param \Drupal\views\ViewExecutable $view Chris@0: * The view to add field data to. Chris@0: */ Chris@0: protected function prepareView(ViewExecutable $view) { Chris@0: $view->storage->invalidateCaches(); Chris@0: $view->initDisplay(); Chris@0: foreach ($this->fieldStorages as $field_storage) { Chris@0: $field_name = $field_storage->getName(); Chris@0: $view->display_handler->options['fields'][$field_name]['id'] = $field_name; Chris@0: $view->display_handler->options['fields'][$field_name]['table'] = 'node__' . $field_name; Chris@0: $view->display_handler->options['fields'][$field_name]['field'] = $field_name; Chris@0: } Chris@0: } Chris@0: Chris@0: public function testFieldRender() { Chris@0: $this->_testSimpleFieldRender(); Chris@0: $this->_testInaccessibleFieldRender(); Chris@0: $this->_testFormatterSimpleFieldRender(); Chris@0: $this->_testMultipleFieldRender(); Chris@0: } Chris@0: Chris@0: public function _testSimpleFieldRender() { Chris@0: $view = Views::getView('test_view_fieldapi'); Chris@0: $this->prepareView($view); Chris@0: $this->executeView($view); Chris@0: Chris@0: // Tests that the rendered fields match the actual value of the fields. Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: for ($key = 0; $key < 2; $key++) { Chris@0: $field_name = $this->fieldStorages[$key]->getName(); Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $expected_field = $this->nodes[$i]->$field_name->value; Chris@0: $this->assertEqual($rendered_field, $expected_field); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: public function _testInaccessibleFieldRender() { Chris@0: $view = Views::getView('test_view_fieldapi'); Chris@0: $this->prepareView($view); Chris@0: $this->executeView($view); Chris@0: Chris@0: // Check that the field handler for the hidden field is correctly removed Chris@0: // from the display. Chris@0: // @see https://www.drupal.org/node/2382931 Chris@0: $this->assertFalse(array_key_exists('field_no_view_access', $view->field)); Chris@0: Chris@0: // Check that the access-denied field is not visible. Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $field_name = $this->fieldStorages[6]->getName(); Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $this->assertFalse($rendered_field, 'Hidden field not rendered'); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that fields with formatters runs as expected. Chris@0: */ Chris@0: public function _testFormatterSimpleFieldRender() { Chris@0: $view = Views::getView('test_view_fieldapi'); Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$this->fieldStorages[5]->getName()]['type'] = 'text_trimmed'; Chris@0: $view->displayHandlers->get('default')->options['fields'][$this->fieldStorages[5]->getName()]['settings'] = [ Chris@0: 'trim_length' => 3, Chris@0: ]; Chris@0: $this->executeView($view); Chris@0: Chris@0: // Make sure that the formatter works as expected. Chris@0: // @TODO: actually there should be a specific formatter. Chris@0: for ($i = 0; $i < 2; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $this->fieldStorages[5]->getName()); Chris@0: $this->assertEqual(strlen(html_entity_decode($rendered_field)), 3); Chris@0: } Chris@0: } Chris@0: Chris@0: public function _testMultipleFieldRender() { Chris@0: $view = Views::getView('test_view_fieldapi'); Chris@0: $field_name = $this->fieldStorages[3]->getName(); Chris@0: Chris@0: // Test delta limit. Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3; Chris@0: $this->executeView($view); Chris@0: Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $items = []; Chris@0: $pure_items = $this->nodes[$i]->{$field_name}->getValue(); Chris@0: $pure_items = array_splice($pure_items, 0, 3); Chris@0: foreach ($pure_items as $j => $item) { Chris@0: $items[] = $pure_items[$j]['value']; Chris@0: } Chris@0: $this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited.'); Chris@0: } Chris@0: Chris@0: // Test that an empty field is rendered without error. Chris@0: $view->style_plugin->getField(4, $this->fieldStorages[4]->getName()); Chris@0: $view->destroy(); Chris@0: Chris@0: // Test delta limit + offset Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 1; Chris@0: $this->executeView($view); Chris@0: Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $items = []; Chris@0: $pure_items = $this->nodes[$i]->{$field_name}->getValue(); Chris@0: $pure_items = array_splice($pure_items, 1, 3); Chris@0: foreach ($pure_items as $j => $item) { Chris@0: $items[] = $pure_items[$j]['value']; Chris@0: } Chris@0: $this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited and the offset is correct.'); Chris@0: } Chris@0: $view->destroy(); Chris@0: Chris@0: // Test delta limit + reverse. Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 0; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = TRUE; Chris@0: $this->executeView($view); Chris@0: Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $items = []; Chris@0: $pure_items = $this->nodes[$i]->{$field_name}->getValue(); Chris@0: array_splice($pure_items, 0, -3); Chris@0: $pure_items = array_reverse($pure_items); Chris@0: foreach ($pure_items as $j => $item) { Chris@0: $items[] = $pure_items[$j]['value']; Chris@0: } Chris@0: $this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited and they are reversed.'); Chris@0: } Chris@0: $view->destroy(); Chris@0: Chris@0: // Test delta first last. Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 0; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = FALSE; Chris@0: $this->executeView($view); Chris@0: Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $items = []; Chris@0: $pure_items = $this->nodes[$i]->{$field_name}->getValue(); Chris@0: $items[] = $pure_items[0]['value']; Chris@0: $items[] = $pure_items[4]['value']; Chris@0: $this->assertEqual($rendered_field, implode(', ', $items), 'Items are limited to first and last.'); Chris@0: } Chris@0: $view->destroy(); Chris@0: Chris@0: // Test delta limit + custom separator. Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = FALSE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = ':'; Chris@0: $this->executeView($view); Chris@0: Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $items = []; Chris@0: $pure_items = $this->nodes[$i]->{$field_name}->getValue(); Chris@0: $pure_items = array_splice($pure_items, 0, 3); Chris@0: foreach ($pure_items as $j => $item) { Chris@0: $items[] = $pure_items[$j]['value']; Chris@0: } Chris@0: $this->assertEqual($rendered_field, implode(':', $items), 'The amount of items is limited and the custom separator is correct.'); Chris@0: } Chris@0: $view->destroy(); Chris@0: Chris@0: // Test separator with HTML, ensure it is escaped. Chris@0: $this->prepareView($view); Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3; Chris@0: $view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = '

test

'; Chris@0: $this->executeView($view); Chris@0: Chris@0: for ($i = 0; $i < 3; $i++) { Chris@0: $rendered_field = $view->style_plugin->getField($i, $field_name); Chris@0: $items = []; Chris@0: $pure_items = $this->nodes[$i]->{$field_name}->getValue(); Chris@0: $pure_items = array_splice($pure_items, 0, 3); Chris@0: foreach ($pure_items as $j => $item) { Chris@0: $items[] = $pure_items[$j]['value']; Chris@0: } Chris@0: $this->assertEqual($rendered_field, implode('

test

', $items), 'The custom separator is correctly escaped.'); Chris@0: } Chris@0: $view->destroy(); Chris@0: } Chris@0: Chris@0: }