Commit b5c736da authored by alexpott's avatar alexpott

Issue #2204325 by Arla, cbr, Berdir, benjy: Fixed The "rendered entity"...

Issue #2204325 by Arla, cbr, Berdir, benjy: Fixed The "rendered entity" formatter breaks for entity types with out a ViewBuilder.
parent d21c9a4e
......@@ -147,4 +147,12 @@ protected function getFieldSetting($setting_name) {
return $this->fieldDefinition->getSetting($setting_name);
}
/**
* {@inheritdoc}
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
// By default, formatters are available for all fields.
return TRUE;
}
}
......@@ -87,4 +87,15 @@ public function view(FieldItemListInterface $items);
*/
public function viewElements(FieldItemListInterface $items);
/**
* Returns if the formatter can be used for the provided field.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition that should be checked.
*
* @return bool
* TRUE if the formatter can be used, FALSE otherwise.
*/
public static function isApplicable(FieldDefinitionInterface $field_definition);
}
......@@ -534,4 +534,13 @@ protected function handlesMultipleValues() {
return $definition['multiple_values'];
}
/**
* {@inheritdoc}
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
// By default, widgets are available for all fields.
return TRUE;
}
}
......@@ -153,4 +153,15 @@ public function errorElement(array $element, ConstraintViolationInterface $viola
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state);
/**
* Returns if the widget can be used for the provided field.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition that should be checked.
*
* @return bool
* TRUE if the widget can be used, FALSE otherwise.
*/
public static function isApplicable(FieldDefinitionInterface $field_definition);
}
......@@ -7,6 +7,7 @@
namespace Drupal\entity_reference\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\entity_reference\RecursiveRenderingException;
......@@ -133,4 +134,14 @@ public function viewElements(FieldItemListInterface $items) {
return $elements;
}
/**
* {@inheritdoc}
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
// This formatter is only available for entity types that have a view
// builder.
$target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type');
return \Drupal::entityManager()->getDefinition($target_type)->hasViewBuilderClass();
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\entity_reference\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests for the administrative UI.
......@@ -24,13 +25,13 @@ class EntityReferenceAdminTest extends WebTestBase {
*
* @var array
*/
public static $modules = array('node', 'field_ui', 'entity_reference', 'path');
public static $modules = array('node', 'field_ui', 'entity_reference', 'path', 'taxonomy');
public function setUp() {
parent::setUp();
// Create test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer node fields'));
$admin_user = $this->drupalCreateUser(array('access content', 'administer node fields', 'administer node display'));
$this->drupalLogin($admin_user);
// Create a content type, with underscores.
......@@ -101,6 +102,97 @@ public function testFieldAdminHandler() {
$this->assertFieldByXPath('//table[@id="field-overview"]//tr[@id="field-test"]/td[1]', 'Test label', 'Field was created and appears in the overview page.');
}
/**
* Tests the formatters for the Entity References
*/
public function testAvailableFormatters() {
// Create a new vocabulary.
Vocabulary::create(array('vid' => 'tags', 'name' => 'tags'))->save();
// Create entity reference field with taxonomy term as a target.
$taxonomy_term_field_name = $this->createEntityReferenceField('taxonomy_term', 'tags');
// Create entity reference field with node as a target.
$node_field_name = $this->createEntityReferenceField('node', $this->type);
// Create entity reference field with date format as a target.
$date_format_field_name = $this->createEntityReferenceField('date_format');
// Display all newly created Entity Reference configuration.
$this->drupalGet('admin/structure/types/manage/' . $this->type . '/display');
// Check for Taxonomy Term select box values.
// Test if Taxonomy Term Entity Reference Field has the correct formatters.
$this->assertFieldSelectOptions('fields[field_' . $taxonomy_term_field_name . '][type]', array(
'entity_reference_label',
'entity_reference_entity_id',
'entity_reference_rss_category',
'entity_reference_entity_view',
'hidden',
));
// Test if Node Entity Reference Field has the correct formatters.
// RSS Category should not be available for this field.
$this->assertFieldSelectOptions('fields[field_' . $node_field_name . '][type]', array(
'entity_reference_label',
'entity_reference_entity_id',
'entity_reference_entity_view',
'hidden',
));
// Test if Date Format Reference Field has the correct formatters.
// RSS Category & Entity View should not be available for this field.
// This could be any field without a ViewBuilder.
$this->assertFieldSelectOptions('fields[field_' . $date_format_field_name . '][type]', array(
'entity_reference_label',
'entity_reference_entity_id',
'hidden',
));
}
/**
* Creates a new Entity Reference fields with a given target type.
*
* @param $target_type
* The name of the target type
* @param $bundle
* Name of the bundle
* Default = NULL
* @return string
* Returns the generated field name
*/
public function createEntityReferenceField($target_type, $bundle = NULL) {
// Generates a bundle path for the newly created content type.
$bundle_path = 'admin/structure/types/manage/' . $this->type;
// Generate a random field name, must be only lowercase characters.
$field_name = strtolower($this->randomMachineName());
// Create the initial entity reference.
$this->drupalPostForm($bundle_path . '/fields', array(
'fields[_add_new_field][label]' => $this->randomMachineName(),
'fields[_add_new_field][field_name]' => $field_name,
'fields[_add_new_field][type]' => 'entity_reference',
), t('Save'));
// Select the correct target type given in the parameters and save field settings.
$this->drupalPostForm(NULL, array('field[settings][target_type]' => $target_type), t('Save field settings'));
// Select required fields if there are any.
$edit = array();
if($bundle) {
$edit['instance[settings][handler_settings][target_bundles][' . $bundle . ']'] = TRUE;
}
// Save settings.
$this->drupalPostForm(NULL, $edit, t('Save settings'));
// Returns the generated field name.
return $field_name;
}
/**
* Checks if a select element contains the specified options.
*
......@@ -118,7 +210,11 @@ protected function assertFieldSelectOptions($name, array $expected_options) {
if ($fields) {
$field = $fields[0];
$options = $this->getAllOptionsList($field);
return $this->assertIdentical(sort($options), sort($expected_options));
sort($options);
sort($expected_options);
return $this->assertIdentical($options, $expected_options);
}
else {
return $this->fail('Unable to find field ' . $name);
......@@ -141,8 +237,9 @@ protected function getAllOptionsList(\SimpleXMLElement $element) {
$options[] = (string) $option['value'];
}
if (isset($element->optgroup)) {
$options += $this->getAllOptionsList($element->optgroup);
// Loops trough all the option groups
foreach ($element->optgroup as $optgroup) {
$options = array_merge($this->getAllOptionsList($optgroup), $options);
}
return $options;
......
......@@ -7,6 +7,7 @@
namespace Drupal\field_test\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
......@@ -96,4 +97,13 @@ public static function multipleValidate($element, FormStateInterface $form_state
form_set_value($element, $items, $form_state);
}
/**
* {@inheritdoc}
* Used in \Drupal\entity_reference\Tests\EntityReferenceAdminTest::testAvailableFormatters().
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
// Returns FALSE if machine name of the field equals field_onewidgetfield.
return $field_definition->getName() != "field_onewidgetfield";
}
}
......@@ -164,8 +164,8 @@ protected function getPlugin(FieldDefinitionInterface $field_definition, $config
/**
* {@inheritdoc}
*/
protected function getPluginOptions($field_type) {
return parent::getPluginOptions($field_type) + array('hidden' => '- ' . $this->t('Hidden') . ' -');
protected function getPluginOptions(FieldDefinitionInterface $field_definition) {
return parent::getPluginOptions($field_definition) + array('hidden' => '- ' . $this->t('Hidden') . ' -');
}
/**
......
......@@ -7,6 +7,7 @@
namespace Drupal\field_ui;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Utility\String;
use Drupal\Core\Config\ConfigFactoryInterface;
......@@ -308,7 +309,7 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, Ent
'#type' => 'select',
'#title' => $this->t('Plugin for @title', array('@title' => $label)),
'#title_display' => 'invisible',
'#options' => $this->getPluginOptions($field_definition->getType()),
'#options' => $this->getPluginOptions($field_definition),
'#default_value' => $display_options ? $display_options['type'] : 'hidden',
'#parents' => array('fields', $field_name, 'type'),
'#attributes' => array('class' => array('field-plugin-type')),
......@@ -725,16 +726,24 @@ protected function getExtraFields() {
abstract protected function getPlugin(FieldDefinitionInterface $field_definition, $configuration);
/**
* Returns an array of widget or formatter options for a field type.
* Returns an array of widget or formatter options for a field.
*
* @param string $field_type
* The name of the field type.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
*
* @return array
* An array of widget or formatter options.
*/
protected function getPluginOptions($field_type) {
return $this->pluginManager->getOptions($field_type);
protected function getPluginOptions(FieldDefinitionInterface $field_definition) {
$options = $this->pluginManager->getOptions($field_definition->getType());
$applicable_options = array();
foreach ($options as $option => $label) {
$plugin_class = DefaultFactory::getPluginClass($option, $this->pluginManager->getDefinition($option));
if ($plugin_class::isApplicable($field_definition)) {
$applicable_options[$option] = $label;
}
}
return $applicable_options;
}
/**
......
......@@ -130,8 +130,8 @@ protected function getPlugin(FieldDefinitionInterface $field_definition, $config
/**
* {@inheritdoc}
*/
protected function getPluginOptions($field_type) {
return parent::getPluginOptions($field_type) + array('hidden' => '- ' . t('Hidden') . ' -');
protected function getPluginOptions(FieldDefinitionInterface $field_definition) {
return parent::getPluginOptions($field_definition) + array('hidden' => '- ' . t('Hidden') . ' -');
}
/**
......
......@@ -143,10 +143,13 @@ function testFormatterUI() {
* Tests widget settings.
*/
public function testWidgetUI() {
// Admin Manage Fields page.
$manage_fields = 'admin/structure/types/manage/' . $this->type;
// Admin Manage Display page.
$manage_display = $manage_fields . '/form-display';
// Create a field, and a node with some data for the field.
// Creates a new field that can be used with multiple formatters.
// Reference: Drupal\field_test\Plugin\Field\FieldWidget\TestFieldWidgetMultiple::isApplicable().
$edit = array(
'fields[_add_new_field][label]' => 'Test field',
'fields[_add_new_field][field_name]' => 'test',
......@@ -161,7 +164,7 @@ public function testWidgetUI() {
$setting_name = key($default_settings);
$setting_value = $display_options['settings'][$setting_name];
// Display the "Manage form display" screen and check that the expected
// Display the "Manage form display" screen and check if the expected
// widget is selected.
$this->drupalGet($manage_display);
$this->assertFieldByName('fields[field_test][type]', $widget_type, 'The expected widget is selected.');
......@@ -222,6 +225,21 @@ public function testWidgetUI() {
// Confirm that the third party settings are not updated on the settings form.
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
$this->assertFieldByName($fieldname, '');
// Creates a new field that can not be used with the multiple formatter.
// Reference: Drupal\field_test\Plugin\Field\FieldWidget\TestFieldWidgetMultiple::isApplicable().
$edit = array(
'fields[_add_new_field][label]' => 'One Widget Field',
'fields[_add_new_field][field_name]' => 'onewidgetfield',
);
$this->fieldUIAddNewField($manage_fields, $edit);
// Go to the Manage Form Display.
$this->drupalGet($manage_display);
// Checks if the select elements contain the specified options.
$this->assertFieldSelectOptions('fields[field_test][type]', array('test_field_widget', 'test_field_widget_multiple', 'hidden'));
$this->assertFieldSelectOptions('fields[field_onewidgetfield][type]', array('test_field_widget', 'hidden'));
}
/**
......@@ -434,4 +452,57 @@ function assertNodeViewTextHelper(EntityInterface $node, $view_mode, $text, $mes
return $return;
}
/**
* Checks if a select element contains the specified options.
*
* @param string $name
* The field name.
* @param array $expected_options
* An array of expected options.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertFieldSelectOptions($name, array $expected_options) {
$xpath = $this->buildXPathQuery('//select[@name=:name]', array(':name' => $name));
$fields = $this->xpath($xpath);
if ($fields) {
$field = $fields[0];
$options = $this->getAllOptionsList($field);
sort($options);
sort($expected_options);
return $this->assertIdentical($options, $expected_options);
}
else {
return $this->fail('Unable to find field ' . $name);
}
}
/**
* Extracts all options from a select element.
*
* @param \SimpleXMLElement $element
* The select element field information.
*
* @return array
* An array of option values as strings.
*/
protected function getAllOptionsList(\SimpleXMLElement $element) {
$options = array();
// Add all options items.
foreach ($element->option as $option) {
$options[] = (string) $option['value'];
}
// Loops trough all the option groups
foreach ($element->optgroup as $optgroup) {
$options = array_merge($this->getAllOptionsList($optgroup), $options);
}
return $options;
}
}
......@@ -7,14 +7,13 @@
namespace Drupal\taxonomy\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\entity_reference\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase;
/**
* Plugin implementation of the 'entity reference taxonomy term RSS' formatter.
*
* @todo: Have a way to indicate this formatter applies only to taxonomy terms.
*
* @FieldFormatter(
* id = "entity_reference_rss_category",
* label = @Translation("RSS category"),
......@@ -45,4 +44,13 @@ public function viewElements(FieldItemListInterface $items) {
return $elements;
}
/**
* {@inheritdoc}
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
// This formatter is only available for taxonomy terms.
return $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'taxonomy_term';
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment