Commit f7716551 authored by webchick's avatar webchick

Issue #2552799 by heddn, glenshewchuck, Xano, deepakaryan1988, swentel,...

Issue #2552799 by heddn, glenshewchuck, Xano, deepakaryan1988, swentel, jordanpagewhite, yched, tim.plunkett: FieldType with no available widget causes Fatal error
parent aced68bf
...@@ -297,13 +297,16 @@ public function getConstraints() { ...@@ -297,13 +297,16 @@ public function getConstraints() {
*/ */
public function defaultValuesForm(array &$form, FormStateInterface $form_state) { public function defaultValuesForm(array &$form, FormStateInterface $form_state) {
if (empty($this->getFieldDefinition()->getDefaultValueCallback())) { if (empty($this->getFieldDefinition()->getDefaultValueCallback())) {
// Place the input in a separate place in the submitted values tree. if ($widget = $this->defaultValueWidget($form_state)) {
$widget = $this->defaultValueWidget($form_state); // Place the input in a separate place in the submitted values tree.
$element = array('#parents' => array('default_value_input'));
$element += $widget->form($this, $element, $form_state);
$element = array('#parents' => array('default_value_input')); return $element;
$element += $widget->form($this, $element, $form_state); }
else {
return $element; return ['#markup' => $this->t('No widget available for: %type.', ['%type' => $this->getFieldDefinition()->getType()])];
}
} }
} }
...@@ -312,16 +315,17 @@ public function defaultValuesForm(array &$form, FormStateInterface $form_state) ...@@ -312,16 +315,17 @@ public function defaultValuesForm(array &$form, FormStateInterface $form_state)
*/ */
public function defaultValuesFormValidate(array $element, array &$form, FormStateInterface $form_state) { public function defaultValuesFormValidate(array $element, array &$form, FormStateInterface $form_state) {
// Extract the submitted value, and validate it. // Extract the submitted value, and validate it.
$widget = $this->defaultValueWidget($form_state); if ($widget = $this->defaultValueWidget($form_state)) {
$widget->extractFormValues($this, $element, $form_state); $widget->extractFormValues($this, $element, $form_state);
// Force a non-required field definition. // Force a non-required field definition.
// @see self::defaultValueWidget(). // @see self::defaultValueWidget().
$this->getFieldDefinition()->setRequired(FALSE); $this->getFieldDefinition()->setRequired(FALSE);
$violations = $this->validate(); $violations = $this->validate();
// Assign reported errors to the correct form element. // Assign reported errors to the correct form element.
if (count($violations)) { if (count($violations)) {
$widget->flagErrors($this, $violations, $element, $form_state); $widget->flagErrors($this, $violations, $element, $form_state);
}
} }
} }
...@@ -330,9 +334,10 @@ public function defaultValuesFormValidate(array $element, array &$form, FormStat ...@@ -330,9 +334,10 @@ public function defaultValuesFormValidate(array $element, array &$form, FormStat
*/ */
public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) { public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) {
// Extract the submitted value, and return it as an array. // Extract the submitted value, and return it as an array.
$widget = $this->defaultValueWidget($form_state); if ($widget = $this->defaultValueWidget($form_state)) {
$widget->extractFormValues($this, $element, $form_state); $widget->extractFormValues($this, $element, $form_state);
return $this->getValue(); return $this->getValue();
}
} }
/** /**
...@@ -348,8 +353,8 @@ public static function processDefaultValue($default_value, FieldableEntityInterf ...@@ -348,8 +353,8 @@ public static function processDefaultValue($default_value, FieldableEntityInterf
* @param \Drupal\Core\Form\FormStateInterface $form_state * @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state of the (entire) configuration form. * The form state of the (entire) configuration form.
* *
* @return \Drupal\Core\Field\WidgetInterface * @return \Drupal\Core\Field\WidgetInterface|null
* A Widget object. * A Widget object or NULL if no widget is available.
*/ */
protected function defaultValueWidget(FormStateInterface $form_state) { protected function defaultValueWidget(FormStateInterface $form_state) {
if (!$form_state->has('default_value_widget')) { if (!$form_state->has('default_value_widget')) {
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
* label = @Translation("Last changed"), * label = @Translation("Last changed"),
* description = @Translation("An entity field containing a UNIX timestamp of when the entity has been last updated."), * description = @Translation("An entity field containing a UNIX timestamp of when the entity has been last updated."),
* no_ui = TRUE, * no_ui = TRUE,
* default_widget = "datetime_default",
* default_formatter = "timestamp",
* list_class = "\Drupal\Core\Field\ChangedFieldItemList" * list_class = "\Drupal\Core\Field\ChangedFieldItemList"
* ) * )
* *
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
* label = @Translation("Created"), * label = @Translation("Created"),
* description = @Translation("An entity field containing a UNIX timestamp of when the entity has been created."), * description = @Translation("An entity field containing a UNIX timestamp of when the entity has been created."),
* no_ui = TRUE, * no_ui = TRUE,
* default_formatter = "timestamp", * default_widget = "datetime_default",
* default_formatter = "timestamp"
* ) * )
*/ */
class CreatedItem extends TimestampItem { class CreatedItem extends TimestampItem {
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
* description = @Translation("An entity field containing an entity reference."), * description = @Translation("An entity field containing an entity reference."),
* category = @Translation("Reference"), * category = @Translation("Reference"),
* no_ui = TRUE, * no_ui = TRUE,
* default_widget = "entity_reference_autocomplete",
* default_formatter = "entity_reference_label", * default_formatter = "entity_reference_label",
* list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList", * list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList",
* constraints = {"ValidReference" = {}} * constraints = {"ValidReference" = {}}
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* label = @Translation("Timestamp"), * label = @Translation("Timestamp"),
* description = @Translation("An entity field containing a UNIX timestamp value."), * description = @Translation("An entity field containing a UNIX timestamp value."),
* no_ui = TRUE, * no_ui = TRUE,
* default_widget = "datetime_default",
* default_formatter = "timestamp", * default_formatter = "timestamp",
* constraints = { * constraints = {
* "ComplexData" = { * "ComplexData" = {
......
...@@ -151,7 +151,7 @@ public function prepareConfiguration($field_type, array $configuration) { ...@@ -151,7 +151,7 @@ public function prepareConfiguration($field_type, array $configuration) {
// If no widget is specified, use the default widget. // If no widget is specified, use the default widget.
if (!isset($configuration['type'])) { if (!isset($configuration['type'])) {
$field_type = $this->fieldTypeManager->getDefinition($field_type); $field_type = $this->fieldTypeManager->getDefinition($field_type);
$configuration['type'] = $field_type['default_widget']; $configuration['type'] = isset($field_type['default_widget']) ? $field_type['default_widget'] : NULL;
} }
// Filter out unknown settings, and fill in defaults for missing settings. // Filter out unknown settings, and fill in defaults for missing settings.
$default_settings = $this->getDefaultSettings($configuration['type']); $default_settings = $this->getDefaultSettings($configuration['type']);
......
...@@ -276,6 +276,12 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, arr ...@@ -276,6 +276,12 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, arr
$display_options = $this->entity->getComponent($field_name); $display_options = $this->entity->getComponent($field_name);
$label = $field_definition->getLabel(); $label = $field_definition->getLabel();
// Disable fields without any applicable plugins.
if (empty($this->getApplicablePluginOptions($field_definition))) {
$this->entity->removeComponent($field_name)->save();
$display_options = $this->entity->getComponent($field_name);
}
$regions = array_keys($this->getRegions()); $regions = array_keys($this->getRegions());
$field_row = array( $field_row = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
...@@ -814,15 +820,15 @@ protected function getExtraFields() { ...@@ -814,15 +820,15 @@ protected function getExtraFields() {
abstract protected function getEntityDisplay($entity_type_id, $bundle, $mode); abstract protected function getEntityDisplay($entity_type_id, $bundle, $mode);
/** /**
* Returns an array of widget or formatter options for a field. * Returns an array of applicable widget or formatter options for a field.
* *
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition. * The field definition.
* *
* @return array * @return array
* An array of widget or formatter options. * An array of applicable widget or formatter options.
*/ */
protected function getPluginOptions(FieldDefinitionInterface $field_definition) { protected function getApplicablePluginOptions(FieldDefinitionInterface $field_definition) {
$options = $this->pluginManager->getOptions($field_definition->getType()); $options = $this->pluginManager->getOptions($field_definition->getType());
$applicable_options = array(); $applicable_options = array();
foreach ($options as $option => $label) { foreach ($options as $option => $label) {
...@@ -831,6 +837,20 @@ protected function getPluginOptions(FieldDefinitionInterface $field_definition) ...@@ -831,6 +837,20 @@ protected function getPluginOptions(FieldDefinitionInterface $field_definition)
$applicable_options[$option] = $label; $applicable_options[$option] = $label;
} }
} }
return $applicable_options;
}
/**
* Returns an array of widget or formatter options for a field.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
*
* @return array
* An array of widget or formatter options.
*/
protected function getPluginOptions(FieldDefinitionInterface $field_definition) {
$applicable_options = $this->getApplicablePluginOptions($field_definition);
return $applicable_options + array('hidden' => '- ' . $this->t('Hidden') . ' -'); return $applicable_options + array('hidden' => '- ' . $this->t('Hidden') . ' -');
} }
......
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
namespace Drupal\Tests\Core\Field; namespace Drupal\Tests\Core\Field;
use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Form\FormState;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
...@@ -155,4 +157,60 @@ public function testEqualsEmptyItems() { ...@@ -155,4 +157,60 @@ public function testEqualsEmptyItems() {
$this->assertEquals(TRUE, $field_list_a->equals($field_list_b)); $this->assertEquals(TRUE, $field_list_a->equals($field_list_b));
} }
/**
* @covers ::defaultValuesForm
*/
public function testDefaultValuesForm() {
$field_definition = $this->getMock(FieldDefinitionInterface::class);
$field_definition->expects($this->any())
->method('getType')
->willReturn('field_type');
/** @var \Drupal\Core\Field\FieldItemList|\PHPUnit_Framework_MockObject_MockObject $field_list */
$field_list = $this->getMock(FieldItemList::class, ['defaultValueWidget'], [$field_definition]);
$field_list->expects($this->any())
->method('defaultValueWidget')
->willReturn(NULL);
$form = [];
$form_state = new FormState();
$string_translation = $this->getStringTranslationStub();
$field_list->setStringTranslation($string_translation);
$this->assertEquals('No widget available for: <em class="placeholder">field_type</em>.', $field_list->defaultValuesForm($form, $form_state)['#markup']);
}
/**
* @covers ::defaultValuesFormValidate
*/
public function testDefaultValuesFormValidate() {
$field_definition = $this->getMock(FieldDefinitionInterface::class);
/** @var \Drupal\Core\Field\FieldItemList|\PHPUnit_Framework_MockObject_MockObject $field_list */
$field_list = $this->getMock(FieldItemList::class, ['defaultValueWidget', 'validate'], [$field_definition]);
$field_list->expects($this->any())
->method('defaultValueWidget')
->willReturn(NULL);
$field_list->expects($this->never())
->method('validate');
$form = [];
$form_state = new FormState();
$field_list->defaultValuesFormValidate([], $form, $form_state);
}
/**
* @covers ::defaultValuesFormSubmit
*/
public function testDefaultValuesFormSubmit() {
$field_definition = $this->getMock(FieldDefinitionInterface::class);
/** @var \Drupal\Core\Field\FieldItemList|\PHPUnit_Framework_MockObject_MockObject $field_list */
$field_list = $this->getMock(FieldItemList::class, ['defaultValueWidget', 'getValue'], [$field_definition]);
$field_list->expects($this->any())
->method('defaultValueWidget')
->willReturn(NULL);
$form = [];
$form_state = new FormState();
$field_list->expects($this->never())
->method('getValue');
$this->assertNull($field_list->defaultValuesFormSubmit([], $form, $form_state));
}
} }
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